From e3d0038f365bf3b0ff68709f7bd4e10d5bb1d36d Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 6 Oct 2022 19:08:02 +0000 Subject: [PATCH 001/367] Increment version to 7.20.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 84f89b32d97..9a4b993de72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.19.0", + "version": "7.20.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 22c8bb68640..5fe3556a11e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.19.0", + "version": "7.20.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 5ca852960ecf2cd2bce083c1b086432608560574 Mon Sep 17 00:00:00 2001 From: Denis Logachov Date: Mon, 10 Oct 2022 16:55:44 +0300 Subject: [PATCH 002/367] Adkernel Bid Adapter: rtbdemand.com alias (#9087) * Adkernel Bid Adapter: rtbdemand.com alias * Update adkernelBidAdapter.js --- modules/adkernelBidAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js index ff7d3be6ebf..b0449418a87 100644 --- a/modules/adkernelBidAdapter.js +++ b/modules/adkernelBidAdapter.js @@ -79,7 +79,6 @@ export const spec = { {code: 'audiencemedia'}, {code: 'waardex_ak'}, {code: 'roqoon'}, - {code: 'andbeyond'}, {code: 'adbite'}, {code: 'houseofpubs'}, {code: 'torchad'}, @@ -97,7 +96,8 @@ export const spec = { {code: 'felixads'}, {code: 'motionspots'}, {code: 'sonic_twist'}, - {code: 'displayioads'} + {code: 'displayioads'}, + {code: 'rtbdemand_com'} ], supportedMediaTypes: [BANNER, VIDEO, NATIVE], From be1995b57337555e9788420508cabdfdb9ec0cc0 Mon Sep 17 00:00:00 2001 From: Mike Marcus Date: Mon, 10 Oct 2022 10:03:59 -0400 Subject: [PATCH 003/367] Lotame Panorama Id System: bug fixes (#9092) * GRUE-246 fixed bug to test for emnpty value before returning, fixed bug to check for null values and to convert a string to an int before treating it as a timestamp. * GRUE-246 Removed trailing space. --- modules/lotamePanoramaIdSystem.js | 16 ++++++++++------ test/spec/modules/lotamePanoramaIdSystem_spec.js | 1 - 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/modules/lotamePanoramaIdSystem.js b/modules/lotamePanoramaIdSystem.js index a03626d4a1f..832d98e4f83 100644 --- a/modules/lotamePanoramaIdSystem.js +++ b/modules/lotamePanoramaIdSystem.js @@ -28,6 +28,7 @@ const DAYS_TO_CACHE = 7; const DAY_MS = 60 * 60 * 24 * 1000; const MISSING_CORE_CONSENT = 111; const GVLID = 95; +const ID_HOST = 'id.crwdcntrl.net'; export const storage = getStorageManager({gvlid: GVLID, moduleName: MODULE_NAME}); let cookieDomain; @@ -57,12 +58,14 @@ function setProfileId(profileId) { * Get the Lotame profile id by checking cookies first and then local storage */ function getProfileId() { + let profileId; if (storage.cookiesAreEnabled()) { - return storage.getCookie(KEY_PROFILE, undefined); + profileId = storage.getCookie(KEY_PROFILE, undefined); } - if (storage.hasLocalStorage()) { - return storage.getDataFromLocalStorage(KEY_PROFILE, undefined); + if (!profileId && storage.hasLocalStorage()) { + profileId = storage.getDataFromLocalStorage(KEY_PROFILE, undefined); } + return profileId; } /** @@ -78,10 +81,11 @@ function getFromStorage(key) { const storedValueExp = storage.getDataFromLocalStorage( `${key}_exp`, undefined ); - if (storedValueExp === '') { + + if (storedValueExp === '' || storedValueExp === null) { value = storage.getDataFromLocalStorage(key, undefined); } else if (storedValueExp) { - if ((new Date(storedValueExp)).getTime() - Date.now() > 0) { + if ((new Date(parseInt(storedValueExp, 10))).getTime() - Date.now() > 0) { value = storage.getDataFromLocalStorage(key, undefined); } } @@ -284,7 +288,7 @@ export const lotamePanoramaIdSubmodule = { const url = buildUrl({ protocol: 'https', - host: `id.crwdcntrl.net`, + host: ID_HOST, pathname: '/id', search: isEmpty(queryParams) ? undefined : queryParams, }); diff --git a/test/spec/modules/lotamePanoramaIdSystem_spec.js b/test/spec/modules/lotamePanoramaIdSystem_spec.js index 090144ab158..5dc055ac080 100644 --- a/test/spec/modules/lotamePanoramaIdSystem_spec.js +++ b/test/spec/modules/lotamePanoramaIdSystem_spec.js @@ -70,7 +70,6 @@ describe('LotameId', function() { it('should call the remote server when getId is called', function () { expect(request.url).to.be.eq('https://id.crwdcntrl.net/id'); - expect(callBackSpy.calledOnce).to.be.true; }); From 728748633a1226d7097cc5765c2b7b24aef91dea Mon Sep 17 00:00:00 2001 From: Chris Huie Date: Tue, 11 Oct 2022 05:07:02 -0600 Subject: [PATCH 004/367] Eplanning Bid Adapter: add support for video (#9044) * add video * move up imptypes logic * fix linting * update curly braces * fix spaces linting * fix line --- modules/eplanningBidAdapter.js | 50 ++- test/spec/modules/eplanningBidAdapter_spec.js | 286 +++++++++++++++++- 2 files changed, 333 insertions(+), 3 deletions(-) diff --git a/modules/eplanningBidAdapter.js b/modules/eplanningBidAdapter.js index 0d37b72f4ad..b60c3571d47 100644 --- a/modules/eplanningBidAdapter.js +++ b/modules/eplanningBidAdapter.js @@ -2,6 +2,7 @@ import {getWindowSelf, isEmpty, parseSizesInput, isGptPubadsDefined, isSlotMatch import {getGlobal} from '../src/prebidGlobal.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {getStorageManager} from '../src/storageManager.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; const BIDDER_CODE = 'eplanning'; export const storage = getStorageManager({bidderCode: BIDDER_CODE}); @@ -19,9 +20,14 @@ const STORAGE_VIEW_PREFIX = 'pbvi_'; const mobileUserAgent = isMobileUserAgent(); const PRIORITY_ORDER_FOR_MOBILE_SIZES_ASC = ['1x1', '300x50', '320x50', '300x250']; const PRIORITY_ORDER_FOR_DESKTOP_SIZES_ASC = ['1x1', '970x90', '970x250', '160x600', '300x600', '728x90', '300x250']; +const VAST_INSTREAM = 1; +const VAST_OUTSTREAM = 2; +const VAST_VERSION_DEFAULT = 3; +const DEFAULT_SIZE_VAST = '640x480'; export const spec = { code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: function(bid) { return Boolean(bid.params.ci) || Boolean(bid.params.t); @@ -86,6 +92,10 @@ export const spec = { params['e_' + id] = (typeof userIds[id] === 'object') ? encodeURIComponent(JSON.stringify(userIds[id])) : encodeURIComponent(userIds[id]); } } + if (spaces.impType) { + params.vctx = spaces.impType & VAST_INSTREAM ? VAST_INSTREAM : VAST_OUTSTREAM; + params.vv = VAST_VERSION_DEFAULT; + } } return { @@ -108,7 +118,6 @@ export const spec = { cpm: ad.pr, width: ad.w, height: ad.h, - ad: ad.adm, ttl: TTL, creativeId: ad.crid, netRevenue: NET_REVENUE, @@ -119,6 +128,13 @@ export const spec = { advertiserDomains: ad.adom }; } + if (isVastResponse(ad)) { + bidResponse.vastXml = ad.adm; + bidResponse.mediaTypes = VIDEO; + } else { + bidResponse.ad = ad.adm; + } + bidResponses.push(bidResponse); }); } @@ -236,17 +252,42 @@ function getSpacesStruct(bids) { return e; } +function getFirstSizeVast(sizes) { + if (sizes == undefined || !Array.isArray(sizes)) { + return undefined; + } + + let size = Array.isArray(sizes[0]) ? sizes[0] : sizes; + + return (Array.isArray(size) && size.length == 2) ? size : undefined; +} + function cleanName(name) { return name.replace(/_|\.|-|\//g, '').replace(/\)\(|\(|\)|:/g, '_').replace(/^_+|_+$/g, ''); } function getSpaces(bidRequests, ml) { + let impType = bidRequests.reduce((previousBits, bid) => (bid.mediaTypes && bid.mediaTypes[VIDEO]) ? (bid.mediaTypes[VIDEO].context == 'outstream' ? (previousBits | 2) : (previousBits | 1)) : previousBits, 0); + // Only one type of auction is supported at a time + if (impType) { + bidRequests = bidRequests.filter((bid) => bid.mediaTypes && bid.mediaTypes[VIDEO] && (impType & VAST_INSTREAM ? (!bid.mediaTypes[VIDEO].context || bid.mediaTypes[VIDEO].context == 'instream') : (bid.mediaTypes[VIDEO].context == 'outstream'))); + } + let spacesStruct = getSpacesStruct(bidRequests); - let es = {str: '', vs: '', map: {}}; + let es = {str: '', vs: '', map: {}, impType: impType}; es.str = Object.keys(spacesStruct).map(size => spacesStruct[size].map((bid, i) => { es.vs += getVs(bid); let name; + + if (impType) { + let firstSize = getFirstSizeVast(bid.mediaTypes[VIDEO].playerSize); + let sizeVast = firstSize ? firstSize.join('x') : DEFAULT_SIZE_VAST; + name = 'video_' + sizeVast + '_' + i; + es.map[name] = bid.bidId; + return name + ':' + sizeVast + ';1'; + } + if (ml) { name = cleanName(bid.adUnitCode); } else { @@ -462,4 +503,9 @@ function registerAuction(storageID) { return true; } + +function isVastResponse(bid) { + return bid.adm.match(/^( Date: Tue, 11 Oct 2022 15:33:11 +0100 Subject: [PATCH 005/367] ConnectID: Support new easy-opt out method (#9069) * Respect custom opt-out override localstorage key. * Wrap opt-out check in a function. * Rename function * Add unit tests Co-authored-by: slimkrazy --- modules/connectIdSystem.js | 17 ++++++++++++++++- test/spec/modules/connectIdSystem_spec.js | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/modules/connectIdSystem.js b/modules/connectIdSystem.js index 2da2eda4c77..4fad832302f 100644 --- a/modules/connectIdSystem.js +++ b/modules/connectIdSystem.js @@ -7,18 +7,27 @@ import {ajax} from '../src/ajax.js'; import {submodule} from '../src/hook.js'; -import {formatQS, logError} from '../src/utils.js'; import {includes} from '../src/polyfill.js'; +import {formatQS, logError} from '../src/utils.js'; const MODULE_NAME = 'connectId'; const VENDOR_ID = 25; const PLACEHOLDER = '__PIXEL_ID__'; const UPS_ENDPOINT = `https://ups.analytics.yahoo.com/ups/${PLACEHOLDER}/fed`; +const OVERRIDE_OPT_OUT_KEY = 'connectIdOptOut'; function isEUConsentRequired(consentData) { return !!(consentData && consentData.gdpr && consentData.gdpr.gdprApplies); } +function userHasOptedOut() { + try { + return localStorage.getItem(OVERRIDE_OPT_OUT_KEY) === '1'; + } catch { + return false; + } +} + /** @type {Submodule} */ export const connectIdSubmodule = { /** @@ -36,6 +45,9 @@ export const connectIdSubmodule = { * @returns {{connectId: string} | undefined} */ decode(value) { + if (userHasOptedOut()) { + return undefined; + } return (typeof value === 'object' && value.connectid) ? {connectId: value.connectid} : undefined; }, @@ -47,6 +59,9 @@ export const connectIdSubmodule = { * @returns {IdResponse|undefined} */ getId(config, consentData) { + if (userHasOptedOut()) { + return; + } const params = config.params || {}; if (!params || typeof params.he !== 'string' || (typeof params.pixelId === 'undefined' && typeof params.endpoint === 'undefined')) { diff --git a/test/spec/modules/connectIdSystem_spec.js b/test/spec/modules/connectIdSystem_spec.js index 41135a74515..fe3cb81c2ea 100644 --- a/test/spec/modules/connectIdSystem_spec.js +++ b/test/spec/modules/connectIdSystem_spec.js @@ -76,6 +76,26 @@ describe('Yahoo ConnectID Submodule', () => { expect(result.callback).to.be.a('function'); }); + it('returns an undefined if the Yahoo specific opt-out key is present in local storage', () => { + localStorage.setItem('connectIdOptOut', '1'); + expect(invokeGetIdAPI({ + he: HASHED_EMAIL, + pixelId: PIXEL_ID + }, consentData)).to.be.undefined; + localStorage.removeItem('connectIdOptOut'); + }); + + it('returns an object with the callback function if the correct params are passed and Yahoo opt-out value is not "1"', () => { + localStorage.setItem('connectIdOptOut', 'true'); + let result = invokeGetIdAPI({ + he: HASHED_EMAIL, + pixelId: PIXEL_ID + }, consentData); + expect(result).to.be.an('object').that.has.all.keys('callback'); + expect(result.callback).to.be.a('function'); + localStorage.removeItem('connectIdOptOut'); + }); + it('Makes an ajax GET request to the production API endpoint with query params', () => { invokeGetIdAPI({ he: HASHED_EMAIL, From 5e18b2dce96549b9d340d1380d048561e780de61 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 11 Oct 2022 07:53:08 -0700 Subject: [PATCH 006/367] Core & multiple modules: introduce new `bidRejected` event, and refactor bid rejection logic (#9013) * Separate code path for bid rejection * Client side bidder rejections * Rejection reasons in constants.json * PBS rejections * priceFloors * currency * Filter out NO_BID bids from targeting * Reject bids whose size does not match the request * Do not allow PBS stored impressions to go through without allowUnknownBidderCodes --- modules/categoryTranslation.js | 8 +- modules/currency.js | 22 +- modules/dchain.js | 4 +- modules/debugging/legacy.js | 4 +- modules/mass.js | 4 +- modules/multibid/index.js | 10 +- modules/prebidServerBidAdapter/index.js | 16 +- modules/priceFloors.js | 30 +-- src/adapters/bidderFactory.js | 24 +- src/auction.js | 209 ++++++++++++------ src/constants.json | 8 + src/prebid.js | 5 +- src/targeting.js | 45 ++-- test/fixtures/fixtures.js | 3 +- test/spec/auctionmanager_spec.js | 130 +++++++++-- test/spec/modules/currency_spec.js | 20 +- .../modules/prebidServerBidAdapter_spec.js | 54 ++++- test/spec/modules/priceFloors_spec.js | 10 +- test/spec/unit/core/bidderFactory_spec.js | 77 ++++++- test/spec/unit/core/targeting_spec.js | 37 +++- test/spec/unit/pbjs_api_spec.js | 6 +- 21 files changed, 509 insertions(+), 217 deletions(-) diff --git a/modules/categoryTranslation.js b/modules/categoryTranslation.js index 57267095ff0..ba73aa01b85 100644 --- a/modules/categoryTranslation.js +++ b/modules/categoryTranslation.js @@ -34,13 +34,13 @@ export const registerAdserver = hook('async', function(adServer) { }, 'registerAdserver'); registerAdserver(); -export const getAdserverCategoryHook = timedBidResponseHook('categoryTranslation', function getAdserverCategoryHook(fn, adUnitCode, bid) { +export const getAdserverCategoryHook = timedBidResponseHook('categoryTranslation', function getAdserverCategoryHook(fn, adUnitCode, bid, reject) { if (!bid) { - return fn.call(this, adUnitCode); // if no bid, call original and let it display warnings + return fn.call(this, adUnitCode, bid, reject); // if no bid, call original and let it display warnings } if (!config.getConfig('adpod.brandCategoryExclusion')) { - return fn.call(this, adUnitCode, bid); + return fn.call(this, adUnitCode, bid, reject); } let localStorageKey = (config.getConfig('brandCategoryTranslation.translationFile')) ? DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB : DEFAULT_IAB_TO_FW_MAPPING_KEY; @@ -63,7 +63,7 @@ export const getAdserverCategoryHook = timedBidResponseHook('categoryTranslation logError('Translation mapping data not found in local storage'); } } - fn.call(this, adUnitCode, bid); + fn.call(this, adUnitCode, bid, reject); }); export function initTranslation(url, localStorageKey) { diff --git a/modules/currency.js b/modules/currency.js index f0ad6681afa..2c8070bcb08 100644 --- a/modules/currency.js +++ b/modules/currency.js @@ -1,10 +1,9 @@ -import { logInfo, logWarn, logError, logMessage } from '../src/utils.js'; -import { getGlobal } from '../src/prebidGlobal.js'; -import { createBid } from '../src/bidfactory.js'; +import {logError, logInfo, logMessage, logWarn} from '../src/utils.js'; +import {getGlobal} from '../src/prebidGlobal.js'; import CONSTANTS from '../src/constants.json'; -import { ajax } from '../src/ajax.js'; -import { config } from '../src/config.js'; -import { getHook } from '../src/hook.js'; +import {ajax} from '../src/ajax.js'; +import {config} from '../src/config.js'; +import {getHook} from '../src/hook.js'; import {defer} from '../src/utils/promise.js'; import {timedBidResponseHook} from '../src/utils/perfMetrics.js'; @@ -181,9 +180,9 @@ function resetCurrency() { bidderCurrencyDefault = {}; } -export const addBidResponseHook = timedBidResponseHook('currency', function addBidResponseHook(fn, adUnitCode, bid) { +export const addBidResponseHook = timedBidResponseHook('currency', function addBidResponseHook(fn, adUnitCode, bid, reject) { if (!bid) { - return fn.call(this, adUnitCode); // if no bid, call original and let it display warnings + return fn.call(this, adUnitCode, bid, reject); // if no bid, call original and let it display warnings } let bidder = bid.bidderCode || bid.bidder; @@ -209,10 +208,10 @@ export const addBidResponseHook = timedBidResponseHook('currency', function addB // execute immediately if the bid is already in the desired currency if (bid.currency === adServerCurrency) { - return fn.call(this, adUnitCode, bid); + return fn.call(this, adUnitCode, bid, reject); } - bidResponseQueue.push(wrapFunction(fn, this, [adUnitCode, bid])); + bidResponseQueue.push(wrapFunction(fn, this, [adUnitCode, bid, reject])); if (!currencySupportEnabled || currencyRatesLoaded) { processBidResponseQueue(); } else { @@ -239,7 +238,8 @@ function wrapFunction(fn, context, params) { } } catch (e) { logWarn('Returning NO_BID, getCurrencyConversion threw error: ', e); - params[1] = createBid(CONSTANTS.STATUS.NO_BID, bid.getIdentifiers()); + // TODO: in v8, this should not continue with a "NO_BID" + params[1] = params[2](CONSTANTS.REJECTION_REASON.CANNOT_CONVERT_CURRENCY); } } return fn.apply(context, params); diff --git a/modules/dchain.js b/modules/dchain.js index 79e20520e93..daf97a7551f 100644 --- a/modules/dchain.js +++ b/modules/dchain.js @@ -109,7 +109,7 @@ function isValidDchain(bid) { } } -export const addBidResponseHook = timedBidResponseHook('dchain', function addBidResponseHook(fn, adUnitCode, bid) { +export const addBidResponseHook = timedBidResponseHook('dchain', function addBidResponseHook(fn, adUnitCode, bid, reject) { const basicDchain = { ver: '1.0', complete: 0, @@ -140,7 +140,7 @@ export const addBidResponseHook = timedBidResponseHook('dchain', function addBid bid.meta.dchain = basicDchain; } - fn(adUnitCode, bid); + fn(adUnitCode, bid, reject); }); export function init() { diff --git a/modules/debugging/legacy.js b/modules/debugging/legacy.js index 15b05cded64..e83b99c5194 100644 --- a/modules/debugging/legacy.js +++ b/modules/debugging/legacy.js @@ -54,7 +54,7 @@ export function applyBidOverrides(overrideObj, bidObj, bidType, logger) { }, bidObj); } -export function addBidResponseHook(next, adUnitCode, bid) { +export function addBidResponseHook(next, adUnitCode, bid, reject) { const {overrides, logger} = this; if (bidderExcluded(overrides.bidders, bid.bidderCode)) { @@ -70,7 +70,7 @@ export function addBidResponseHook(next, adUnitCode, bid) { }); } - next(adUnitCode, bid); + next(adUnitCode, bid, reject); } export function addBidderRequestsHook(next, bidderRequests) { diff --git a/modules/mass.js b/modules/mass.js index 6a01f06bd90..113fdce8d4f 100644 --- a/modules/mass.js +++ b/modules/mass.js @@ -78,7 +78,7 @@ export function updateRenderers() { /** * Before hook for 'addBidResponse'. */ -export const addBidResponseHook = timedBidResponseHook('mass', function addBidResponseHook(next, adUnitCode, bid, {index = auctionManager.index} = {}) { +export const addBidResponseHook = timedBidResponseHook('mass', function addBidResponseHook(next, adUnitCode, bid, reject, {index = auctionManager.index} = {}) { let renderer; for (let i = 0; i < renderers.length; i++) { if (renderers[i].match(bid)) { @@ -104,7 +104,7 @@ export const addBidResponseHook = timedBidResponseHook('mass', function addBidRe addListenerOnce(); } - next(adUnitCode, bid); + next(adUnitCode, bid, reject); }); /** diff --git a/modules/multibid/index.js b/modules/multibid/index.js index fb28be83fa8..76f4ede8f8e 100644 --- a/modules/multibid/index.js +++ b/modules/multibid/index.js @@ -99,7 +99,7 @@ export function adjustBidderRequestsHook(fn, bidderRequests) { * @param {String} ad unit code for bid * @param {Object} bid object */ -export const addBidResponseHook = timedBidResponseHook('multibid', function addBidResponseHook(fn, adUnitCode, bid) { +export const addBidResponseHook = timedBidResponseHook('multibid', function addBidResponseHook(fn, adUnitCode, bid, reject) { let floor = deepAccess(bid, 'floorData.floorValue'); if (!config.getConfig('multibid')) resetMultiConfig(); @@ -107,7 +107,7 @@ export const addBidResponseHook = timedBidResponseHook('multibid', function addB // Else checks if multiconfig exists and bid bidderCode exists within config // Else continue with no modifications if (hasMultibid && multiConfig[bid.bidderCode] && deepAccess(bid, 'video.context') === 'adpod') { - fn.call(this, adUnitCode, bid); + fn.call(this, adUnitCode, bid, reject); } else if (hasMultibid && multiConfig[bid.bidderCode]) { // Set property multibidPrefix on bid if (multiConfig[bid.bidderCode].prefix) bid.multibidPrefix = multiConfig[bid.bidderCode].prefix; @@ -127,7 +127,7 @@ export const addBidResponseHook = timedBidResponseHook('multibid', function addB if (multiConfig[bid.bidderCode].prefix) bid.targetingBidder = multiConfig[bid.bidderCode].prefix + length; if (length === multiConfig[bid.bidderCode].maxbids) multibidUnits[adUnitCode][bid.bidderCode].maxReached = true; - fn.call(this, adUnitCode, bid); + fn.call(this, adUnitCode, bid, reject); } else { logWarn(`Filtering multibid received from bidder ${bid.bidderCode}: ` + ((multibidUnits[adUnitCode][bid.bidderCode].maxReached) ? `Maximum bid limit reached for ad unit code ${adUnitCode}` : 'Bid cpm under floors value.')); } @@ -137,10 +137,10 @@ export const addBidResponseHook = timedBidResponseHook('multibid', function addB deepSetValue(multibidUnits, [adUnitCode, bid.bidderCode], {ads: [bid]}); if (multibidUnits[adUnitCode][bid.bidderCode].ads.length === multiConfig[bid.bidderCode].maxbids) multibidUnits[adUnitCode][bid.bidderCode].maxReached = true; - fn.call(this, adUnitCode, bid); + fn.call(this, adUnitCode, bid, reject); } } else { - fn.call(this, adUnitCode, bid); + fn.call(this, adUnitCode, bid, reject); } }); diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 5bdf9868d24..856b962e8a0 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -950,10 +950,6 @@ Object.assign(ORTB2.prototype, { (seatbid.bid || []).forEach(bid => { let bidRequest = this.getBidRequest(bid.impid, seatbid.seat); if (bidRequest == null) { - if (!s2sConfig.allowUnknownBidderCodes) { - logWarn(`PBS adapter received bid from unknown bidder (${seatbid.seat}), but 's2sConfig.allowUnknownBidderCodes' is not set. Ignoring bid.`); - return; - } // for stored impression, a request was made with bidder code `null`. Pick it up here so that NO_BID, BID_WON, etc events // can work as expected (otherwise, the original request will always result in NO_BID). bidRequest = this.getBidRequest(bid.impid, null); @@ -968,6 +964,7 @@ Object.assign(ORTB2.prototype, { transactionId: this.adUnitsByImp[bid.impid].transactionId, auctionId: this.auctionId, }); + bidObject.requestBidder = bidRequest?.bidder; bidObject.requestTimestamp = this.requestTimestamp; bidObject.cpm = cpm; if (bid?.ext?.prebid?.meta?.adaptercode) { @@ -1158,8 +1155,15 @@ export function PrebidServer() { onBid: function ({adUnit, bid}) { const metrics = bid.metrics = s2sBidRequest.metrics.fork().renameWith(); metrics.checkpoint('addBidResponse'); - if (metrics.measureTime('addBidResponse.validate', () => isValid(adUnit, bid))) { - addBidResponse(adUnit, bid); + if ((bid.requestId == null || bid.requestBidder == null) && !s2sBidRequest.s2sConfig.allowUnknownBidderCodes) { + logWarn(`PBS adapter received bid from unknown bidder (${bid.bidder}), but 's2sConfig.allowUnknownBidderCodes' is not set. Ignoring bid.`); + addBidResponse.reject(adUnit, bid, CONSTANTS.REJECTION_REASON.BIDDER_DISALLOWED); + } else { + if (metrics.measureTime('addBidResponse.validate', () => isValid(adUnit, bid))) { + addBidResponse(adUnit, bid); + } else { + addBidResponse.reject(adUnit, bid, CONSTANTS.REJECTION_REASON.INVALID); + } } } }) diff --git a/modules/priceFloors.js b/modules/priceFloors.js index e4203fd73d3..5aee87d474e 100644 --- a/modules/priceFloors.js +++ b/modules/priceFloors.js @@ -20,7 +20,6 @@ import {ajaxBuilder} from '../src/ajax.js'; import * as events from '../src/events.js'; import CONSTANTS from '../src/constants.json'; import {getHook} from '../src/hook.js'; -import {createBid} from '../src/bidfactory.js'; import {find} from '../src/polyfill.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {bidderSettings} from '../src/bidderSettings.js'; @@ -694,11 +693,11 @@ function shouldFloorBid(floorData, floorInfo, bid) { * @summary The main driving force of floors. On bidResponse we hook in and intercept bidResponses. * And if the rule we find determines a bid should be floored we will do so. */ -export const addBidResponseHook = timedBidResponseHook('priceFloors', function addBidResponseHook(fn, adUnitCode, bid) { +export const addBidResponseHook = timedBidResponseHook('priceFloors', function addBidResponseHook(fn, adUnitCode, bid, reject) { let floorData = _floorDataForAuction[bid.auctionId]; // if no floor data then bail if (!floorData || !bid || floorData.skipped) { - return fn.call(this, adUnitCode, bid); + return fn.call(this, adUnitCode, bid, reject); } const matchingBidRequest = auctionManager.index.getBidRequest(bid); @@ -708,7 +707,7 @@ export const addBidResponseHook = timedBidResponseHook('priceFloors', function a if (!floorInfo.matchingFloor) { logWarn(`${MODULE_NAME}: unable to determine a matching price floor for bidResponse`, bid); - return fn.call(this, adUnitCode, bid); + return fn.call(this, adUnitCode, bid, reject); } // determine the base cpm to use based on if the currency matches the floor currency @@ -724,7 +723,7 @@ export const addBidResponseHook = timedBidResponseHook('priceFloors', function a adjustedCpm = getGlobal().convertCurrency(bid.cpm, bidResponseCurrency.toUpperCase(), floorCurrency); } catch (err) { logError(`${MODULE_NAME}: Unable do get currency conversion for bidResponse to Floor Currency. Do you have Currency module enabled? ${bid}`); - return fn.call(this, adUnitCode, bid); + return fn.call(this, adUnitCode, bid, reject); } } @@ -737,25 +736,12 @@ export const addBidResponseHook = timedBidResponseHook('priceFloors', function a // now do the compare! if (shouldFloorBid(floorData, floorInfo, bid)) { // bid fails floor -> throw it out - // create basic bid no-bid with necessary data fro analytics adapters - let flooredBid = createBid(CONSTANTS.STATUS.NO_BID, bid.getIdentifiers()); - Object.assign(flooredBid, pick(bid, [ - 'floorData', - 'width', - 'height', - 'mediaType', - 'currency', - 'originalCpm', - 'originalCurrency', - 'getCpmInNewCurrency', - ])); - flooredBid.status = CONSTANTS.BID_STATUS.BID_REJECTED; - // if floor not met update bid with 0 cpm so it is not included downstream and marked as no-bid - flooredBid.cpm = 0; + // continue with a "NO_BID" bid, TODO: remove this in v8 + const flooredBid = reject(CONSTANTS.REJECTION_REASON.FLOOR_NOT_MET); logWarn(`${MODULE_NAME}: ${flooredBid.bidderCode}'s Bid Response for ${adUnitCode} was rejected due to floor not met (adjusted cpm: ${bid?.floorData?.cpmAfterAdjustments}, floor: ${floorInfo?.matchingFloor})`, bid); - return fn.call(this, adUnitCode, flooredBid); + return fn.call(this, adUnitCode, flooredBid, reject); } - return fn.call(this, adUnitCode, bid); + return fn.call(this, adUnitCode, bid, reject); }); config.getConfig('floors', config => handleSetFloorsConfig(config.floors)); diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index c60f4b8a015..d0b716d656d 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -202,6 +202,8 @@ export function newBidder(spec) { adUnitCodesHandled[adUnitCode] = true; if (metrics.measureTime('addBidResponse.validate', () => isValid(adUnitCode, bid))) { addBidResponse(adUnitCode, bid); + } else { + addBidResponse.reject(adUnitCode, bid, CONSTANTS.REJECTION_REASON.INVALID) } } @@ -262,6 +264,7 @@ export function newBidder(spec) { bid.adapterCode = bidRequest.bidder; if (isInvalidAlternateBidder(bid.bidderCode, bidRequest.bidder)) { logWarn(`${bid.bidderCode} is not a registered partner or known bidder of ${bidRequest.bidder}, hence continuing without bid. If you wish to support this bidder, please mark allowAlternateBidderCodes as true in bidderSettings.`); + addBidResponse.reject(bidRequest.adUnitCode, bid, CONSTANTS.REJECTION_REASON.BIDDER_DISALLOWED) return; } // creating a copy of original values as cpm and currency are modified later @@ -272,6 +275,7 @@ export function newBidder(spec) { addBidWithCode(bidRequest.adUnitCode, prebidBid); } else { logWarn(`Bidder ${spec.code} made bid for unknown request ID: ${bid.requestId}. Ignoring.`); + addBidResponse.reject(null, bid, CONSTANTS.REJECTION_REASON.INVALID_REQUEST_ID); } }, onCompletion: afterAllResponses, @@ -541,24 +545,22 @@ export function getIabSubCategory(bidderCode, category) { // check that the bid has a width and height set function validBidSize(adUnitCode, bid, {index = auctionManager.index} = {}) { - if ((bid.width || parseInt(bid.width, 10) === 0) && (bid.height || parseInt(bid.height, 10) === 0)) { - bid.width = parseInt(bid.width, 10); - bid.height = parseInt(bid.height, 10); - return true; - } - const bidRequest = index.getBidRequest(bid); const mediaTypes = index.getMediaTypes(bid); const sizes = (bidRequest && bidRequest.sizes) || (mediaTypes && mediaTypes.banner && mediaTypes.banner.sizes); - const parsedSizes = parseSizesInput(sizes); + const parsedSizes = parseSizesInput(sizes).map(sz => sz.split('x').map(n => parseInt(n, 10))); + + if ((bid.width || parseInt(bid.width, 10) === 0) && (bid.height || parseInt(bid.height, 10) === 0)) { + bid.width = parseInt(bid.width, 10); + bid.height = parseInt(bid.height, 10); + return parsedSizes.length === 0 || parsedSizes.some(([w, h]) => bid.width === w && bid.height === h); + } // if a banner impression has one valid size, we assign that size to any bid // response that does not explicitly set width or height if (parsedSizes.length === 1) { - const [ width, height ] = parsedSizes[0].split('x'); - bid.width = parseInt(width, 10); - bid.height = parseInt(height, 10); + ([bid.width, bid.height] = parsedSizes[0]); return true; } @@ -600,7 +602,7 @@ export function isValid(adUnitCode, bid, {index = auctionManager.index} = {}) { return false; } if (bid.mediaType === 'banner' && !validBidSize(adUnitCode, bid, {index})) { - logError(errorMessage(`Banner bids require a width and height`)); + logError(errorMessage(`Banner bids require a width and height that match one of the requested sizes`)); return false; } diff --git a/src/auction.js b/src/auction.js index 81280e0833c..26561d87d71 100644 --- a/src/auction.js +++ b/src/auction.js @@ -58,26 +58,41 @@ */ import { - flatten, timestamp, adUnitsFilter, deepAccess, getValue, parseUrl, generateUUID, - logMessage, bind, logError, logInfo, logWarn, isEmpty, _each, isFn, isEmptyStr + _each, + adUnitsFilter, + bind, + deepAccess, + flatten, + generateUUID, + getValue, + isEmpty, + isEmptyStr, + isFn, + logError, + logInfo, + logMessage, + logWarn, + parseUrl, + timestamp } 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 {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, includes} from './polyfill.js'; -import { OUTSTREAM } from './video.js'; -import { VIDEO } from './mediaTypes.js'; +import {OUTSTREAM} from './video.js'; +import {VIDEO} from './mediaTypes.js'; import {auctionManager} from './auctionManager.js'; import {bidderSettings} from './bidderSettings.js'; -import * as events from './events.js' +import * as events from './events.js'; import adapterManager from './adapterManager.js'; import CONSTANTS from './constants.json'; import {GreedyPromise} from './utils/promise.js'; import {useMetrics} from './utils/perfMetrics.js'; +import {createBid} from './bidfactory.js'; const { syncUsers } = userSync; @@ -119,24 +134,26 @@ export function resetAuctionState() { */ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, auctionId, ortb2Fragments, metrics}) { metrics = useMetrics(metrics); - let _adUnits = adUnits; - let _labels = labels; - let _adUnitCodes = adUnitCodes; + const _adUnits = adUnits; + const _labels = labels; + const _adUnitCodes = adUnitCodes; + const _auctionId = auctionId || generateUUID(); + const _timeout = cbTimeout; + const _timelyBidders = new Set(); + let _bidsRejected = []; + let _callback = callback; let _bidderRequests = []; let _bidsReceived = []; let _noBids = []; + let _winningBids = []; let _auctionStart; let _auctionEnd; - let _auctionId = auctionId || generateUUID(); - let _auctionStatus; - let _callback = callback; let _timer; - let _timeout = cbTimeout; - let _winningBids = []; - let _timelyBidders = new Set(); + let _auctionStatus; function addBidRequests(bidderRequests) { _bidderRequests = _bidderRequests.concat(bidderRequests); } function addBidReceived(bidsReceived) { _bidsReceived = _bidsReceived.concat(bidsReceived); } + function addBidRejected(bidsRejected) { _bidsRejected = _bidsRejected.concat(bidsRejected); } function addNoBid(noBid) { _noBids = _noBids.concat(noBid); } function getProperties() { @@ -151,6 +168,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a bidderRequests: _bidderRequests, noBids: _noBids, bidsReceived: _bidsReceived, + bidsRejected: _bidsRejected, winningBids: _winningBids, timeout: _timeout, metrics: metrics @@ -352,6 +370,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a return { addBidReceived, + addBidRejected, addNoBid, executeCallback, callBids, @@ -372,7 +391,14 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a }; } -export const addBidResponse = hook('sync', function(adUnitCode, bid) { +/** + * Hook into this to intercept bids before they are added to an auction. + * + * @param adUnitCode + * @param bid + * @param {function(String)} reject: a function that, when called, rejects `bid` with the given reason. + */ +export const addBidResponse = hook('sync', function(adUnitCode, bid, reject) { this.dispatch.call(null, adUnitCode, bid); }, 'addBidResponse'); @@ -425,20 +451,49 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM } } - function handleBidResponse(adUnitCode, bid) { + function handleBidResponse(adUnitCode, bid, handler) { bidResponseMap[bid.requestId] = true; - + addCommonResponseProperties(bid, adUnitCode) outstandingBidsAdded++; - let auctionId = auctionInstance.getAuctionId(); + return handler(afterBidAdded); + } - let bidResponse = getPreparedBidForAuction({adUnitCode, bid, auctionId}); + function acceptBidResponse(adUnitCode, bid) { + handleBidResponse(adUnitCode, bid, (done) => { + let bidResponse = getPreparedBidForAuction(bid); - if (bidResponse.mediaType === 'video') { - tryAddVideoBid(auctionInstance, bidResponse, afterBidAdded); - } else { - addBidToAuction(auctionInstance, bidResponse); - afterBidAdded(); - } + if (bidResponse.mediaType === 'video') { + tryAddVideoBid(auctionInstance, bidResponse, done); + } else { + addBidToAuction(auctionInstance, bidResponse); + done(); + } + }); + } + + function rejectBidResponse(adUnitCode, bid, reason) { + return handleBidResponse(adUnitCode, bid, (done) => { + // return a "NO_BID" replacement that the caller can decide to continue with + // TODO: remove this in v8; see https://github.com/prebid/Prebid.js/issues/8956 + const noBid = createBid(CONSTANTS.STATUS.NO_BID, bid.getIdentifiers()); + Object.assign(noBid, Object.fromEntries(Object.entries(bid).filter(([k]) => !noBid.hasOwnProperty(k) && ![ + 'ad', + 'adUrl', + 'vastXml', + 'vastUrl', + 'native', + ].includes(k)))); + noBid.status = CONSTANTS.BID_STATUS.BID_REJECTED; + noBid.cpm = 0; + + bid.rejectionReason = reason; + logWarn(`Bid from ${bid.bidder || 'unknown bidder'} was rejected: ${reason}`, bid) + events.emit(CONSTANTS.EVENTS.BID_REJECTED, bid); + auctionInstance.addBidRejected(bid); + done(); + + return noBid; + }) } function adapterDone() { @@ -470,12 +525,24 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM } return { - addBidResponse: function (adUnit, bid) { - const bidderRequest = index.getBidderRequest(bid); - waitFor((bidderRequest && bidderRequest.bidderRequestId) || '', addBidResponse.call({ - dispatch: handleBidResponse, - }, adUnit, bid)); - }, + addBidResponse: (function () { + function addBid(adUnitCode, bid) { + const bidderRequest = index.getBidderRequest(bid); + waitFor((bidderRequest && bidderRequest.bidderRequestId) || '', addBidResponse.call({ + dispatch: acceptBidResponse, + }, adUnitCode, bid, (() => { + let rejection; + return (reason) => { + if (rejection == null) { + rejection = rejectBidResponse(adUnitCode, bid, reason); + } + return rejection; + } + })())); + } + addBid.reject = rejectBidResponse; + return addBid; + })(), adapterDone: function () { guard(this, adapterDone.bind(this)) } @@ -492,9 +559,7 @@ export function doCallbacksIfTimedout(auctionInstance, bidResponse) { export function addBidToAuction(auctionInstance, bidResponse) { setupBidTargeting(bidResponse); - const metrics = useMetrics(bidResponse.metrics); - metrics.timeSince('addBidResponse', 'addBidResponse.total'); - + useMetrics(bidResponse.metrics).timeSince('addBidResponse', 'addBidResponse.total'); events.emit(CONSTANTS.EVENTS.BID_RESPONSE, bidResponse); auctionInstance.addBidReceived(bidResponse); @@ -595,35 +660,41 @@ export const callPrebidCache = hook('async', function(auctionInstance, bidRespon batchAndStore(auctionInstance, bidResponse, afterBidAdded); }, 'callPrebidCache'); -// Postprocess the bids so that all the universal properties exist, no matter which bidder they came from. -// This should be called before addBidToAuction(). -function getPreparedBidForAuction({adUnitCode, bid, auctionId}, {index = auctionManager.index} = {}) { - const bidderRequest = index.getBidderRequest(bid); - const start = (bidderRequest && bidderRequest.start) || bid.requestTimestamp; - - let bidObject = Object.assign({}, bid, { - auctionId, - responseTimestamp: timestamp(), - requestTimestamp: start, - cpm: parseFloat(bid.cpm) || 0, - bidder: bid.bidderCode, +/** + * Augment `bidResponse` with properties that are common across all bids - including rejected bids. + * + */ +function addCommonResponseProperties(bidResponse, adUnitCode, {index = auctionManager.index} = {}) { + const bidderRequest = index.getBidderRequest(bidResponse); + const start = (bidderRequest && bidderRequest.start) || bidResponse.requestTimestamp; + + Object.assign(bidResponse, { + responseTimestamp: bidResponse.responseTimestamp || timestamp(), + requestTimestamp: bidResponse.requestTimestamp || start, + cpm: bidResponse.cpm || parseFloat(bidResponse.cpm) || 0, + bidder: bidResponse.bidder || bidResponse.bidderCode, adUnitCode }); - bidObject.timeToRespond = bidObject.responseTimestamp - bidObject.requestTimestamp; + bidResponse.timeToRespond = bidResponse.responseTimestamp - bidResponse.requestTimestamp; +} +/** + * Add additional bid response properties that are universal for all _accepted_ bids. + */ +function getPreparedBidForAuction(bid, {index = auctionManager.index} = {}) { // Let listeners know that now is the time to adjust the bid, if they want to. // // CAREFUL: Publishers rely on certain bid properties to be available (like cpm), // but others to not be set yet (like priceStrings). See #1372 and #1389. - events.emit(CONSTANTS.EVENTS.BID_ADJUSTMENT, bidObject); + events.emit(CONSTANTS.EVENTS.BID_ADJUSTMENT, bid); // a publisher-defined renderer can be used to render bids - const adUnitRenderer = index.getAdUnit(bidObject).renderer; + const adUnitRenderer = index.getAdUnit(bid).renderer; // a publisher can also define a renderer for a mediaType - const bidObjectMediaType = bidObject.mediaType; - const mediaTypes = index.getMediaTypes(bidObject); + const bidObjectMediaType = bid.mediaType; + const mediaTypes = index.getMediaTypes(bid); const bidMediaType = mediaTypes && mediaTypes[bidObjectMediaType]; var mediaTypeRenderer = bidMediaType && bidMediaType.renderer; @@ -639,25 +710,25 @@ function getPreparedBidForAuction({adUnitCode, bid, auctionId}, {index = auction if (renderer) { // be aware, an adapter could already have installed the bidder, in which case this overwrite's the existing adapter - bidObject.renderer = Renderer.install({ url: renderer.url, config: renderer.options });// rename options to config, to make it consistent? - bidObject.renderer.setRender(renderer.render); + bid.renderer = Renderer.install({ url: renderer.url, config: renderer.options });// rename options to config, to make it consistent? + bid.renderer.setRender(renderer.render); } // Use the config value 'mediaTypeGranularity' if it has been defined for mediaType, else use 'customPriceBucket' const mediaTypeGranularity = getMediaTypeGranularity(bid.mediaType, mediaTypes, config.getConfig('mediaTypePriceGranularity')); const priceStringsObj = getPriceBucketString( - bidObject.cpm, + bid.cpm, (typeof mediaTypeGranularity === 'object') ? mediaTypeGranularity : config.getConfig('customPriceBucket'), config.getConfig('currency.granularityMultiplier') ); - bidObject.pbLg = priceStringsObj.low; - bidObject.pbMg = priceStringsObj.med; - bidObject.pbHg = priceStringsObj.high; - bidObject.pbAg = priceStringsObj.auto; - bidObject.pbDg = priceStringsObj.dense; - bidObject.pbCg = priceStringsObj.custom; - - return bidObject; + bid.pbLg = priceStringsObj.low; + bid.pbMg = priceStringsObj.med; + bid.pbHg = priceStringsObj.high; + bid.pbAg = priceStringsObj.auto; + bid.pbDg = priceStringsObj.dense; + bid.pbCg = priceStringsObj.custom; + + return bid; } function setupBidTargeting(bidObject) { diff --git a/src/constants.json b/src/constants.json index ad57fb45c4f..30ade5fccbe 100644 --- a/src/constants.json +++ b/src/constants.json @@ -29,6 +29,7 @@ "BID_TIMEOUT": "bidTimeout", "BID_REQUESTED": "bidRequested", "BID_RESPONSE": "bidResponse", + "BID_REJECTED": "bidRejected", "NO_BID": "noBid", "BID_WON": "bidWon", "BIDDER_DONE": "bidderDone", @@ -119,6 +120,13 @@ "RENDERED": "rendered", "BID_REJECTED": "bidRejected" }, + "REJECTION_REASON": { + "INVALID": "Bid has missing or invalid properties", + "INVALID_REQUEST_ID": "Invalid request ID", + "BIDDER_DISALLOWED": "Bidder code is not allowed by allowedAlternateBidderCodes / allowUnknownBidderCodes", + "FLOOR_NOT_MET": "Bid does not meet price floor", + "CANNOT_CONVERT_CURRENCY": "Unable to convert currency" + }, "PREBID_NATIVE_DATA_KEYS_TO_ORTB": { "body": "desc", "body2": "desc2", diff --git a/src/prebid.js b/src/prebid.js index 18826fc7205..a0981cd387a 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -36,7 +36,7 @@ import {listenMessagesFromCreative} from './secureCreatives.js'; import {userSync} from './userSync.js'; import {config} from './config.js'; import {auctionManager} from './auctionManager.js'; -import {filters, targeting} from './targeting.js'; +import {isBidUsable, targeting} from './targeting.js'; import {hook, wrapHook} from './hook.js'; import {loadSession} from './debugging.js'; import {includes} from './polyfill.js'; @@ -296,8 +296,7 @@ $$PREBID_GLOBAL$$.getAdserverTargetingForAdUnitCodeStr = function (adunitCode) { $$PREBID_GLOBAL$$.getHighestUnusedBidResponseForAdUnitCode = function (adunitCode) { if (adunitCode) { const bid = auctionManager.getAllBidsForAdUnitCode(adunitCode) - .filter(filters.isUnusedBid) - .filter(filters.isBidNotExpired) + .filter(isBidUsable) return bid.length ? bid.reduce(getHighestCpm) : {} } else { diff --git a/src/targeting.js b/src/targeting.js index d2b3e9f8470..a427867e890 100644 --- a/src/targeting.js +++ b/src/targeting.js @@ -1,15 +1,28 @@ import { - uniques, isGptPubadsDefined, getHighestCpm, getOldestHighestCpmBid, groupBy, isAdUnitCodeMatchingSlot, timestamp, - deepAccess, deepClone, logError, logWarn, logInfo, isFn, isArray, logMessage, isStr, + deepAccess, + deepClone, + getHighestCpm, + getOldestHighestCpmBid, + groupBy, + isAdUnitCodeMatchingSlot, + isArray, + isFn, + isGptPubadsDefined, + isStr, + logError, + logInfo, + logMessage, + logWarn, + timestamp, + uniques, } 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 { hook } from './hook.js'; -import { bidderSettings } from './bidderSettings.js'; -import {includes, find} from './polyfill.js'; +import {config} from './config.js'; +import {NATIVE_TARGETING_KEYS} from './native.js'; +import {auctionManager} from './auctionManager.js'; +import {ADPOD} from './mediaTypes.js'; +import {hook} from './hook.js'; +import {bidderSettings} from './bidderSettings.js'; +import {find, includes} from './polyfill.js'; import CONSTANTS from './constants.json'; var pbTargetingKeys = []; @@ -32,10 +45,17 @@ const isBidNotExpired = (bid) => (bid.responseTimestamp + bid.ttl * 1000 - TTL_B const isUnusedBid = (bid) => bid && ((bid.status && !includes([CONSTANTS.BID_STATUS.RENDERED], bid.status)) || !bid.status); export let filters = { + isActualBid(bid) { + return bid.getStatusCode() === CONSTANTS.STATUS.GOOD + }, isBidNotExpired, isUnusedBid }; +export function isBidUsable(bid) { + return !Object.values(filters).some((predicate) => !predicate(bid)); +} + // If two bids are found for same adUnitCode, we will use the highest one to take part in auction // This can happen in case of concurrent auctions // If adUnitBidLimit is set above 0 return top N number of bids @@ -449,10 +469,7 @@ export function newTargeting(auctionManager) { bidsReceived = bidsReceived .filter(bid => deepAccess(bid, 'video.context') !== ADPOD) - .filter(bid => bid.mediaType !== 'banner' || sizeSupported([bid.width, bid.height])) - .filter(filters.isUnusedBid) - .filter(filters.isBidNotExpired) - ; + .filter(isBidUsable); return getHighestCpmBidsFromBidPool(bidsReceived, getOldestHighestCpmBid); } diff --git a/test/fixtures/fixtures.js b/test/fixtures/fixtures.js index b0fbd7da806..b66d885c113 100644 --- a/test/fixtures/fixtures.js +++ b/test/fixtures/fixtures.js @@ -1,5 +1,6 @@ // jscs:disable import CONSTANTS from 'src/constants.json'; +import {createBid} from '../../src/bidfactory.js'; const utils = require('src/utils.js'); function convertTargetingsFromOldToNew(targetings) { @@ -1268,7 +1269,7 @@ export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, ad if (typeof status !== 'undefined') { bid.status = status; } - return bid; + return Object.assign(createBid(CONSTANTS.STATUS.GOOD), bid); } export function getServerTestingsAds() { diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index 49ae13c43cc..105401a62a4 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -21,6 +21,7 @@ import {auctionManager} from '../../src/auctionManager.js'; import 'modules/debugging/index.js' // some tests look for debugging side effects import {AuctionIndex} from '../../src/auctionIndex.js'; import {expect} from 'chai'; +import {deepClone} from '../../src/utils.js'; var assert = require('assert'); @@ -57,7 +58,16 @@ function mockBid(opts) { 'currency': 'USD', 'netRevenue': true, 'ttl': 360, - getSize: () => '300x250' + getSize: () => '300x250', + getIdentifiers() { + return { + src: this.source, + bidder: this.bidderCode, + bidId: this.requestId, + transactionId: this.transactionId, + auctionId: this.auctionId + } + } }; } @@ -1323,6 +1333,7 @@ describe('auctionmanager.js', function () { getAdUnits: () => getBidRequests().flatMap(br => br.bids).map(br => ({ code: br.adUnitCode, transactionId: br.transactionId, mediaTypes: br.mediaTypes })), getAuctionId: () => '1', addBidReceived: () => true, + addBidRejected: () => true, getTimeout: () => 1000, getAuctionStart: () => start, } @@ -1382,26 +1393,32 @@ describe('auctionmanager.js', function () { bidRequests = null; }); - it('should call auction done after bid is added to auction for mediaType banner', function () { - let ADUNIT_CODE2 = 'adUnitCode2'; - let BIDDER_CODE2 = 'sampleBidder2'; - - let bids1 = [mockBid({ bidderCode: BIDDER_CODE1, transactionId: ADUNIT_CODE1 })]; - let bids2 = [mockBid({ bidderCode: BIDDER_CODE2, transactionId: ADUNIT_CODE2 })]; - bidRequests = [ - mockBidRequest(bids[0]), - mockBidRequest(bids1[0], { adUnitCode: ADUNIT_CODE1 }), - mockBidRequest(bids2[0], { adUnitCode: ADUNIT_CODE2 }) - ]; - let cbs = auctionCallbacks(doneSpy, auction); - cbs.addBidResponse.call(bidRequests[0], ADUNIT_CODE, bids[0]); - cbs.adapterDone.call(bidRequests[0]); - cbs.addBidResponse.call(bidRequests[1], ADUNIT_CODE1, bids1[0]); - cbs.adapterDone.call(bidRequests[1]); - cbs.addBidResponse.call(bidRequests[2], ADUNIT_CODE2, bids2[0]); - cbs.adapterDone.call(bidRequests[2]); - assert.equal(doneSpy.callCount, 1); - }); + Object.entries({ + 'added to': (cbs) => cbs.addBidResponse, + 'rejected from': (cbs) => cbs.addBidResponse.reject, + }).forEach(([t, getMethod]) => { + it(`should call auction done after bid is ${t} auction for mediaType banner`, function () { + let ADUNIT_CODE2 = 'adUnitCode2'; + let BIDDER_CODE2 = 'sampleBidder2'; + + let bids1 = [mockBid({ bidderCode: BIDDER_CODE1, transactionId: ADUNIT_CODE1 })]; + let bids2 = [mockBid({ bidderCode: BIDDER_CODE2, transactionId: ADUNIT_CODE2 })]; + bidRequests = [ + mockBidRequest(bids[0]), + mockBidRequest(bids1[0], { adUnitCode: ADUNIT_CODE1 }), + mockBidRequest(bids2[0], { adUnitCode: ADUNIT_CODE2 }) + ]; + let cbs = auctionCallbacks(doneSpy, auction); + const method = getMethod(cbs); + method(ADUNIT_CODE, bids[0]); + cbs.adapterDone.call(bidRequests[0]); + method(ADUNIT_CODE1, bids1[0]); + cbs.adapterDone.call(bidRequests[1]); + method(ADUNIT_CODE2, bids2[0]); + cbs.adapterDone.call(bidRequests[2]); + assert.equal(doneSpy.callCount, 1); + }); + }) it('should call auction done after prebid cache is complete for mediaType video', function() { bids[0].mediaType = 'video'; @@ -1543,6 +1560,77 @@ describe('auctionmanager.js', function () { }); }) }); + + describe('when bids are rejected', () => { + let cbs, bid, expectedRejection; + const onBidRejected = sinon.stub(); + const REJECTION_REASON = 'Bid rejected'; + const AU_CODE = 'au'; + + function rejectHook(fn, adUnitCode, bid, reject) { + reject(REJECTION_REASON); + reject(REJECTION_REASON); // second call should do nothing + } + + before(() => { + addBidResponse.before(rejectHook, 999); + events.on(CONSTANTS.EVENTS.BID_REJECTED, onBidRejected); + }); + + after(() => { + addBidResponse.getHooks({hook: rejectHook}).remove(); + events.off(CONSTANTS.EVENTS.BID_REJECTED, onBidRejected); + }); + + beforeEach(() => { + onBidRejected.reset(); + bid = mockBid({bidderCode: BIDDER_CODE}); + bidRequests = [ + mockBidRequest(bid), + ]; + cbs = auctionCallbacks(doneSpy, auction); + expectedRejection = sinon.match(Object.assign({}, bid, { + rejectionReason: REJECTION_REASON, + adUnitCode: AU_CODE + })); + auction.addBidRejected = sinon.stub(); + }); + + Object.entries({ + 'with addBidResponse.reject': () => cbs.addBidResponse.reject(AU_CODE, deepClone(bid), REJECTION_REASON), + 'from addBidResponse hooks': () => cbs.addBidResponse(AU_CODE, deepClone(bid)) + }).forEach(([t, rejectBid]) => { + describe(t, () => { + it('should emit a BID_REJECTED event', () => { + rejectBid(); + sinon.assert.calledWith(onBidRejected, expectedRejection); + }); + + it('should pass bid to auction.addBidRejected', () => { + rejectBid(); + sinon.assert.calledWith(auction.addBidRejected, expectedRejection); + }); + }) + }); + + it('should return a NO_BID replacement', () => { + const noBid = cbs.addBidResponse.reject(AU_CODE, {...bid, statusMessage: 'Bid available', status: CONSTANTS.BID_STATUS.RENDERED}, 'Rejected'); + sinon.assert.match(noBid, { + status: CONSTANTS.BID_STATUS.BID_REJECTED, + statusMessage: 'Bid returned empty or error response', + cpm: 0, + requestId: bid.requestId, + auctionId: bid.auctionId, + adUnitCode: AU_CODE, + rejectionReason: undefined, + }); + }); + + it('addBidResponse hooks should not be able to reject the same bid twice', () => { + cbs.addBidResponse(AU_CODE, bid); + expect(auction.addBidRejected.calledOnce).to.be.true; + }); + }) }); describe('auctionOptions', function() { diff --git a/test/spec/modules/currency_spec.js b/test/spec/modules/currency_spec.js index 6eb4f929a42..b674cb5976d 100644 --- a/test/spec/modules/currency_spec.js +++ b/test/spec/modules/currency_spec.js @@ -351,6 +351,11 @@ describe('currency', function () { }); describe('currency.addBidResponseDecorator', function () { + let reject; + beforeEach(() => { + reject = sinon.stub().returns({status: 'rejected'}); + }); + it('should leave bid at 1 when currency support is not enabled and fromCurrency is USD', function () { setConfig({}); var bid = makeBid({ 'cpm': 1, 'currency': 'USD' }); @@ -368,8 +373,9 @@ describe('currency', function () { var innerBid; addBidResponseHook(function(adCodeId, bid) { innerBid = bid; - }, 'elementId', bid); - expect(innerBid.statusMessage).to.equal('Bid returned empty or error response'); + }, 'elementId', bid, reject); + expect(innerBid.status).to.equal('rejected'); + expect(reject.calledOnce).to.be.true; }); it('should not buffer bid when currency is already in desired currency', function () { @@ -395,8 +401,9 @@ describe('currency', function () { var innerBid; addBidResponseHook(function(adCodeId, bid) { innerBid = bid; - }, 'elementId', bid); - expect(innerBid.statusMessage).to.equal('Bid returned empty or error response'); + }, 'elementId', bid, reject); + expect(innerBid.status).to.equal('rejected'); + expect(reject.calledOnce).to.be.true; }); it('should result in NO_BID when adServerCurrency is not supported in file', function () { @@ -407,8 +414,9 @@ describe('currency', function () { var innerBid; addBidResponseHook(function(adCodeId, bid) { innerBid = bid; - }, 'elementId', bid); - expect(innerBid.statusMessage).to.equal('Bid returned empty or error response'); + }, 'elementId', bid, reject); + expect(innerBid.status).to.equal('rejected'); + expect(reject.calledOnce).to.be.true; }); it('should return 1 when currency support is enabled and same currency code is requested as is set to adServerCurrency', function () { diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index c3ca3261193..b5209e5be12 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -536,6 +536,8 @@ describe('S2S Adapter', function () { addBidResponse = sinon.spy(), done = sinon.spy(); + addBidResponse.reject = sinon.spy(); + function prepRequest(req) { req.ad_units.forEach((adUnit) => { delete adUnit.nativeParams @@ -595,6 +597,7 @@ describe('S2S Adapter', function () { afterEach(function () { addBidResponse.resetHistory(); + addBidResponse.reject = sinon.spy(); done.resetHistory(); }); @@ -2903,6 +2906,16 @@ describe('S2S Adapter', function () { }); } + it('should reject invalid bids', () => { + config.setConfig({ s2sConfig: CONFIG }); + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + const response = deepClone(RESPONSE_OPENRTB); + Object.assign(response.seatbid[0].bid[0], {w: null, h: null}); + server.requests[0].respond(200, {}, JSON.stringify(response)); + expect(addBidResponse.reject.calledOnce).to.be.true; + expect(addBidResponse.called).to.be.false; + }); + it('does not (by default) allow bids that were not requested', function () { config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); @@ -2911,6 +2924,7 @@ describe('S2S Adapter', function () { server.requests[0].respond(200, {}, JSON.stringify(response)); expect(addBidResponse.called).to.be.false; + expect(addBidResponse.reject.calledOnce).to.be.true; }); it('allows unrequested bids if config.allowUnknownBidderCodes', function () { @@ -2924,17 +2938,35 @@ describe('S2S Adapter', function () { expect(addBidResponse.calledWith(sinon.match.any, sinon.match({ bidderCode: 'unknown' }))).to.be.true; }); - it('uses "null" request\'s ID for all responses, when a null request is present', function () { - const cfg = {...CONFIG, allowUnknownBidderCodes: true}; - config.setConfig({s2sConfig: cfg}); - const req = {...REQUEST, s2sConfig: cfg, ad_units: [{...REQUEST.ad_units[0], bids: [{bidder: null, bid_id: 'testId'}]}]}; - const bidReq = {...BID_REQUESTS[0], bidderCode: null, bids: [{...BID_REQUESTS[0].bids[0], bidder: null, bidId: 'testId'}]} - adapter.callBids(req, [bidReq], addBidResponse, done, ajax); - const response = deepClone(RESPONSE_OPENRTB); - response.seatbid[0].seat = 'storedImpression'; - server.requests[0].respond(200, {}, JSON.stringify(response)); - sinon.assert.calledWith(addBidResponse, sinon.match.any, sinon.match({bidderCode: 'storedImpression', requestId: 'testId'})) - }); + describe('stored impressions', () => { + let bidReq, response; + + function mks2sReq(s2sConfig = CONFIG) { + return {...REQUEST, s2sConfig, ad_units: [{...REQUEST.ad_units[0], bids: [{bidder: null, bid_id: 'testId'}]}]}; + } + + beforeEach(() => { + bidReq = {...BID_REQUESTS[0], bidderCode: null, bids: [{...BID_REQUESTS[0].bids[0], bidder: null, bidId: 'testId'}]} + response = deepClone(RESPONSE_OPENRTB); + response.seatbid[0].seat = 'storedImpression'; + }) + + it('uses "null" request\'s ID for all responses, when a null request is present', function () { + const cfg = {...CONFIG, allowUnknownBidderCodes: true}; + config.setConfig({s2sConfig: cfg}); + adapter.callBids(mks2sReq(cfg), [bidReq], addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(response)); + sinon.assert.calledWith(addBidResponse, sinon.match.any, sinon.match({bidderCode: 'storedImpression', requestId: 'testId'})) + }); + + it('does not allow null requests (= stored impressions) if allowUnknownBidderCodes is not set', () => { + config.setConfig({s2sConfig: CONFIG}); + adapter.callBids(mks2sReq(), [bidReq], addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(response)); + expect(addBidResponse.called).to.be.false; + expect(addBidResponse.reject.calledOnce).to.be.true; + }); + }) it('copies ortb2Imp to response when there is only a null bid', () => { const cfg = {...CONFIG}; diff --git a/test/spec/modules/priceFloors_spec.js b/test/spec/modules/priceFloors_spec.js index cbdd4d179e3..b7d771814d0 100644 --- a/test/spec/modules/priceFloors_spec.js +++ b/test/spec/modules/priceFloors_spec.js @@ -1665,7 +1665,7 @@ describe('the price floors module', function () { }); describe('bidResponseHook tests', function () { const AUCTION_ID = '123456'; - let returnedBidResponse, indexStub; + let returnedBidResponse, indexStub, reject; let adUnit = { transactionId: 'au', code: 'test_div_1' @@ -1681,6 +1681,7 @@ describe('the price floors module', function () { }; beforeEach(function () { returnedBidResponse = {}; + reject = sinon.stub().returns({status: 'rejected'}); indexStub = sinon.stub(auctionManager, 'index'); indexStub.get(() => stubAuctionIndex({adUnits: [adUnit]})); }); @@ -1693,7 +1694,7 @@ describe('the price floors module', function () { let next = (adUnitCode, bid) => { returnedBidResponse = bid; }; - addBidResponseHook(next, bidResp.adUnitCode, Object.assign(createBid(CONSTANTS.STATUS.GOOD, {auctionId: AUCTION_ID}), bidResp)); + addBidResponseHook(next, bidResp.adUnitCode, Object.assign(createBid(CONSTANTS.STATUS.GOOD, {auctionId: AUCTION_ID}), bidResp), reject); }; it('continues with the auction if not floors data is present without any flooring', function () { runBidResponse(); @@ -1710,9 +1711,8 @@ describe('the price floors module', function () { _floorDataForAuction[AUCTION_ID] = utils.deepClone(basicFloorConfig); _floorDataForAuction[AUCTION_ID].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); + expect(reject.calledOnce).to.be.true; + expect(returnedBidResponse.status).to.equal('rejected'); }); it('if it finds a rule and does not floor should update the bid accordingly', function () { _floorDataForAuction[AUCTION_ID] = utils.deepClone(basicFloorConfig); diff --git a/test/spec/unit/core/bidderFactory_spec.js b/test/spec/unit/core/bidderFactory_spec.js index 7164e468e71..fa6cf7e6bb5 100644 --- a/test/spec/unit/core/bidderFactory_spec.js +++ b/test/spec/unit/core/bidderFactory_spec.js @@ -1,4 +1,4 @@ -import { newBidder, registerBidder, preloadBidderMappingFile, storage } from 'src/adapters/bidderFactory.js'; +import {newBidder, registerBidder, preloadBidderMappingFile, storage, isValid} from 'src/adapters/bidderFactory.js'; import adapterManager from 'src/adapterManager.js'; import * as ajax from 'src/ajax.js'; import { expect } from 'chai'; @@ -62,6 +62,7 @@ describe('bidders created by newBidder', function () { }; addBidResponseStub = sinon.stub(); + addBidResponseStub.reject = sinon.stub(); doneStub = sinon.stub(); }); @@ -508,7 +509,7 @@ describe('bidders created by newBidder', function () { expect(userSyncStub.firstCall.args[2]).to.equal('usersync.com'); }); - it('should logError when required bid response params are missing', function () { + it('should logError and reject bid when required bid response params are missing', function () { const bidder = newBidder(spec); const bid = { @@ -532,9 +533,10 @@ describe('bidders created by newBidder', function () { bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); expect(logErrorSpy.calledOnce).to.equal(true); + expect(addBidResponseStub.reject.calledOnce).to.be.true; }); - it('should logError when required bid response params are undefined', function () { + it('should logError and reject bid when required response params are undefined', function () { const bidder = newBidder(spec); const bid = { @@ -562,6 +564,7 @@ describe('bidders created by newBidder', function () { bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); expect(logErrorSpy.calledOnce).to.equal(true); + expect(addBidResponseStub.reject.calledOnce).to.be.true; }); it('should require requestId from interpretResponse', () => { @@ -586,6 +589,7 @@ describe('bidders created by newBidder', function () { bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); expect(addBidResponseStub.called).to.be.false; + expect(addBidResponseStub.reject.calledOnce).to.be.true; }); }); @@ -856,6 +860,7 @@ describe('validate bid response: ', function () { }); addBidResponseStub = sinon.stub(); + addBidResponseStub.reject = sinon.stub(); doneStub = sinon.stub(); ajaxStub = sinon.stub(ajax, 'ajax').callsFake(function(url, callbacks) { const fakeResponse = sinon.stub(); @@ -954,7 +959,8 @@ describe('validate bid response: ', function () { spec.interpretResponse.returns(bids1); bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); - expect(addBidResponseStub.calledOnce).to.equal(false); + expect(addBidResponseStub.called).to.equal(false); + expect(addBidResponseStub.reject.calledOnce).to.be.true; expect(logErrorSpy.calledWithMatch('Ignoring bid: Native bid missing some required properties.')).to.equal(true); }); } @@ -1074,7 +1080,8 @@ describe('validate bid response: ', function () { spec.interpretResponse.returns(bids1); bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); - expect(addBidResponseStub.calledOnce).to.equal(false); + expect(addBidResponseStub.called).to.equal(false); + expect(addBidResponseStub.reject.calledOnce).to.be.true; expect(logWarnSpy.callCount).to.equal(1); }); @@ -1085,7 +1092,8 @@ describe('validate bid response: ', function () { spec.interpretResponse.returns(bids1); bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); - expect(addBidResponseStub.calledOnce).to.equal(false); + expect(addBidResponseStub.called).to.equal(false); + expect(addBidResponseStub.reject.calledOnce).to.be.true; }); it('should log warning when the particular bidder is not specified in allowedAlternateBidderCodes and allowAlternateBidderCodes flag is true', function () { @@ -1096,7 +1104,8 @@ describe('validate bid response: ', function () { spec.interpretResponse.returns(bids1); bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); - expect(addBidResponseStub.calledOnce).to.equal(false); + expect(addBidResponseStub.called).to.equal(false); + expect(addBidResponseStub.reject.calledOnce).to.be.true; expect(logWarnSpy.callCount).to.equal(1); }); @@ -1147,7 +1156,8 @@ describe('validate bid response: ', function () { spec.interpretResponse.returns(bids1); bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); - expect(addBidResponseStub.calledOnce).to.equal(false); + expect(addBidResponseStub.called).to.equal(false); + expect(addBidResponseStub.reject.calledOnce).to.be.true; expect(logWarnSpy.callCount).to.equal(1); }); @@ -1159,7 +1169,7 @@ describe('validate bid response: ', function () { spec.interpretResponse.returns(bids1); bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); - expect(addBidResponseStub.calledOnce).to.equal(true); + expect(addBidResponseStub.called).to.equal(true); expect(logWarnSpy.callCount).to.equal(0); expect(logErrorSpy.callCount).to.equal(0); }); @@ -1172,8 +1182,9 @@ describe('validate bid response: ', function () { spec.interpretResponse.returns(bids1); bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); - expect(addBidResponseStub.calledOnce).to.equal(false); + expect(addBidResponseStub.called).to.equal(false); expect(logWarnSpy.callCount).to.equal(1); + expect(addBidResponseStub.reject.calledOnce).to.be.true; }); it('should not accept the bid, when bidderSetting is missing for the bidder. It should fallback to standard setting and reject the bid', function () { @@ -1183,7 +1194,8 @@ describe('validate bid response: ', function () { spec.interpretResponse.returns(bids1); bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); - expect(addBidResponseStub.calledOnce).to.equal(false); + expect(addBidResponseStub.called).to.equal(false); + expect(addBidResponseStub.reject.calledOnce).to.be.true; expect(logWarnSpy.callCount).to.equal(1); }); }); @@ -1385,3 +1397,46 @@ describe('preload mapping url hook', function() { clock.restore(); }); }); + +describe('bid response isValid', () => { + describe('size check', () => { + let req, index; + + beforeEach(() => { + req = { + ...MOCK_BIDS_REQUEST.bids[0], + mediaTypes: { + banner: { + sizes: [[1, 2], [3, 4]] + } + } + } + }); + + function mkResponse(width, height) { + return { + requestId: req.bidId, + width, + height, + cpm: 1, + ttl: 60, + creativeId: '123', + netRevenue: true, + currency: 'USD', + mediaType: 'banner', + } + } + + function checkValid(bid) { + return isValid('au', bid, {index: stubAuctionIndex({bidRequests: [req]})}); + } + + it('should succeed when response has a size that was in request', () => { + expect(checkValid(mkResponse(3, 4))).to.be.true; + }); + + it('should fail when response has a size that was not in request', () => { + expect(checkValid(mkResponse(10, 11))).to.be.false; + }); + }) +}); diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js index 4585ddbfaaf..448f1b36e3a 100644 --- a/test/spec/unit/core/targeting_spec.js +++ b/test/spec/unit/core/targeting_spec.js @@ -6,8 +6,14 @@ import CONSTANTS from 'src/constants.json'; import { auctionManager } from 'src/auctionManager.js'; import * as utils from 'src/utils.js'; import {deepClone} from 'src/utils.js'; +import {createBid} from '../../../../src/bidfactory.js'; +import {hook} from '../../../../src/hook.js'; -const bid1 = { +function mkBid(bid, status = CONSTANTS.STATUS.GOOD) { + return Object.assign(createBid(status), bid); +} + +const sampleBid = { 'bidderCode': 'rubicon', 'width': '300', 'height': '250', @@ -39,7 +45,9 @@ const bid1 = { 'ttl': 300 }; -const bid2 = { +const bid1 = mkBid(sampleBid); + +const bid2 = mkBid({ 'bidderCode': 'rubicon', 'width': '300', 'height': '250', @@ -67,9 +75,9 @@ const bid2 = { 'netRevenue': true, 'currency': 'USD', 'ttl': 300 -}; +}); -const bid3 = { +const bid3 = mkBid({ 'bidderCode': 'rubicon', 'width': '300', 'height': '600', @@ -97,9 +105,9 @@ const bid3 = { 'netRevenue': true, 'currency': 'USD', 'ttl': 300 -}; +}); -const nativeBid1 = { +const nativeBid1 = mkBid({ 'bidderCode': 'appnexus', 'width': 0, 'height': 0, @@ -165,8 +173,9 @@ const nativeBid1 = { [CONSTANTS.NATIVE_KEYS.image]: 'http://vcdn.adnxs.com/p/creative-image/94/22/cd/0f/9422cd0f-f400-45d3-80f5-2b92629d9257.jpg', [CONSTANTS.NATIVE_KEYS.icon]: 'http://vcdn.adnxs.com/p/creative-image/bd/59/a6/c6/bd59a6c6-0851-411d-a16d-031475a51312.png' } -}; -const nativeBid2 = { +}); + +const nativeBid2 = mkBid({ 'bidderCode': 'dgads', 'width': 0, 'height': 0, @@ -222,7 +231,7 @@ const nativeBid2 = { [CONSTANTS.NATIVE_KEYS.sponsoredBy]: 'test.com', [CONSTANTS.NATIVE_KEYS.clickUrl]: 'http://prebid.org/' } -}; +}); describe('targeting tests', function () { let sandbox; @@ -231,6 +240,10 @@ describe('targeting tests', function () { let bidCacheFilterFunction; let undef; + before(() => { + hook.ready(); + }); + beforeEach(function() { sandbox = sinon.sandbox.create(); @@ -287,6 +300,12 @@ describe('targeting tests', function () { bidExpiryStub.restore(); }); + it('should filter out NO_BID bids', () => { + bidsReceived = [mkBid(sampleBid, CONSTANTS.STATUS.NO_BID)]; + const tg = targetingInstance.getAllTargeting(); + expect(tg[bidsReceived[0].adUnitCode]).to.eql({}); + }); + describe('when handling different adunit targeting value types', function () { const adUnitCode = '/123456/header-bid-tag-0'; const adServerTargeting = {}; diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 6757ef42094..aac36ee76a1 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -200,6 +200,7 @@ describe('Unit: Prebid Module', function () { hook.ready(); $$PREBID_GLOBAL$$.requestBids.getHooks().remove(); resetDebugging(); + sinon.stub(filters, 'isActualBid').returns(true); // stub this out so that we can use vanilla objects as bids }); beforeEach(function () { @@ -216,6 +217,7 @@ describe('Unit: Prebid Module', function () { after(function() { auctionManager.clearAllAuctions(); + filters.isActualBid.restore(); }); describe('and global adUnits', () => { @@ -504,8 +506,8 @@ describe('Unit: Prebid Module', function () { 'client_initiated_ad_counting': true, 'rtb': { 'banner': { - 'width': 728, - 'height': 90, + 'width': 300, + 'height': 250, 'content': '' }, 'trackers': [{ From 31522176dda74a1e962f192af6a30defc071808c Mon Sep 17 00:00:00 2001 From: jsnellbaker <31102355+jsnellbaker@users.noreply.github.com> Date: Wed, 12 Oct 2022 09:20:02 -0400 Subject: [PATCH 007/367] Appnexus Bid Adapter: add support for debug params via query string (#9091) * appnexus bid adapter - add support for debug params via query string * add unit test and some updates --- modules/appnexusBidAdapter.js | 21 +++++++++++++++-- test/spec/modules/appnexusBidAdapter_spec.js | 24 ++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index 7b59ce4ee3b..cabbb448960 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -11,6 +11,7 @@ import { getMinValueFromArray, getParameterByName, getUniqueIdentifierStr, + getWindowFromDocument, isArray, isArrayOfNums, isEmpty, @@ -23,8 +24,7 @@ import { logMessage, logWarn, mergeDeep, - transformBidderParamKeywords, - getWindowFromDocument + transformBidderParamKeywords } from '../src/utils.js'; import {Renderer} from '../src/Renderer.js'; import {config} from '../src/config.js'; @@ -47,6 +47,11 @@ const VIDEO_RTB_TARGETING = ['minduration', 'maxduration', 'skip', 'skipafter', const USER_PARAMS = ['age', 'externalUid', 'segments', 'gender', 'dnt', 'language']; const APP_DEVICE_PARAMS = ['geo', 'device_id']; // appid is collected separately const DEBUG_PARAMS = ['enabled', 'dongle', 'member_id', 'debug_timeout']; +const DEBUG_QUERY_PARAM_MAP = { + 'apn_debug_dongle': 'dongle', + 'apn_debug_member_id': 'member_id', + 'apn_debug_timeout': 'debug_timeout' +}; const VIDEO_MAPPING = { playback_method: { 'unknown': 0, @@ -184,6 +189,18 @@ export const spec = { logError('AppNexus Debug Auction Cookie Error:\n\n' + e); } } else { + Object.keys(DEBUG_QUERY_PARAM_MAP).forEach(qparam => { + let qval = getParameterByName(qparam); + if (isStr(qval) && qval !== '') { + debugObj[DEBUG_QUERY_PARAM_MAP[qparam]] = qval; + debugObj.enabled = true; + } + }); + debugObj = convertTypes({ + 'member_id': 'number', + 'debug_timeout': 'number' + }, debugObj); + const debugBidRequest = find(bidRequests, hasDebug); if (debugBidRequest && debugBidRequest.debug) { debugObj = debugBidRequest.debug; diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index 87a4a0fbe2d..5cd189da9a1 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -4,6 +4,7 @@ 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 * as utils from 'src/utils.js'; import { config } from 'src/config.js'; const ENDPOINT = 'https://ib.adnxs.com/ut/v3/prebid'; @@ -370,6 +371,29 @@ describe('AppNexusAdapter', function () { }); }); + it('should add debug params from query', function () { + let getParamStub = sinon.stub(utils, 'getParameterByName').callsFake(function(par) { + if (par === 'apn_debug_dongle') return 'abcdef'; + if (par === 'apn_debug_member_id') return '1234'; + if (par === 'apn_debug_timeout') return '1000'; + + return ''; + }); + + let bidRequest = deepClone(bidRequests[0]); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.debug).to.exist.and.to.deep.equal({ + 'dongle': 'abcdef', + 'enabled': true, + 'member_id': 1234, + 'debug_timeout': 1000 + }); + + getParamStub.restore(); + }); + it('should attach reserve param when either bid param or getFloor function exists', function () { let getFloorResponse = { currency: 'USD', floor: 3 }; let request, payload = null; From 50f6d12a97d9b63f04deea3cc3ff9a23280e88b0 Mon Sep 17 00:00:00 2001 From: shakhaltb <108469576+shakhaltb@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:11:31 +0300 Subject: [PATCH 008/367] Taboola Bid Adapter: fix multiple impressions bug (#9104) * create taboola adapter * create taboola adapter md * taboolaBidAdapter.js - small fixes taboolaBidAdapter_spec.js - new UT * taboolaBidAdapter.js - small fixes taboolaBidAdapter_spec.js - new UT * update the md * update the Maintainer email * * update MD page * refactor code for better readability * small fix in UT * * add privacy to the request builder * add relevant Ut * small fixes in UT * * code refactoring + add more accurate way to get page url and referer * add relevant Ut * small fixes in md * * code refactoring + gte user id * add relevant Ut * small fixes * * code refactoring + gte user id * add relevant Ut * small fixes * * update end point url * update UT * Update banner End point structure * small fixes + update epi url * remove the destruction from the bidResponse property * (update the unit tests) remove the destruction from the bidResponse property * fix tests * fix tests - run stubs on each test * rerun because of another adapter flaky test * rerun because of another adapter flaky test * fix cors issue, switch between height, width position * update badv, bcat to be based in the ortb2 to support prebid 7 new protocols + update Ut * retry run circleci * retry run circleci * pull from upstream update md (placement + pub ) * update badv, bcat UT * rerun build * rerun build * support storageAllowed restriction on unit tests for prebid 7 * create taboola adapter * create taboola adapter md * taboolaBidAdapter.js - small fixes taboolaBidAdapter_spec.js - new UT * taboolaBidAdapter.js - small fixes taboolaBidAdapter_spec.js - new UT * update the md * update the Maintainer email * * update MD page * refactor code for better readability * small fix in UT * * add privacy to the request builder * add relevant Ut * small fixes in UT * * code refactoring + add more accurate way to get page url and referer * add relevant Ut * small fixes in md * * code refactoring + gte user id * add relevant Ut * small fixes * * code refactoring + gte user id * add relevant Ut * small fixes * * update end point url * update UT * Update banner End point structure * small fixes + update epi url * remove the destruction from the bidResponse property * (update the unit tests) remove the destruction from the bidResponse property * fix tests * fix tests - run stubs on each test * rerun because of another adapter flaky test * rerun because of another adapter flaky test * fix cors issue, switch between height, width position * update badv, bcat to be based in the ortb2 to support prebid 7 new protocols + update Ut * retry run circleci * retry run circleci * pull from upstream update md (placement + pub ) * update badv, bcat UT * rerun build * rerun build * support storageAllowed restriction on unit tests for prebid 7 * support storageAllowed restriction on unit tests for prebid 7 * add it also to the aftereach * add it also to the aftereach * change the api endpoint https protocol * update Taboola prebid documentation: tagId, publisherId, bidFloor. * update bid response ttl to 60 seconds. * update Taboola prebid documentation. * update-ttl-passing * Update taboolaBidAdapter_spec.js * add fallback default value in case of null * add semicolons * . * . * . * .. * ... * support-dynamic-endpoint-url * support-dynamic-endpoint-url * support-dynamic-endpoint-url * support-dynamic-endpoint-url * support-dynamic-endpoint-url * support-dynamic-endpoint-url * support-dynamic-endpoint-url * optional-chaining * set netRevenue to true. * fix bid response in case we have multiple impressions * add test * fix lint Co-authored-by: Michael Co-authored-by: mikiz <31058500+mikizi@users.noreply.github.com> Co-authored-by: jenny.l Co-authored-by: jennylt <48404417+jennylt@users.noreply.github.com> Co-authored-by: Ahmad Lobany Co-authored-by: ahmadlob <109217988+ahmadlob@users.noreply.github.com> --- modules/taboolaBidAdapter.js | 8 +- test/spec/modules/taboolaBidAdapter_spec.js | 121 ++++++++++++++++++-- 2 files changed, 114 insertions(+), 15 deletions(-) diff --git a/modules/taboolaBidAdapter.js b/modules/taboolaBidAdapter.js index 13f04848dd6..d4bf6623f9b 100644 --- a/modules/taboolaBidAdapter.js +++ b/modules/taboolaBidAdapter.js @@ -147,7 +147,7 @@ export const spec = { return []; } - return bids.map((bid, id) => getBid(bid.bidId, currency, bidResponses[id])).filter(Boolean); + return bidResponses.map((bidResponse) => getBid(bids, currency, bidResponse)).filter(Boolean); }, }; @@ -204,7 +204,7 @@ function getBidResponses({body}) { const {seatbid, cur} = body; - if (!seatbid.length || !seatbid[0].bid) { + if (!seatbid.length || !seatbid[0].bid || !seatbid[0].bid.length) { return []; } @@ -214,14 +214,14 @@ function getBidResponses({body}) { }; } -function getBid(requestId, currency, bidResponse) { +function getBid(bids, currency, bidResponse) { if (!bidResponse) { return; } const { price: cpm, crid: creativeId, adm: ad, w: width, h: height, exp: ttl, adomain: advertiserDomains, meta = {} } = bidResponse; - + let requestId = bids[bidResponse.impid - 1].bidId; if (advertiserDomains && advertiserDomains.length > 0) { meta.advertiserDomains = advertiserDomains } diff --git a/test/spec/modules/taboolaBidAdapter_spec.js b/test/spec/modules/taboolaBidAdapter_spec.js index b41a17a8e0a..9af11363957 100644 --- a/test/spec/modules/taboolaBidAdapter_spec.js +++ b/test/spec/modules/taboolaBidAdapter_spec.js @@ -4,7 +4,7 @@ import {config} from '../../../src/config' import * as utils from '../../../src/utils' describe('Taboola Adapter', function () { - let hasLocalStorage, cookiesAreEnabled, getDataFromLocalStorage, localStorageIsEnabled, getCookie; + let hasLocalStorage, cookiesAreEnabled, getDataFromLocalStorage, localStorageIsEnabled, getCookie, commonBidRequest; beforeEach(() => { hasLocalStorage = sinon.stub(userData.storageManager, 'hasLocalStorage'); @@ -12,7 +12,7 @@ describe('Taboola Adapter', function () { getCookie = sinon.stub(userData.storageManager, 'getCookie'); getDataFromLocalStorage = sinon.stub(userData.storageManager, 'getDataFromLocalStorage'); localStorageIsEnabled = sinon.stub(userData.storageManager, 'localStorageIsEnabled'); - + commonBidRequest = createBidRequest(); $$PREBID_GLOBAL$$.bidderSettings = { taboola: { storageAllowed: true @@ -30,19 +30,19 @@ describe('Taboola Adapter', function () { $$PREBID_GLOBAL$$.bidderSettings = {}; }) - const commonBidRequest = { + const displayBidRequestParams = { + sizes: [[300, 250], [300, 600]] + } + + const createBidRequest = () => ({ bidder: 'taboola', params: { publisherId: 'publisherId', tagId: 'placement name' }, - bidId: 'aa43860a-4644-442a-b5e0-93f268cs4d19', - auctionId: '65746dca-26f3-4186-be13-dfa63469b1b7', - } - - const displayBidRequestParams = { - sizes: [[300, 250], [300, 600]] - } + bidId: utils.generateUUID(), + auctionId: utils.generateUUID(), + }); describe('isBidRequestValid', function () { it('should fail when bid is invalid - tagId isn`t defined', function () { @@ -132,7 +132,7 @@ describe('Taboola Adapter', function () { describe('buildRequests', function () { const defaultBidRequest = { - ...commonBidRequest, + ...createBidRequest(), ...displayBidRequestParams, } @@ -441,6 +441,105 @@ describe('Taboola Adapter', function () { overriddenServerResponse.body.seatbid[0].bid = bid; }); + it('should interpret multi impression request', function () { + const multiRequest = { + bids: [ + { + ...createBidRequest(), + ...displayBidRequestParams + }, + { + ...createBidRequest(), + ...displayBidRequestParams + } + ] + } + + const multiServerResponse = { + body: { + 'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15', + 'seatbid': [ + { + 'bid': [ + { + 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c', + 'impid': '2', + 'price': 0.342068, + 'adid': '2785119545551083381', + 'adm': 'ADM2', + 'adomain': [ + 'example.xyz' + ], + 'cid': '15744349', + 'crid': '278195503434041083381', + 'w': 300, + 'h': 250, + 'exp': 60, + 'lurl': 'http://us-trc.taboola.com/sample' + }, + { + 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c', + 'impid': '1', + 'price': 0.342068, + 'adid': '2785119545551083381', + 'adm': 'ADM1', + 'adomain': [ + 'example.xyz' + ], + 'cid': '15744349', + 'crid': '278195503434041083381', + 'w': 300, + 'h': 250, + 'exp': 60, + 'lurl': 'http://us-trc.taboola.com/sample' + } + ], + 'seat': '14204545260' + } + ], + 'bidid': 'da43860a-4644-442a-b5e0-93f268cf8d19', + 'cur': 'USD' + } + }; + + const [bid] = multiServerResponse.body.seatbid[0].bid; + const expectedRes = [ + { + requestId: multiRequest.bids[1].bidId, + cpm: bid.price, + creativeId: bid.crid, + ttl: 60, + netRevenue: true, + currency: multiServerResponse.body.cur, + mediaType: 'banner', + ad: multiServerResponse.body.seatbid[0].bid[0].adm, + width: bid.w, + height: bid.h, + meta: { + 'advertiserDomains': bid.adomain + }, + }, + { + requestId: multiRequest.bids[0].bidId, + cpm: bid.price, + creativeId: bid.crid, + ttl: 60, + netRevenue: true, + currency: multiServerResponse.body.cur, + mediaType: 'banner', + ad: multiServerResponse.body.seatbid[0].bid[1].adm, + width: bid.w, + height: bid.h, + meta: { + 'advertiserDomains': bid.adomain + }, + } + ] + + const res = spec.interpretResponse(multiServerResponse, multiRequest) + expect(res).to.deep.equal(expectedRes) + }); + it('should interpret display response', function () { const [bid] = serverResponse.body.seatbid[0].bid; const expectedRes = [ From c0f8bc9248435398809a675b11f6ef556101c7d7 Mon Sep 17 00:00:00 2001 From: Robert Ray Martinez III Date: Wed, 12 Oct 2022 12:08:16 -0700 Subject: [PATCH 009/367] Magnite Analytics Adapter: New Adapter (#9068) * stash * mgni analytics done? * test not finished * remove log * get rid of console log * pass render transaction id * add bid Id * fix bidder done * fix tests * Handle PPI elementids case * added lots of test + minor fixes * implement Michele review comments fix clashing rubicon configs in tests * michele fixes * sometimes bidWons do not have "bidId" so use "requestId" * add logs so we can debug on page * handle currency conversion errors better * bug fixes * time since page load * Magnite MD * Move session to auction init * Change adUnitMap to transactionId Add delay processing to Bid Won * oops --- modules/magniteAnalyticsAdapter.js | 902 ++++++++ modules/magniteAnalyticsAdapter.md | 18 + modules/rubiconAnalyticsAdapter.js | 23 +- .../modules/magniteAnalyticsAdapter_spec.js | 1942 +++++++++++++++++ .../modules/rubiconAnalyticsAdapter_spec.js | 5 +- 5 files changed, 2878 insertions(+), 12 deletions(-) create mode 100644 modules/magniteAnalyticsAdapter.js create mode 100644 modules/magniteAnalyticsAdapter.md create mode 100644 test/spec/modules/magniteAnalyticsAdapter_spec.js diff --git a/modules/magniteAnalyticsAdapter.js b/modules/magniteAnalyticsAdapter.js new file mode 100644 index 00000000000..dba847e1b07 --- /dev/null +++ b/modules/magniteAnalyticsAdapter.js @@ -0,0 +1,902 @@ +import { generateUUID, mergeDeep, deepAccess, parseUrl, logError, pick, isEmpty, logWarn, debugTurnedOn, parseQS, getWindowLocation, isAdUnitCodeMatchingSlot, isNumber, deepSetValue, deepClone, logInfo, isGptPubadsDefined } from '../src/utils.js'; +import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import CONSTANTS from '../src/constants.json'; +import { ajax } from '../src/ajax.js'; +import { config } from '../src/config.js'; +import { getGlobal } from '../src/prebidGlobal.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const RUBICON_GVL_ID = 52; +export const storage = getStorageManager({ gvlid: RUBICON_GVL_ID, moduleName: 'magnite' }); +const COOKIE_NAME = 'mgniSession'; +const LAST_SEEN_EXPIRE_TIME = 1800000; // 30 mins +const END_EXPIRE_TIME = 21600000; // 6 hours +const MODULE_NAME = 'Magnite Analytics'; +const BID_REJECTED_IPF = 'rejected-ipf'; + +// List of known rubicon aliases +// This gets updated on auction init to account for any custom aliases present +let rubiconAliases = ['rubicon']; + +const pbsErrorMap = { + 1: 'timeout-error', + 2: 'input-error', + 3: 'connect-error', + 4: 'request-error', + 999: 'generic-error' +} + +let prebidGlobal = getGlobal(); +const { + EVENTS: { + AUCTION_INIT, + AUCTION_END, + BID_REQUESTED, + BID_RESPONSE, + BIDDER_DONE, + BID_TIMEOUT, + BID_WON, + BILLABLE_EVENT + }, + STATUS: { + GOOD, + NO_BID + }, + BID_STATUS: { + BID_REJECTED + } +} = CONSTANTS; + +// The saved state of rubicon specific setConfig controls +export let rubiConf; +// Saving state of all our data we want +let cache; +const resetConfs = () => { + cache = { + auctions: {}, + auctionOrder: [], + timeouts: {}, + billing: {}, + pendingEvents: {}, + eventPending: false, + elementIdMap: {}, + sessionData: {} + } + rubiConf = { + pvid: generateUUID().slice(0, 8), + analyticsEventDelay: 500, + analyticsBatchTimeout: 5000, + analyticsProcessDelay: 1, + dmBilling: { + enabled: false, + vendors: [], + waitForAuction: true + } + } +} +resetConfs(); + +config.getConfig('rubicon', config => { + mergeDeep(rubiConf, config.rubicon); + if (deepAccess(config, 'rubicon.updatePageView') === true) { + rubiConf.pvid = generateUUID().slice(0, 8) + } +}); + +// pbs confs +let serverConfig; +config.getConfig('s2sConfig', ({ s2sConfig }) => { + serverConfig = s2sConfig; +}); + +const DEFAULT_INTEGRATION = 'pbjs'; + +const adUnitIsOnlyInstream = adUnit => { + return adUnit.mediaTypes && Object.keys(adUnit.mediaTypes).length === 1 && deepAccess(adUnit, 'mediaTypes.video.context') === 'instream'; +} + +const sendPendingEvents = () => { + cache.pendingEvents.trigger = `batched-${Object.keys(cache.pendingEvents).sort().join('-')}`; + sendEvent(cache.pendingEvents); + cache.pendingEvents = {}; + cache.eventPending = false; +} + +const addEventToQueue = (event, auctionId, eventName) => { + // If it's auction has not left yet, add it there + if (cache.auctions[auctionId] && !cache.auctions[auctionId].sent) { + cache.auctions[auctionId].pendingEvents = mergeDeep(cache.auctions[auctionId].pendingEvents, event); + } else if (rubiConf.analyticsEventDelay > 0) { + // else if we are trying to batch stuff up, add it to pending events to be fired + cache.pendingEvents = mergeDeep(cache.pendingEvents, event); + + // If no event is pending yet, start a timer for them to be sent and attempted to be gathered together + if (!cache.eventPending) { + setTimeout(sendPendingEvents, rubiConf.analyticsEventDelay); + cache.eventPending = true; + } + } else { + // else - send it solo + event.trigger = `solo-${eventName}`; + sendEvent(event); + } +} + +const sendEvent = payload => { + const event = { + ...getTopLevelDetails(), + ...payload + } + ajax( + endpoint, + null, + JSON.stringify(event), + { + contentType: 'application/json' + } + ); +} + +const sendAuctionEvent = (auctionId, trigger) => { + let auctionCache = cache.auctions[auctionId]; + const auctionEvent = formatAuction(auctionCache.auction); + + auctionCache.sent = true; + sendEvent({ + auctions: [auctionEvent], + ...(auctionCache.pendingEvents || {}), // if any pending events were attached + trigger + }); +} + +const formatAuction = auction => { + const auctionEvent = deepClone(auction); + + auctionEvent.samplingFactor = 1; + + // We stored adUnits and bids as objects for quick lookups, now they are mapped into arrays for PBA + auctionEvent.adUnits = Object.entries(auctionEvent.adUnits).map(([tid, adUnit]) => { + adUnit.bids = Object.entries(adUnit.bids).map(([bidId, bid]) => { + // determine adUnit.status from its bid statuses. Use priority below to determine, higher index is better + let statusPriority = ['error', 'no-bid', 'success']; + if (statusPriority.indexOf(bid.status) > statusPriority.indexOf(adUnit.status)) { + adUnit.status = bid.status; + } + + // If PBS told us to overwrite the bid ID, do so + if (bid.pbsBidId) { + bid.oldBidId = bid.bidId; + bid.bidId = bid.pbsBidId; + delete bid.pbsBidId; + } + return bid; + }); + return adUnit; + }); + return auctionEvent; +} + +const isBillingEventValid = event => { + // vendor is whitelisted + const isWhitelistedVendor = rubiConf.dmBilling.vendors.includes(event.vendor); + // event is not duplicated + const isNotDuplicate = typeof deepAccess(cache.billing, `${event.vendor}.${event.billingId}`) !== 'boolean'; + // billingId is defined and a string + return typeof event.billingId === 'string' && isWhitelistedVendor && isNotDuplicate; +} + +const formatBillingEvent = event => { + let billingEvent = deepClone(event); + // Pass along type if is string and not empty else general + billingEvent.type = (typeof event.type === 'string' && event.type) || 'general'; + billingEvent.accountId = accountId; + // mark as sent + deepSetValue(cache.billing, `${event.vendor}.${event.billingId}`, true); + return billingEvent; +} + +const getBidPrice = bid => { + // get the cpm from bidResponse + let cpm; + let currency; + if (bid.status === BID_REJECTED && typeof deepAccess(bid, 'floorData.cpmAfterAdjustments') === 'number') { + // 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; + } + // 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(prebidGlobal.convertCurrency(cpm, currency, 'USD')); + } catch (err) { + logWarn(`${MODULE_NAME}: Could not determine the bidPriceUSD of the bid `, bid); + bid.conversionError = true; + bid.ogCurrency = currency; + bid.ogPrice = cpm; + return 0; + } +} + +export const parseBidResponse = (bid, previousBidResponse) => { + // The current bidResponse for this matching requestId/bidRequestId + let responsePrice = getBidPrice(bid) + // we need to compare it with the previous one (if there was one) log highest only + // THIS WILL CHANGE WITH ALLOWING MULTIBID BETTER + if (previousBidResponse && previousBidResponse.bidPriceUSD > responsePrice) { + return previousBidResponse; + } + + return pick(bid, [ + 'bidPriceUSD', () => responsePrice, + 'dealId', dealId => dealId || undefined, + 'mediaType', + 'dimensions', () => { + const width = bid.width || bid.playerWidth; + const height = bid.height || bid.playerHeight; + return (width && height) ? { width, height } : undefined; + }, + 'floorValue', () => deepAccess(bid, 'floorData.floorValue'), + 'floorRuleValue', () => deepAccess(bid, 'floorData.floorRuleValue'), + 'floorRule', () => debugTurnedOn() ? deepAccess(bid, 'floorData.floorRule') : undefined, + 'adomains', () => { + const adomains = deepAccess(bid, 'meta.advertiserDomains'); + const validAdomains = Array.isArray(adomains) && adomains.filter(domain => typeof domain === 'string'); + return validAdomains && validAdomains.length > 0 ? validAdomains.slice(0, 10) : undefined + }, + 'conversionError', conversionError => conversionError === true || undefined, // only pass if exactly true + 'ogCurrency', + 'ogPrice' + ]); +} + +const addFloorData = floorData => { + if (floorData.location === 'noData') { + return pick(floorData, [ + 'location', + 'fetchStatus', + 'floorProvider as provider' + ]); + } else { + return pick(floorData, [ + 'location', + 'modelVersion as modelName', + 'modelWeight', + 'modelTimestamp', + 'skipped', + 'enforcement', () => deepAccess(floorData, 'enforcements.enforceJS'), + 'dealsEnforced', () => deepAccess(floorData, 'enforcements.floorDeals'), + 'skipRate', + 'fetchStatus', + 'floorMin', + 'floorProvider as provider' + ]); + } +} + +let pageReferer; + +const getTopLevelDetails = () => { + let payload = { + channel: 'web', + integration: rubiConf.int_type || DEFAULT_INTEGRATION, + referrerUri: pageReferer, + version: '$prebid.version$', + referrerHostname: magniteAdapter.referrerHostname || getHostNameFromReferer(pageReferer), + timestamps: { + timeSincePageLoad: performance.now(), + eventTime: Date.now(), + prebidLoaded: magniteAdapter.MODULE_INITIALIZED_TIME + } + } + + // Add DM wrapper details + if (rubiConf.wrapperName) { + payload.wrapper = { + name: rubiConf.wrapperName, + family: rubiConf.wrapperFamily, + rule: rubiConf.rule_name + } + } + + if (cache.sessionData) { + // gather session info + payload.session = pick(cache.sessionData, [ + 'id', + 'pvid', + 'start', + 'expires' + ]); + // Any FPKVS set? + if (!isEmpty(cache.sessionData.fpkvs)) { + payload.fpkvs = Object.keys(cache.sessionData.fpkvs).map(key => { + return { key, value: cache.sessionData.fpkvs[key] }; + }); + } + } + return payload; +} + +export const getHostNameFromReferer = referer => { + try { + magniteAdapter.referrerHostname = parseUrl(referer, { noDecodeWholeURL: true }).hostname; + } catch (e) { + logError(`${MODULE_NAME}: Unable to parse hostname from supplied url: `, referer, e); + magniteAdapter.referrerHostname = ''; + } + return magniteAdapter.referrerHostname +}; + +const getRpaCookie = () => { + let encodedCookie = storage.getDataFromLocalStorage(COOKIE_NAME); + if (encodedCookie) { + try { + return JSON.parse(window.atob(encodedCookie)); + } catch (e) { + logError(`${MODULE_NAME}: Unable to decode ${COOKIE_NAME} value: `, e); + } + } + return {}; +} + +const setRpaCookie = (decodedCookie) => { + try { + storage.setDataInLocalStorage(COOKIE_NAME, window.btoa(JSON.stringify(decodedCookie))); + } catch (e) { + logError(`${MODULE_NAME}: Unable to encode ${COOKIE_NAME} value: `, e); + } +} + +const updateRpaCookie = () => { + const currentTime = Date.now(); + let decodedRpaCookie = getRpaCookie(); + if ( + !Object.keys(decodedRpaCookie).length || + (currentTime - decodedRpaCookie.lastSeen) > LAST_SEEN_EXPIRE_TIME || + decodedRpaCookie.expires < currentTime + ) { + decodedRpaCookie = { + id: generateUUID(), + start: currentTime, + expires: currentTime + END_EXPIRE_TIME, // six hours later, + } + } + // possible that decodedRpaCookie is undefined, and if it is, we probably are blocked by storage or some other exception + if (Object.keys(decodedRpaCookie).length) { + decodedRpaCookie.lastSeen = currentTime; + decodedRpaCookie.fpkvs = { ...decodedRpaCookie.fpkvs, ...getFpkvs() }; + decodedRpaCookie.pvid = rubiConf.pvid; + setRpaCookie(decodedRpaCookie) + } + return decodedRpaCookie; +} + +/* + Filters and converts URL Params into an object and returns only KVs that match the 'utm_KEY' format +*/ +const getUtmParams = () => { + let search; + + try { + search = parseQS(getWindowLocation().search); + } catch (e) { + search = {}; + } + + return Object.keys(search).reduce((accum, param) => { + if (param.match(/utm_/)) { + accum[param.replace(/utm_/, '')] = search[param]; + } + return accum; + }, {}); +} + +const getFpkvs = () => { + rubiConf.fpkvs = Object.assign((rubiConf.fpkvs || {}), getUtmParams()); + + // convert all values to strings + Object.keys(rubiConf.fpkvs).forEach(key => { + rubiConf.fpkvs[key] = rubiConf.fpkvs[key] + ''; + }); + + return rubiConf.fpkvs; +} + +/* + Checks the alias registry for any entries of the rubicon bid adapter. + adds to the rubiconAliases list if found +*/ +const setRubiconAliases = (aliasRegistry) => { + const otherAliases = Object.keys(aliasRegistry).filter(alias => aliasRegistry[alias] === 'rubicon'); + rubiconAliases.push(...otherAliases); +} + +const sizeToDimensions = size => { + return { + width: size.w || size[0], + height: size.h || size[1] + }; +} + +const findMatchingAdUnitFromAuctions = (matchesFunction, returnFirstMatch) => { + // finding matching adUnit / auction + let matches = {}; + + // loop through auctions in order and adunits + for (const auctionId of cache.auctionOrder) { + const auction = cache.auctions[auctionId].auction; + for (const transactionId in auction.adUnits) { + const adUnit = auction.adUnits[transactionId]; + + // check if this matches + let doesMatch; + try { + doesMatch = matchesFunction(adUnit, auction); + } catch (error) { + logWarn(`${MODULE_NAME}: Error running matches function: ${returnFirstMatch}`, error); + doesMatch = false; + } + if (doesMatch) { + matches = { adUnit, auction }; + + // we either return first match or we want last one matching so go to end + if (returnFirstMatch) return matches; + } + } + } + return matches; +} + +const getRenderingIds = bidWonData => { + // if bid caching off -> return the bidWon auction id + if (!config.getConfig('useBidCache')) { + return { + renderTransactionId: bidWonData.transactionId, + renderAuctionId: bidWonData.auctionId + }; + } + + // a rendering auction id is the LATEST auction / adunit which contains GAM ID's + const matchingFunction = (adUnit, auction) => { + // does adUnit match our bidWon and gam id's are present + const gamHasRendered = deepAccess(cache, `auctions.${auction.auctionId}.gamRenders.${adUnit.transactionId}`); + return adUnit.adUnitCode === bidWonData.adUnitCode && gamHasRendered; + } + let { adUnit, auction } = findMatchingAdUnitFromAuctions(matchingFunction, false); + // If no match was found, we will use the actual bid won auction id + return { + renderTransactionId: (adUnit && adUnit.transactionId) || bidWonData.transactionId, + renderAuctionId: (auction && auction.auctionId) || bidWonData.auctionId + } +} + +const formatBidWon = bidWonData => { + // get transaction and auction id of where this "rendered" + const { renderTransactionId, renderAuctionId } = getRenderingIds(bidWonData); + + const isCachedBid = renderTransactionId !== bidWonData.transactionId; + logInfo(`${MODULE_NAME}: Bid Won : `, { + isCachedBid, + renderAuctionId, + renderTransactionId, + sourceAuctionId: bidWonData.auctionId, + sourceTransactionId: bidWonData.transactionId, + }); + + // get the bid from the source auction id + let bid = deepAccess(cache, `auctions.${bidWonData.auctionId}.auction.adUnits.${bidWonData.transactionId}.bids.${bidWonData.requestId}`); + let adUnit = deepAccess(cache, `auctions.${bidWonData.auctionId}.auction.adUnits.${bidWonData.transactionId}`); + let bidWon = { + ...bid, + sourceAuctionId: bidWonData.auctionId, + renderAuctionId, + transactionId: bidWonData.transactionId, + sourceTransactionId: bidWonData.transactionId, + bidId: bid.pbsBidId || bidWonData.bidId || bidWonData.requestId, // if PBS had us overwrite bidId, use that as signal + renderTransactionId, + accountId, + siteId: adUnit.siteId, + zoneId: adUnit.zoneId, + mediaTypes: adUnit.mediaTypes, + adUnitCode: adUnit.adUnitCode, + isCachedBid: isCachedBid || undefined // only send if it is true (save some space) + } + delete bidWon.pbsBidId; // if pbsBidId is there delete it (no need to pass it) + return bidWon; +} + +const formatGamEvent = (slotEvent, adUnit, auction) => { + const gamEvent = pick(slotEvent, [ + // these come in as `null` from Gpt, which when stringified does not get removed + // so set explicitly to undefined when not a number + 'advertiserId', advertiserId => isNumber(advertiserId) ? advertiserId : undefined, + 'creativeId', creativeId => isNumber(slotEvent.sourceAgnosticCreativeId) ? slotEvent.sourceAgnosticCreativeId : isNumber(creativeId) ? creativeId : undefined, + 'lineItemId', lineItemId => isNumber(slotEvent.sourceAgnosticLineItemId) ? slotEvent.sourceAgnosticLineItemId : isNumber(lineItemId) ? lineItemId : undefined, + 'adSlot', () => slotEvent.slot.getAdUnitPath(), + 'isSlotEmpty', () => slotEvent.isEmpty || undefined + ]); + gamEvent.auctionId = auction.auctionId; + gamEvent.transactionId = adUnit.transactionId; + return gamEvent; +} + +const subscribeToGamSlots = () => { + window.googletag.pubads().addEventListener('slotRenderEnded', event => { + const isMatchingAdSlot = isAdUnitCodeMatchingSlot(event.slot); + + // We want to find the FIRST auction - adUnit that matches and does not have gam data yet + const matchingFunction = (adUnit, auction) => { + // first it has to match the slot + // if the code is present in the elementIdMap then we use the matched id as code here + const elementIds = cache.elementIdMap[adUnit.adUnitCode] || [adUnit.adUnitCode]; + const matchesSlot = elementIds.some(isMatchingAdSlot); + + // next it has to have NOT already been counted as gam rendered + const gamHasRendered = deepAccess(cache, `auctions.${auction.auctionId}.gamRenders.${adUnit.transactionId}`); + return matchesSlot && !gamHasRendered; + } + let { adUnit, auction } = findMatchingAdUnitFromAuctions(matchingFunction, true); + + const slotName = `${event.slot.getAdUnitPath()} - ${event.slot.getSlotElementId()}`; + + if (!adUnit || !auction) { + logInfo(`${MODULE_NAME}: Could not find matching adUnit for Gam Render: `, { + slotName + }); + return; + } + const auctionId = auction.auctionId; + + logInfo(`${MODULE_NAME}: Gam Render: `, { + slotName, + transactionId: adUnit.transactionId, + auctionId: auctionId, + adUnit: adUnit, + }); + + // if we have an adunit, then we need to make a gam event + const gamEvent = formatGamEvent(event, adUnit, auction); + + // marking that this prebid adunit has had its matching gam render found + deepSetValue(cache, `auctions.${auctionId}.gamRenders.${adUnit.transactionId}`, true); + + addEventToQueue({ gamRenders: [gamEvent] }, auctionId, 'gam'); + + // If this auction now has all gam slots rendered, fire the payload + if (!cache.auctions[auctionId].sent && Object.keys(cache.auctions[auctionId].gamRenders).every(tid => cache.auctions[auctionId].gamRenders[tid])) { + // clear the auction end timeout + clearTimeout(cache.timeouts[auctionId]); + delete cache.timeouts[auctionId]; + + // wait for bid wons a bit or send right away + if (rubiConf.analyticsEventDelay > 0) { + setTimeout(() => { + sendAuctionEvent(auctionId, 'gam-delayed'); + }, rubiConf.analyticsEventDelay); + } else { + sendAuctionEvent(auctionId, 'gam'); + } + } + }); +} + +let accountId; +let endpoint; + +let magniteAdapter = adapter({ analyticsType: 'endpoint' }); + +magniteAdapter.originEnableAnalytics = magniteAdapter.enableAnalytics; +function enableMgniAnalytics(config = {}) { + let error = false; + // endpoint + endpoint = deepAccess(config, 'options.endpoint'); + if (!endpoint) { + logError(`${MODULE_NAME}: required endpoint missing`); + error = true; + } + // accountId + accountId = Number(deepAccess(config, 'options.accountId')); + if (!accountId) { + logError(`${MODULE_NAME}: required accountId missing`); + error = true; + } + if (!error) { + magniteAdapter.originEnableAnalytics(config); + } + // listen to gam slot renders! + if (isGptPubadsDefined()) { + subscribeToGamSlots(); + } else { + window.googletag = window.googletag || {}; + window.googletag.cmd = window.googletag.cmd || []; + window.googletag.cmd.push(() => subscribeToGamSlots()); + } +}; + +const handleBidWon = args => { + const bidWon = formatBidWon(args); + addEventToQueue({ bidsWon: [bidWon] }, bidWon.renderAuctionId, 'bidWon'); +} + +magniteAdapter.enableAnalytics = enableMgniAnalytics; + +magniteAdapter.originDisableAnalytics = magniteAdapter.disableAnalytics; +magniteAdapter.disableAnalytics = function () { + // trick analytics module to register our enable back as main one + magniteAdapter._oldEnable = enableMgniAnalytics; + endpoint = undefined; + accountId = undefined; + resetConfs(); + magniteAdapter.originDisableAnalytics(); +} + +magniteAdapter.MODULE_INITIALIZED_TIME = Date.now(); +magniteAdapter.referrerHostname = ''; + +magniteAdapter.track = ({ eventType, args }) => { + switch (eventType) { + case AUCTION_INIT: + // Update session + cache.sessionData = storage.localStorageIsEnabled() && updateRpaCookie(); + // set the rubicon aliases + setRubiconAliases(adapterManager.aliasRegistry); + + // latest page "referer" + pageReferer = deepAccess(args, 'bidderRequests.0.refererInfo.page'); + + // set auction level data + let auctionData = pick(args, [ + 'auctionId', + 'timestamp as auctionStart', + 'timeout as clientTimeoutMillis', + ]); + auctionData.accountId = accountId; + + // Order bidders were called + auctionData.bidderOrder = args.bidderRequests.map(bidderRequest => bidderRequest.bidderCode); + + // Price Floors information + const floorData = deepAccess(args, 'bidderRequests.0.bids.0.floorData'); + if (floorData) { + auctionData.floors = addFloorData(floorData); + } + + // GDPR info + const gdprData = deepAccess(args, 'bidderRequests.0.gdprConsent'); + if (gdprData) { + auctionData.gdpr = pick(gdprData, [ + 'gdprApplies as applies', + 'consentString', + 'apiVersion as version' + ]); + } + + // User ID Data included in auction + const userIds = Object.keys(deepAccess(args, 'bidderRequests.0.bids.0.userId', {})).map(id => { + return { provider: id, hasId: true } + }); + if (userIds.length) { + auctionData.user = { ids: userIds }; + } + + if (serverConfig) { + auctionData.serverTimeoutMillis = serverConfig.timeout; + } + + // lets us keep a map of adunit and wether it had a gam or bid won render yet, used to track when to send events + let gamRenders = {}; + // adunits saved as map of transactionIds + auctionData.adUnits = args.adUnits.reduce((adMap, adUnit) => { + let ad = pick(adUnit, [ + 'code as adUnitCode', + 'transactionId', + 'mediaTypes', mediaTypes => Object.keys(mediaTypes), + 'sizes as dimensions', sizes => sizes.map(sizeToDimensions), + ]); + ad.pbAdSlot = deepAccess(adUnit, 'ortb2Imp.ext.data.pbadslot'); + ad.pattern = deepAccess(adUnit, 'ortb2Imp.ext.data.aupname'); + ad.gpid = deepAccess(adUnit, 'ortb2Imp.ext.gpid'); + ad.bids = {}; + adMap[adUnit.transactionId] = ad; + gamRenders[adUnit.transactionId] = false; + + // Handle case elementId's (div Id's) are set on adUnit - PPI + const elementIds = deepAccess(adUnit, 'ortb2Imp.ext.data.elementid'); + if (elementIds) { + cache.elementIdMap[adUnit.code] = cache.elementIdMap[adUnit.code] || []; + // set it to array if set to string to be careful (should be array of strings) + const newIds = typeof elementIds === 'string' ? [elementIds] : elementIds; + newIds.forEach(id => { + if (!cache.elementIdMap[adUnit.code].includes(id)) { + cache.elementIdMap[adUnit.code].push(id); + } + }); + } + return adMap; + }, {}); + + // holding our pba data to send + cache.auctions[args.auctionId] = { + auction: auctionData, + gamRenders, + pendingEvents: {} + } + break; + case BID_REQUESTED: + args.bids.forEach(bid => { + const adUnit = deepAccess(cache, `auctions.${args.auctionId}.auction.adUnits.${bid.transactionId}`); + adUnit.bids[bid.bidId] = pick(bid, [ + 'bidder', + 'bidId', + 'source', () => bid.src === 's2s' ? 'server' : 'client', + 'status', () => 'no-bid' + ]); + // set acct site zone id on adunit + if ((!adUnit.siteId || !adUnit.zoneId) && rubiconAliases.indexOf(bid.bidder) !== -1) { + if (deepAccess(bid, 'params.accountId') == accountId) { + adUnit.accountId = parseInt(accountId); + adUnit.siteId = parseInt(deepAccess(bid, 'params.siteId')); + adUnit.zoneId = parseInt(deepAccess(bid, 'params.zoneId')); + } + } + }); + break; + case BID_RESPONSE: + const auctionEntry = deepAccess(cache, `auctions.${args.auctionId}.auction`); + const adUnit = deepAccess(auctionEntry, `adUnits.${args.transactionId}`); + let bid = adUnit.bids[args.requestId]; + + // if this came from multibid, there might now be matching bid, so check + // THIS logic will change when we support multibid per bid request + if (!bid && args.originalRequestId) { + let ogBid = adUnit.bids[args.originalRequestId]; + // create new bid + adUnit.bids[args.requestId] = { + ...ogBid, + bidId: args.requestId, + bidderDetail: args.targetingBidder + }; + bid = adUnit.bids[args.requestId]; + } + + // if we have not set enforcements yet set it (This is hidden from bidders until now so we have to get from here) + if (typeof deepAccess(auctionEntry, 'floors.enforcement') !== 'boolean' && deepAccess(args, 'floorData.enforcements')) { + auctionEntry.floors.enforcement = args.floorData.enforcements.enforceJS; + auctionEntry.floors.dealsEnforced = args.floorData.enforcements.floorDeals; + } + + // Log error if no matching bid! + if (!bid) { + logError(`${MODULE_NAME}: Could not find associated bid request for bid response with requestId: `, args.requestId); + break; + } + + // set bid status + switch (args.getStatusCode()) { + case GOOD: + bid.status = 'success'; + delete bid.error; // it's possible for this to be set by a previous timeout + break; + case NO_BID: + bid.status = args.status === BID_REJECTED ? BID_REJECTED_IPF : 'no-bid'; + delete bid.error; + break; + default: + bid.status = 'error'; + bid.error = { + code: 'request-error' + }; + } + bid.clientLatencyMillis = args.timeToRespond || Date.now() - cache.auctions[args.auctionId].auction.auctionStart; + bid.bidResponse = parseBidResponse(args, bid.bidResponse); + + // if pbs gave us back a bidId, we need to use it and update our bidId to PBA + const pbsBidId = (args.pbsBidId == 0 ? generateUUID() : args.pbsBidId) || (args.seatBidId == 0 ? generateUUID() : args.seatBidId); + if (pbsBidId) { + bid.pbsBidId = pbsBidId; + } + break; + case BIDDER_DONE: + const serverError = deepAccess(args, 'serverErrors.0'); + const serverResponseTimeMs = args.serverResponseTimeMs; + args.bids.forEach(bid => { + let cachedBid = deepAccess(cache, `auctions.${bid.auctionId}.auction.adUnits.${bid.transactionId}.bids.${bid.bidId}`); + if (typeof bid.serverResponseTimeMs !== 'undefined') { + cachedBid.serverLatencyMillis = bid.serverResponseTimeMs; + } else if (serverResponseTimeMs && bid.source === 's2s') { + cachedBid.serverLatencyMillis = serverResponseTimeMs; + } + // if PBS said we had an error, and this bid has not been processed by BID_RESPONSE YET + if (serverError && (!cachedBid.status || ['no-bid', 'error'].indexOf(cachedBid.status) !== -1)) { + cachedBid.status = 'error'; + cachedBid.error = { + code: pbsErrorMap[serverError.code] || pbsErrorMap[999], + description: serverError.message + } + } + + // set client latency if not done yet + if (!cachedBid.clientLatencyMillis) { + cachedBid.clientLatencyMillis = Date.now() - cache.auctions[args.auctionId].auction.auctionStart; + } + }); + break; + case BID_WON: + // Allowing us to delay bidWon handling so it happens at right time + // we expect it to happen after gpt slotRenderEnded, but have seen it happen before when testing + // this will ensure it happens after if set + if (rubiConf.analyticsProcessDelay > 0) { + setTimeout(() => { + handleBidWon(args); + }, rubiConf.analyticsProcessDelay); + } else { + handleBidWon(args); + } + break; + case AUCTION_END: + let auctionCache = cache.auctions[args.auctionId]; + // if for some reason the auction did not do its normal thing, this could be undefied so bail + if (!auctionCache) { + break; + } + // Set this auction as being done + auctionCache.auction.auctionEnd = args.auctionEnd; + + // keeping order of auctions and if the payload has been sent or not + cache.auctionOrder.push(args.auctionId); + + const isOnlyInstreamAuction = args.adUnits && args.adUnits.every(adUnit => adUnitIsOnlyInstream(adUnit)); + + // if we are not waiting OR it is instream only auction + if (isOnlyInstreamAuction || rubiConf.analyticsBatchTimeout === 0) { + sendAuctionEvent(args.auctionId, 'solo-auction'); + } else { + // start timer to send batched payload just in case we don't hear any BID_WON events + cache.timeouts[args.auctionId] = setTimeout(() => { + sendAuctionEvent(args.auctionId, 'auctionEnd'); + }, rubiConf.analyticsBatchTimeout); + } + break; + case BID_TIMEOUT: + args.forEach(badBid => { + let bid = deepAccess(cache, `auctions.${badBid.auctionId}.auction.adUnits.${badBid.transactionId}.bids.${badBid.bidId}`, {}); + // might be set already by bidder-done, so do not overwrite + if (bid.status !== 'error') { + bid.status = 'error'; + bid.error = { + code: 'timeout-error', + description: 'prebid.js timeout' // will help us diff if timeout was set by PBS or PBJS + }; + } + }); + break; + case BILLABLE_EVENT: + if (rubiConf.dmBilling.enabled && isBillingEventValid(args)) { + // add to the map indicating it has not been sent yet + deepSetValue(cache.billing, `${args.vendor}.${args.billingId}`, false); + const billingEvent = formatBillingEvent(args); + addEventToQueue({ billableEvents: [billingEvent] }, args.auctionId, 'billing'); + } else { + logInfo(`${MODULE_NAME}: Billing event ignored`, args); + } + break; + } +}; + +adapterManager.registerAnalyticsAdapter({ + adapter: magniteAdapter, + code: 'magnite', + gvlid: RUBICON_GVL_ID +}); + +export default magniteAdapter; diff --git a/modules/magniteAnalyticsAdapter.md b/modules/magniteAnalyticsAdapter.md new file mode 100644 index 00000000000..a9ad0f4345b --- /dev/null +++ b/modules/magniteAnalyticsAdapter.md @@ -0,0 +1,18 @@ +# Magnite Analytics Adapter + +``` +Module Name: Magnite Analytics Adapter +Module Type: Analytics Adapter +Maintainer: demand-manager-support@magnite.com +``` + +## How to configure? +``` +pbjs.enableAnalytics({ + provider: 'magnite', + options: { + accountId: 12345, // The account id assigned to you by the Magnite Team + endpoint: 'http:localhost:9999/event' // Given by the Magnite Team + } +}); +``` diff --git a/modules/rubiconAnalyticsAdapter.js b/modules/rubiconAnalyticsAdapter.js index 223385159a5..76043b71c64 100644 --- a/modules/rubiconAnalyticsAdapter.js +++ b/modules/rubiconAnalyticsAdapter.js @@ -62,15 +62,20 @@ const cache = { const BID_REJECTED_IPF = 'rejected-ipf'; -export let rubiConf = { - pvid: generateUUID().slice(0, 8), - analyticsEventDelay: 0, - dmBilling: { - enabled: false, - vendors: [], - waitForAuction: true +export let rubiConf; +export const resetRubiConf = () => { + rubiConf = { + pvid: generateUUID().slice(0, 8), + analyticsEventDelay: 0, + dmBilling: { + enabled: false, + vendors: [], + waitForAuction: true + } } -}; +} +resetRubiConf(); + // we are saving these as global to this module so that if a pub accidentally overwrites the entire // rubicon object, then we do not lose other data config.getConfig('rubicon', config => { @@ -418,7 +423,7 @@ function getBidPrice(bid) { } } -export function parseBidResponse(bid, previousBidResponse, auctionFloorData) { +export function parseBidResponse(bid, previousBidResponse) { // The current bidResponse for this matching requestId/bidRequestId let responsePrice = getBidPrice(bid) // we need to compare it with the previous one (if there was one) diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..eb9ba190e33 --- /dev/null +++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js @@ -0,0 +1,1942 @@ +import magniteAdapter, { + parseBidResponse, + getHostNameFromReferer, + storage, + rubiConf, +} from '../../../modules/magniteAnalyticsAdapter.js'; +import CONSTANTS from 'src/constants.json'; +import { config } from 'src/config.js'; +import { server } from 'test/mocks/xhr.js'; +import * as mockGpt from '../integration/faker/googletag.js'; +import { + setConfig, + addBidResponseHook, +} from 'modules/currency.js'; +import { getGlobal } from '../../../src/prebidGlobal.js'; +import { deepAccess } from '../../../src/utils.js'; + +let events = require('src/events.js'); +let utils = require('src/utils.js'); + +const { + EVENTS: { + AUCTION_INIT, + AUCTION_END, + BID_REQUESTED, + BID_RESPONSE, + BIDDER_DONE, + BID_WON, + BID_TIMEOUT, + BILLABLE_EVENT + } +} = CONSTANTS; + +const STUBBED_UUID = '12345678-1234-1234-1234-123456789abc'; + +// Mock Event Data +const MOCK = { + AUCTION_INIT: { + 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'timestamp': 1658868383741, + 'adUnits': [ + { + 'code': 'box', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ] + ] + } + }, + 'bids': [ + { + 'bidder': 'rubicon', + 'params': { + 'accountId': 1001, + 'siteId': 267318, + 'zoneId': 1861698 + } + } + ], + 'sizes': [ + [ + 300, + 250 + ] + ], + 'transactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'ortb2Imp': { + 'ext': { + 'tid': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'data': { + 'adserver': { + 'name': 'gam', + 'adslot': '/1234567/prebid-slot' + }, + 'pbadslot': '/1234567/prebid-slot' + }, + 'gpid': '/1234567/prebid-slot' + } + } + } + ], + 'bidderRequests': [ + { + 'bidderCode': 'rubicon', + 'bids': [ + { + 'bidder': 'rubicon', + 'params': { + 'accountId': 1001, + 'siteId': 267318, + 'zoneId': 1861698, + }, + 'adUnitCode': 'box', + 'transactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'bidId': '23fcd8cf4bf0d7', + 'src': 'client', + 'startTime': 1658868383748 + } + ], + 'refererInfo': { + 'page': 'http://a-test-domain.com:8000/test_pages/sanity/TEMP/prebidTest.html?pbjs_debug=true', + }, + } + ], + 'timeout': 3000, + 'config': { + 'accountId': 1001, + 'endpoint': 'https://pba-event-service-alb-dev.use1.fanops.net/event' + } + }, + BID_REQUESTED: { + 'bidderCode': 'rubicon', + 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'transactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'bids': [ + { + 'bidder': 'rubicon', + 'params': { + 'accountId': 1001, + 'siteId': 267318, + 'zoneId': 1861698, + }, + 'adUnitCode': 'box', + 'bidId': '23fcd8cf4bf0d7', + 'transactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'src': 'client', + } + ] + }, + BID_RESPONSE: { + 'bidderCode': 'rubicon', + 'width': 300, + 'height': 250, + 'adId': '3c0b59947ced11', + 'requestId': '23fcd8cf4bf0d7', + 'transactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'mediaType': 'banner', + 'source': 'client', + 'currency': 'USD', + 'creativeId': '4954828', + 'cpm': 3.4, + 'ttl': 300, + 'netRevenue': true, + 'ad': '', + 'bidder': 'rubicon', + 'adUnitCode': 'box', + 'timeToRespond': 271, + 'size': '300x250', + 'status': 'rendered', + getStatusCode: () => 1, + }, + AUCTION_END: { + 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'auctionEnd': 1658868384019, + }, + BIDDER_DONE: { + 'bidderCode': 'rubicon', + 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'bids': [ + { + 'bidder': 'rubicon', + 'adUnitCode': 'box', + 'transactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'bidId': '23fcd8cf4bf0d7', + 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'src': 'client', + } + ] + }, + BID_WON: { + 'bidderCode': 'rubicon', + 'bidId': '23fcd8cf4bf0d7', + 'adId': '3c0b59947ced11', + 'requestId': '23fcd8cf4bf0d7', + 'transactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'mediaType': 'banner', + 'currency': 'USD', + 'cpm': 3.4, + 'ttl': 300, + 'bidder': 'rubicon', + 'adUnitCode': 'box', + 'status': 'rendered', + } +} + +const ANALYTICS_MESSAGE = { + 'channel': 'web', + 'integration': 'pbjs', + 'referrerUri': 'http://a-test-domain.com:8000/test_pages/sanity/TEMP/prebidTest.html?pbjs_debug=true', + 'version': '$prebid.version$', + 'referrerHostname': 'a-test-domain.com', + 'timestamps': { + 'timeSincePageLoad': 500, + 'eventTime': 1519767014281, + 'prebidLoaded': magniteAdapter.MODULE_INITIALIZED_TIME + }, + 'wrapper': { + 'name': '10000_fakewrapper_test' + }, + 'session': { + 'id': '12345678-1234-1234-1234-123456789abc', + 'pvid': '12345678', + 'start': 1519767013781, + 'expires': 1519788613781 + }, + 'auctions': [ + { + 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'auctionStart': 1658868383741, + 'samplingFactor': 1, + 'clientTimeoutMillis': 3000, + 'accountId': 1001, + 'bidderOrder': [ + 'rubicon' + ], + 'serverTimeoutMillis': 1000, + 'adUnits': [ + { + 'adUnitCode': 'box', + 'transactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'mediaTypes': [ + 'banner' + ], + 'dimensions': [ + { + 'width': 300, + 'height': 250 + } + ], + 'pbAdSlot': '/1234567/prebid-slot', + 'gpid': '/1234567/prebid-slot', + 'bids': [ + { + 'bidder': 'rubicon', + 'bidId': '23fcd8cf4bf0d7', + 'source': 'client', + 'status': 'success', + 'clientLatencyMillis': 271, + 'bidResponse': { + 'bidPriceUSD': 3.4, + 'mediaType': 'banner', + 'dimensions': { + 'width': 300, + 'height': 250 + } + } + } + ], + 'accountId': 1001, + 'siteId': 267318, + 'zoneId': 1861698, + 'status': 'success' + } + ], + 'auctionEnd': 1658868384019 + } + ], + 'gamRenders': [ + { + 'adSlot': 'box', + 'advertiserId': 1111, + 'creativeId': 2222, + 'lineItemId': 3333, + 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'transactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a' + } + ], + 'bidsWon': [ + { + 'bidder': 'rubicon', + 'bidId': '23fcd8cf4bf0d7', + 'source': 'client', + 'status': 'success', + 'clientLatencyMillis': 271, + 'bidResponse': { + 'bidPriceUSD': 3.4, + 'mediaType': 'banner', + 'dimensions': { + 'width': 300, + 'height': 250 + } + }, + 'sourceAuctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'renderAuctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', + 'sourceTransactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'renderTransactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'transactionId': '7b10a106-89ea-4e19-bc51-9b2e970fc42a', + 'accountId': 1001, + 'siteId': 267318, + 'zoneId': 1861698, + 'mediaTypes': [ + 'banner' + ], + 'adUnitCode': 'box' + } + ], + 'trigger': 'gam-delayed' +} + +describe('magnite analytics adapter', function () { + let sandbox; + let clock; + let getDataFromLocalStorageStub, setDataInLocalStorageStub, localStorageIsEnabledStub; + let gptSlot0; + let gptSlotRenderEnded0; + beforeEach(function () { + mockGpt.enable(); + gptSlot0 = mockGpt.makeSlot({ code: 'box' }); + gptSlotRenderEnded0 = { + eventName: 'slotRenderEnded', + params: { + slot: gptSlot0, + isEmpty: false, + advertiserId: 1111, + sourceAgnosticCreativeId: 2222, + sourceAgnosticLineItemId: 3333 + } + }; + getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); + setDataInLocalStorageStub = sinon.stub(storage, 'setDataInLocalStorage'); + localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled'); + sandbox = sinon.sandbox.create(); + + localStorageIsEnabledStub.returns(true); + + sandbox.stub(events, 'getEvents').returns([]); + + sandbox.stub(utils, 'generateUUID').returns(STUBBED_UUID); + + clock = sandbox.useFakeTimers(1519767013781); + + magniteAdapter.referrerHostname = ''; + + config.setConfig({ + s2sConfig: { + timeout: 1000, + accountId: 10000, + }, + rubicon: { + wrapperName: '10000_fakewrapper_test' + } + }) + }); + + afterEach(function () { + sandbox.restore(); + config.resetConfig(); + mockGpt.enable(); + getDataFromLocalStorageStub.restore(); + setDataInLocalStorageStub.restore(); + localStorageIsEnabledStub.restore(); + magniteAdapter.disableAnalytics(); + }); + + it('should require accountId', function () { + sandbox.stub(utils, 'logError'); + + magniteAdapter.enableAnalytics({ + options: { + endpoint: '//localhost:9999/event' + } + }); + + expect(utils.logError.called).to.equal(true); + }); + + it('should require endpoint', function () { + sandbox.stub(utils, 'logError'); + + magniteAdapter.enableAnalytics({ + options: { + accountId: 1001 + } + }); + + expect(utils.logError.called).to.equal(true); + }); + + describe('config subscribe', function () { + it('should update the pvid if user asks', function () { + expect(utils.generateUUID.called).to.equal(false); + config.setConfig({ rubicon: { updatePageView: true } }); + expect(utils.generateUUID.called).to.equal(true); + }); + it('should merge in and preserve older set configs', function () { + config.setConfig({ + rubicon: { + wrapperName: '1001_general', + int_type: 'dmpbjs', + fpkvs: { + source: 'fb' + }, + updatePageView: true + } + }); + expect(rubiConf).to.deep.equal({ + analyticsEventDelay: 500, + analyticsBatchTimeout: 5000, + analyticsProcessDelay: 1, + dmBilling: { + enabled: false, + vendors: [], + waitForAuction: true + }, + pvid: '12345678', + wrapperName: '1001_general', + int_type: 'dmpbjs', + fpkvs: { + source: 'fb' + }, + updatePageView: true + }); + + // update it with stuff + config.setConfig({ + rubicon: { + analyticsBatchTimeout: 3000, + fpkvs: { + link: 'email' + } + } + }); + expect(rubiConf).to.deep.equal({ + analyticsEventDelay: 500, + analyticsBatchTimeout: 3000, + analyticsProcessDelay: 1, + dmBilling: { + enabled: false, + vendors: [], + waitForAuction: true + }, + pvid: '12345678', + wrapperName: '1001_general', + int_type: 'dmpbjs', + fpkvs: { + source: 'fb', + link: 'email' + }, + updatePageView: true + }); + + // overwriting specific edge keys should update them + config.setConfig({ + rubicon: { + fpkvs: { + link: 'iMessage', + source: 'twitter' + } + } + }); + expect(rubiConf).to.deep.equal({ + analyticsEventDelay: 500, + analyticsBatchTimeout: 3000, + analyticsProcessDelay: 1, + dmBilling: { + enabled: false, + vendors: [], + waitForAuction: true + }, + pvid: '12345678', + wrapperName: '1001_general', + int_type: 'dmpbjs', + fpkvs: { + link: 'iMessage', + source: 'twitter' + }, + updatePageView: true + }); + }); + }); + + describe('when handling events', function () { + function performStandardAuction({ + gptEvents = [gptSlotRenderEnded0], + auctionId = MOCK.AUCTION_INIT.auctionId, + eventDelay = rubiConf.analyticsEventDelay, + sendBidWon = true + } = {}) { + events.emit(AUCTION_INIT, { ...MOCK.AUCTION_INIT, auctionId }); + events.emit(BID_REQUESTED, { ...MOCK.BID_REQUESTED, auctionId }); + events.emit(BID_RESPONSE, { ...MOCK.BID_RESPONSE, auctionId }); + events.emit(BIDDER_DONE, { ...MOCK.BIDDER_DONE, auctionId }); + events.emit(AUCTION_END, { ...MOCK.AUCTION_END, auctionId }); + + if (gptEvents && gptEvents.length) { + gptEvents.forEach(gptEvent => mockGpt.emitEvent(gptEvent.eventName, gptEvent.params)); + } + + if (sendBidWon) { + events.emit(BID_WON, { ...MOCK.BID_WON, auctionId }); + } + + if (eventDelay > 0) { + clock.tick(eventDelay); + } + } + + beforeEach(function () { + magniteAdapter.enableAnalytics({ + options: { + endpoint: '//localhost:9999/event', + accountId: 1001 + } + }); + config.setConfig({ rubicon: { updatePageView: true } }); + }); + + it('should build a batched message from prebid events', function () { + performStandardAuction(); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + + expect(request.url).to.equal('//localhost:9999/event'); + + let message = JSON.parse(request.requestBody); + + expect(message).to.deep.equal(ANALYTICS_MESSAGE); + }); + + it('should pass along bidderOrder correctly', function () { + const auctionInit = utils.deepClone(MOCK.AUCTION_INIT); + + auctionInit.bidderRequests = auctionInit.bidderRequests.concat([ + { bidderCode: 'pubmatic' }, + { bidderCode: 'ix' }, + { bidderCode: 'appnexus' } + ]) + + events.emit(AUCTION_INIT, auctionInit); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + clock.tick(rubiConf.analyticsBatchTimeout + 1000); + + let message = JSON.parse(server.requests[0].requestBody); + expect(message.auctions[0].bidderOrder).to.deep.equal([ + 'rubicon', + 'pubmatic', + 'ix', + 'appnexus' + ]); + }); + + it('should pass along user ids', function () { + let auctionInit = utils.deepClone(MOCK.AUCTION_INIT); + auctionInit.bidderRequests[0].bids[0].userId = { + criteoId: 'sadfe4334', + lotamePanoramaId: 'asdf3gf4eg', + pubcid: 'dsfa4545-svgdfs5', + sharedId: { id1: 'asdf', id2: 'sadf4344' } + }; + + events.emit(AUCTION_INIT, auctionInit); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + clock.tick(rubiConf.analyticsBatchTimeout + 1000); + + let message = JSON.parse(server.requests[0].requestBody); + + expect(message.auctions[0].user).to.deep.equal({ + ids: [ + { provider: 'criteoId', 'hasId': true }, + { provider: 'lotamePanoramaId', 'hasId': true }, + { provider: 'pubcid', 'hasId': true }, + { provider: 'sharedId', 'hasId': true }, + ] + }); + }); + + // A-Domain tests + [ + { input: ['magnite.com'], expected: ['magnite.com'] }, + { input: ['magnite.com', 'prebid.org'], expected: ['magnite.com', 'prebid.org'] }, + { input: [123, 'prebid.org', false, true, [], 'magnite.com', {}], expected: ['prebid.org', 'magnite.com'] }, + { input: 'not array', expected: undefined }, + { input: [], expected: undefined }, + ].forEach((test, index) => { + it(`should handle adomain correctly - #${index + 1}`, function () { + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + + let bidResponse = utils.deepClone(MOCK.BID_RESPONSE); + bidResponse.meta = { + advertiserDomains: test.input + } + + events.emit(BID_RESPONSE, bidResponse); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(BID_WON, MOCK.BID_WON); + clock.tick(rubiConf.analyticsBatchTimeout + 1000); + + let message = JSON.parse(server.requests[0].requestBody); + expect(message.auctions[0].adUnits[0].bids[0].bidResponse.adomains).to.deep.equal(test.expected); + }); + }); + + describe('with session handling', function () { + const expectedPvid = STUBBED_UUID.slice(0, 8); + beforeEach(function () { + config.setConfig({ rubicon: { updatePageView: true } }); + }); + + it('should not log any session data if local storage is not enabled', function () { + localStorageIsEnabledStub.returns(false); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + delete expectedMessage.session; + delete expectedMessage.fpkvs; + + performStandardAuction(); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + + expect(request.url).to.equal('//localhost:9999/event'); + + let message = JSON.parse(request.requestBody); + + expect(message).to.deep.equal(expectedMessage); + }); + + it('should should pass along custom rubicon kv and pvid when defined', function () { + config.setConfig({ + rubicon: { + fpkvs: { + source: 'fb', + link: 'email' + } + } + }); + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.session.pvid = STUBBED_UUID.slice(0, 8); + expectedMessage.fpkvs = [ + { key: 'source', value: 'fb' }, + { key: 'link', value: 'email' } + ] + expect(message).to.deep.equal(expectedMessage); + }); + + it('should convert kvs to strings before sending', function () { + config.setConfig({ + rubicon: { + fpkvs: { + number: 24, + boolean: false, + string: 'hello', + array: ['one', 2, 'three'], + object: { one: 'two' } + } + } + }); + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.session.pvid = STUBBED_UUID.slice(0, 8); + expectedMessage.fpkvs = [ + { key: 'number', value: '24' }, + { key: 'boolean', value: 'false' }, + { key: 'string', value: 'hello' }, + { key: 'array', value: 'one,2,three' }, + { key: 'object', value: '[object Object]' } + ] + expect(message).to.deep.equal(expectedMessage); + }); + + it('should use the query utm param rubicon kv value and pass updated kv and pvid when defined', function () { + sandbox.stub(utils, 'getWindowLocation').returns({ 'search': '?utm_source=other', 'pbjs_debug': 'true' }); + + config.setConfig({ + rubicon: { + fpkvs: { + source: 'fb', + link: 'email' + } + } + }); + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.session.pvid = STUBBED_UUID.slice(0, 8); + expectedMessage.fpkvs = [ + { key: 'source', value: 'other' }, + { key: 'link', value: 'email' } + ] + + message.fpkvs.sort((left, right) => left.key < right.key); + expectedMessage.fpkvs.sort((left, right) => left.key < right.key); + + expect(message).to.deep.equal(expectedMessage); + }); + + it('should pick up existing localStorage and use its values', function () { + // set some localStorage + let inputlocalStorage = { + id: '987654', + start: 1519767017881, // 15 mins before "now" + expires: 1519767039481, // six hours later + lastSeen: 1519766113781, + fpkvs: { source: 'tw' } + }; + getDataFromLocalStorageStub.withArgs('mgniSession').returns(btoa(JSON.stringify(inputlocalStorage))); + + config.setConfig({ + rubicon: { + fpkvs: { + link: 'email' // should merge this with what is in the localStorage! + } + } + }); + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.session = { + id: '987654', + start: 1519767017881, + expires: 1519767039481, + pvid: expectedPvid + } + expectedMessage.fpkvs = [ + { key: 'source', value: 'tw' }, + { key: 'link', value: 'email' } + ] + expect(message).to.deep.equal(expectedMessage); + + let calledWith; + try { + calledWith = JSON.parse(atob(setDataInLocalStorageStub.getCall(0).args[1])); + } catch (e) { + calledWith = {}; + } + + expect(calledWith).to.deep.equal({ + id: '987654', // should have stayed same + start: 1519767017881, // should have stayed same + expires: 1519767039481, // should have stayed same + lastSeen: 1519767013781, // lastSeen updated to our auction init time + fpkvs: { source: 'tw', link: 'email' }, // link merged in + pvid: expectedPvid // new pvid stored + }); + }); + + it('should overwrite matching localstorge value and use its remaining values', function () { + sandbox.stub(utils, 'getWindowLocation').returns({ 'search': '?utm_source=fb&utm_click=dog' }); + + // set some localStorage + let inputlocalStorage = { + id: '987654', + start: 1519766113781, // 15 mins before "now" + expires: 1519787713781, // six hours later + lastSeen: 1519766113781, + fpkvs: { source: 'tw', link: 'email' } + }; + getDataFromLocalStorageStub.withArgs('mgniSession').returns(btoa(JSON.stringify(inputlocalStorage))); + + config.setConfig({ + rubicon: { + fpkvs: { + link: 'email' // should merge this with what is in the localStorage! + } + } + }); + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.session = { + id: '987654', + start: 1519766113781, + expires: 1519787713781, + pvid: expectedPvid + } + expectedMessage.fpkvs = [ + { key: 'source', value: 'fb' }, + { key: 'link', value: 'email' }, + { key: 'click', value: 'dog' } + ] + + message.fpkvs.sort((left, right) => left.key < right.key); + expectedMessage.fpkvs.sort((left, right) => left.key < right.key); + + expect(message).to.deep.equal(expectedMessage); + + let calledWith; + try { + calledWith = JSON.parse(atob(setDataInLocalStorageStub.getCall(0).args[1])); + } catch (e) { + calledWith = {}; + } + + expect(calledWith).to.deep.equal({ + id: '987654', // should have stayed same + start: 1519766113781, // should have stayed same + expires: 1519787713781, // should have stayed same + lastSeen: 1519767013781, // lastSeen updated to our auction init time + fpkvs: { source: 'fb', link: 'email', click: 'dog' }, // link merged in + pvid: expectedPvid // new pvid stored + }); + }); + + it('should throw out session if lastSeen > 30 mins ago and create new one', function () { + // set some localStorage + let inputlocalStorage = { + id: '987654', + start: 1519764313781, // 45 mins before "now" + expires: 1519785913781, // six hours later + lastSeen: 1519764313781, // 45 mins before "now" + fpkvs: { source: 'tw' } + }; + getDataFromLocalStorageStub.withArgs('mgniSession').returns(btoa(JSON.stringify(inputlocalStorage))); + + config.setConfig({ + rubicon: { + fpkvs: { + link: 'email' // should merge this with what is in the localStorage! + } + } + }); + + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + // session should match what is already in ANALYTICS_MESSAGE, just need to add pvid + expectedMessage.session.pvid = expectedPvid; + + // the saved fpkvs should have been thrown out since session expired + expectedMessage.fpkvs = [ + { key: 'link', value: 'email' } + ] + expect(message).to.deep.equal(expectedMessage); + + let calledWith; + try { + calledWith = JSON.parse(atob(setDataInLocalStorageStub.getCall(0).args[1])); + } catch (e) { + calledWith = {}; + } + + expect(calledWith).to.deep.equal({ + id: STUBBED_UUID, // should have generated not used input + start: 1519767013781, // updated to whenever auction init started + expires: 1519788613781, // 6 hours after start + lastSeen: 1519767013781, // lastSeen updated to our "now" + fpkvs: { link: 'email' }, // link merged in + pvid: expectedPvid // new pvid stored + }); + }); + + it('should throw out session if past expires time and create new one', function () { + // set some localStorage + let inputlocalStorage = { + id: '987654', + start: 1519745353781, // 6 hours before "expires" + expires: 1519766953781, // little more than six hours ago + lastSeen: 1519767008781, // 5 seconds ago + fpkvs: { source: 'tw' } + }; + getDataFromLocalStorageStub.withArgs('mgniSession').returns(btoa(JSON.stringify(inputlocalStorage))); + + config.setConfig({ + rubicon: { + fpkvs: { + link: 'email' // should merge this with what is in the localStorage! + } + } + }); + + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + // session should match what is already in ANALYTICS_MESSAGE, just need to add pvid + expectedMessage.session.pvid = expectedPvid; + + // the saved fpkvs should have been thrown out since session expired + expectedMessage.fpkvs = [ + { key: 'link', value: 'email' } + ] + expect(message).to.deep.equal(expectedMessage); + + let calledWith; + try { + calledWith = JSON.parse(atob(setDataInLocalStorageStub.getCall(0).args[1])); + } catch (e) { + calledWith = {}; + } + + expect(calledWith).to.deep.equal({ + id: STUBBED_UUID, // should have generated and not used same one + start: 1519767013781, // updated to whenever auction init started + expires: 1519788613781, // 6 hours after start + lastSeen: 1519767013781, // lastSeen updated to our "now" + fpkvs: { link: 'email' }, // link merged in + pvid: expectedPvid // new pvid stored + }); + }); + }); + + it('should send gam data if adunit has elementid ortb2 fields', function () { + // update auction init mock to have the elementids in the adunit + // and change adUnitCode to be hashes + let auctionInit = utils.deepClone(MOCK.AUCTION_INIT); + auctionInit.adUnits[0].ortb2Imp.ext.data.elementid = [gptSlot0.getSlotElementId()]; + auctionInit.adUnits[0].code = '1a2b3c4d'; + + // bid request + let bidRequested = utils.deepClone(MOCK.BID_REQUESTED); + bidRequested.bids[0].adUnitCode = '1a2b3c4d'; + + // bid response + let bidResponse = utils.deepClone(MOCK.BID_RESPONSE); + bidResponse.adUnitCode = '1a2b3c4d'; + + // bidder done + let bidderDone = utils.deepClone(MOCK.BIDDER_DONE); + bidderDone.bids[0].adUnitCode = '1a2b3c4d'; + + // bidder done + let bidWon = utils.deepClone(MOCK.BID_WON); + bidWon.adUnitCode = '1a2b3c4d'; + + // Run auction + events.emit(AUCTION_INIT, auctionInit); + events.emit(BID_REQUESTED, bidRequested); + events.emit(BID_RESPONSE, bidResponse); + events.emit(BIDDER_DONE, bidderDone); + events.emit(AUCTION_END, MOCK.AUCTION_END); + + // emmit gpt events and bidWon + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + + events.emit(BID_WON, bidWon); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + + // new adUnitCodes in payload + expectedMessage.auctions[0].adUnits[0].adUnitCode = '1a2b3c4d'; + expectedMessage.bidsWon[0].adUnitCode = '1a2b3c4d'; + expect(message).to.deep.equal(expectedMessage); + }); + + it('should delay the event call depending on analyticsEventDelay config', function () { + config.setConfig({ + rubicon: { + analyticsEventDelay: 2000 + } + }); + performStandardAuction({ eventDelay: 0 }); + + // Should not be sent until delay + expect(server.requests.length).to.equal(0); + + // tick the clock and it should fire + clock.tick(2000); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + + // The timestamps should be changed from the default by (set eventDelay (2000) - eventDelay default (500)) + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.timestamps.eventTime = expectedMessage.timestamps.eventTime + 1500; + expectedMessage.timestamps.timeSincePageLoad = expectedMessage.timestamps.timeSincePageLoad + 1500; + + expect(message).to.deep.equal(expectedMessage); + }); + + ['seatBidId', 'pbsBidId'].forEach(pbsParam => { + it(`should overwrite prebid bidId with incoming PBS ${pbsParam}`, function () { + // bid response + let seatBidResponse = utils.deepClone(MOCK.BID_RESPONSE); + seatBidResponse[pbsParam] = 'abc-123-do-re-me'; + + // Run auction + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BID_RESPONSE, seatBidResponse); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + + // emmit gpt events and bidWon + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + + events.emit(BID_WON, MOCK.BID_WON); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + + // new adUnitCodes in payload + expectedMessage.auctions[0].adUnits[0].bids[0].bidId = 'abc-123-do-re-me'; + expectedMessage.auctions[0].adUnits[0].bids[0].oldBidId = '23fcd8cf4bf0d7'; + expectedMessage.bidsWon[0].bidId = 'abc-123-do-re-me'; + expect(message).to.deep.equal(expectedMessage); + }); + }); + + [0, '0'].forEach(pbsParam => { + it(`should generate new bidId if incoming pbsBidId is ${pbsParam}`, function () { + // bid response + let seatBidResponse = utils.deepClone(MOCK.BID_RESPONSE); + seatBidResponse.pbsBidId = pbsParam; + + // Run auction + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BID_RESPONSE, seatBidResponse); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + + // emmit gpt events and bidWon + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + + events.emit(BID_WON, MOCK.BID_WON); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + + // new adUnitCodes in payload + expectedMessage.auctions[0].adUnits[0].bids[0].bidId = STUBBED_UUID; + expectedMessage.auctions[0].adUnits[0].bids[0].oldBidId = '23fcd8cf4bf0d7'; + expectedMessage.bidsWon[0].bidId = STUBBED_UUID; + expect(message).to.deep.equal(expectedMessage); + }); + }); + + it(`should pick highest cpm if more than one bidResponse comes in`, function () { + // Run auction + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + + const bidResp = utils.deepClone(MOCK.BID_RESPONSE); + + // emit some bid responses + [1.0, 5.5, 0.1].forEach(cpm => { + events.emit(BID_RESPONSE, { ...bidResp, cpm }); + }); + + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + + // emmit gpt events and bidWon + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + + events.emit(BID_WON, MOCK.BID_WON); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + + // highest cpm in payload + expectedMessage.auctions[0].adUnits[0].bids[0].bidResponse.bidPriceUSD = 5.5; + expectedMessage.bidsWon[0].bidResponse.bidPriceUSD = 5.5; + expect(message).to.deep.equal(expectedMessage); + }); + + it('should send bid won events by themselves if emitted after auction pba payload is sent', function () { + performStandardAuction({ sendBidWon: false }); + + // Now send bidWon + events.emit(BID_WON, MOCK.BID_WON); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + + // should see two server requests + expect(server.requests.length).to.equal(2); + + // first is normal analytics event without bidWon + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + delete expectedMessage.bidsWon; + + let message = JSON.parse(server.requests[0].requestBody); + expect(message).to.deep.equal(expectedMessage); + + // second is just a bidWon (remove gam and auction event) + message = JSON.parse(server.requests[1].requestBody); + + let expectedMessage2 = utils.deepClone(ANALYTICS_MESSAGE); + delete expectedMessage2.auctions; + delete expectedMessage2.gamRenders; + + // second event should be event delay time after first one + expectedMessage2.timestamps.eventTime = expectedMessage.timestamps.eventTime + rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay; + expectedMessage2.timestamps.timeSincePageLoad = expectedMessage.timestamps.timeSincePageLoad + rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay; + + // trigger is `batched-bidsWon` + expectedMessage2.trigger = 'batched-bidsWon'; + + expect(message).to.deep.equal(expectedMessage2); + }); + + it('should send gamRender events by themselves if emitted after auction pba payload is sent', function () { + // dont send extra events and hit the batch timeout + performStandardAuction({ gptEvents: [], sendBidWon: false, eventDelay: rubiConf.analyticsBatchTimeout }); + + // Now send gptEvent and bidWon + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + events.emit(BID_WON, MOCK.BID_WON); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + + // should see two server requests + expect(server.requests.length).to.equal(2); + + // first is normal analytics event without bidWon or gam + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + delete expectedMessage.bidsWon; + delete expectedMessage.gamRenders; + + // timing changes a bit -> timestamps should be batchTimeout - event delay later + const expectedExtraTime = rubiConf.analyticsBatchTimeout - rubiConf.analyticsEventDelay; + expectedMessage.timestamps.eventTime = expectedMessage.timestamps.eventTime + expectedExtraTime; + expectedMessage.timestamps.timeSincePageLoad = expectedMessage.timestamps.timeSincePageLoad + expectedExtraTime; + + // since gam event did not fire, the trigger should be auctionEnd + expectedMessage.trigger = 'auctionEnd'; + + let message = JSON.parse(server.requests[0].requestBody); + expect(message).to.deep.equal(expectedMessage); + + // second is gam and bid won + message = JSON.parse(server.requests[1].requestBody); + + let expectedMessage2 = utils.deepClone(ANALYTICS_MESSAGE); + // second event should be event delay time after first one + expectedMessage2.timestamps.eventTime = expectedMessage.timestamps.eventTime + rubiConf.analyticsEventDelay; + expectedMessage2.timestamps.timeSincePageLoad = expectedMessage.timestamps.timeSincePageLoad + rubiConf.analyticsEventDelay; + delete expectedMessage2.auctions; + + // trigger should be `batched-bidsWon-gamRender` + expectedMessage2.trigger = 'batched-bidsWon-gamRenders'; + + expect(message).to.deep.equal(expectedMessage2); + }); + + it('should send all events solo if delay and batch set to 0', function () { + const defaultDelay = rubiConf.analyticsEventDelay; + config.setConfig({ + rubicon: { + analyticsBatchTimeout: 0, + analyticsEventDelay: 0, + analyticsProcessDelay: 0 + } + }); + + performStandardAuction({ eventDelay: 0 }); + + // should be 3 requests + expect(server.requests.length).to.equal(3); + + // grab expected 3 requests from default message + let { auctions, gamRenders, bidsWon, ...rest } = utils.deepClone(ANALYTICS_MESSAGE); + + // rest of payload should have timestamps changed to be - default eventDelay since we changed it to 0 + rest.timestamps.eventTime = rest.timestamps.eventTime - defaultDelay; + rest.timestamps.timeSincePageLoad = rest.timestamps.timeSincePageLoad - defaultDelay; + + // loop through and assert events fired in correct order with correct stuff + [ + { expectedMessage: { auctions, ...rest }, trigger: 'solo-auction' }, + { expectedMessage: { gamRenders, ...rest }, trigger: 'solo-gam' }, + { expectedMessage: { bidsWon, ...rest }, trigger: 'solo-bidWon' }, + ].forEach((stuff, requestNum) => { + let message = JSON.parse(server.requests[requestNum].requestBody); + stuff.expectedMessage.trigger = stuff.trigger; + expect(message).to.deep.equal(stuff.expectedMessage); + }); + }); + + it(`should correctly mark bids as timed out`, function () { + // Run auction (simulate bidder timed out in 1000 ms) + const auctionStart = Date.now() - 1000; + events.emit(AUCTION_INIT, { ...MOCK.AUCTION_INIT, timestamp: auctionStart }); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + + // emit bid timeout + events.emit(BID_TIMEOUT, [ + { + auctionId: MOCK.AUCTION_INIT.auctionId, + adUnitCode: MOCK.AUCTION_INIT.adUnits[0].code, + bidId: MOCK.BID_REQUESTED.bids[0].bidId, + transactionId: MOCK.AUCTION_INIT.adUnits[0].transactionId, + } + ]); + + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + + // emmit gpt events and bidWon + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + + // should see error time out bid + expectedMessage.auctions[0].adUnits[0].bids[0].status = 'error'; + expectedMessage.auctions[0].adUnits[0].bids[0].error = { + code: 'timeout-error', + description: 'prebid.js timeout' // will help us diff if timeout was set by PBS or PBJS + }; + + // should not see bidResponse or bidsWon + delete expectedMessage.auctions[0].adUnits[0].bids[0].bidResponse; + delete expectedMessage.bidsWon; + + // adunit should be marked as error + expectedMessage.auctions[0].adUnits[0].status = 'error'; + + // timed out in 1000 ms + expectedMessage.auctions[0].adUnits[0].bids[0].clientLatencyMillis = 1000; + + expectedMessage.auctions[0].auctionStart = auctionStart; + + expect(message).to.deep.equal(expectedMessage); + }); + + [ + { name: 'aupname', adUnitPath: 'adUnits.0.ortb2Imp.ext.data.aupname', eventPath: 'auctions.0.adUnits.0.pattern', input: '1234/mycoolsite/*&gpt_leaderboard&deviceType=mobile' }, + { name: 'gpid', adUnitPath: 'adUnits.0.ortb2Imp.ext.gpid', eventPath: 'auctions.0.adUnits.0.gpid', input: '1234/gpid/path' }, + { name: 'pbadslot', adUnitPath: 'adUnits.0.ortb2Imp.ext.data.pbadslot', eventPath: 'auctions.0.adUnits.0.pbAdSlot', input: '1234/pbadslot/path' } + ].forEach(test => { + it(`should correctly pass ${test.name}`, function () { + // bid response + let auctionInit = utils.deepClone(MOCK.AUCTION_INIT); + utils.deepSetValue(auctionInit, test.adUnitPath, test.input); + + // Run auction + events.emit(AUCTION_INIT, auctionInit); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + + // emmit gpt events and bidWon + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + + events.emit(BID_WON, MOCK.BID_WON); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + + // pattern in payload + expect(deepAccess(message, test.eventPath)).to.equal(test.input); + }); + }); + + it('should pass bidderDetail for multibid auctions', function () { + let bidResponse = utils.deepClone(MOCK.BID_RESPONSE); + bidResponse.targetingBidder = 'rubi2'; + bidResponse.originalRequestId = bidResponse.requestId; + bidResponse.requestId = '1a2b3c4d5e6f7g8h9'; + + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BID_RESPONSE, bidResponse); + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + + // emmit gpt events and bidWon + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + + let bidWon = utils.deepClone(MOCK.BID_WON); + bidWon.bidId = bidWon.requestId = '1a2b3c4d5e6f7g8h9'; + bidWon.bidderDetail = 'rubi2'; + events.emit(BID_WON, bidWon); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + + expect(server.requests.length).to.equal(1); + + let message = JSON.parse(server.requests[0].requestBody); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + + // expect an extra bid added + expectedMessage.auctions[0].adUnits[0].bids.push({ + ...ANALYTICS_MESSAGE.auctions[0].adUnits[0].bids[0], + bidderDetail: 'rubi2', + bidId: '1a2b3c4d5e6f7g8h9' + }); + + // bid won is our extra bid + expectedMessage.bidsWon[0].bidderDetail = 'rubi2'; + expectedMessage.bidsWon[0].bidId = '1a2b3c4d5e6f7g8h9'; + + expect(message).to.deep.equal(expectedMessage); + }); + + it('should pass bidderDetail for multibid auctions', function () { + // Set the rates + setConfig({ + adServerCurrency: 'JPY', + rates: { + USD: { + JPY: 100 + } + } + }); + + // set our bid response to JPY + let bidResponse = utils.deepClone(MOCK.BID_RESPONSE); + bidResponse.currency = 'JPY'; + bidResponse.cpm = 100; + + // Now add the bidResponse hook which hooks on the currenct conversion function onto the bid response + let innerBid; + addBidResponseHook(function (adCodeId, bid) { + innerBid = bid; + }, 'elementId', bidResponse); + + // Use the rubi analytics parseBidResponse Function to get the resulting cpm from the bid response! + const bidResponseObj = parseBidResponse(innerBid); + expect(bidResponseObj).to.have.property('bidPriceUSD'); + expect(bidResponseObj.bidPriceUSD).to.equal(1.0); + }); + + it('should use the integration type provided in the config instead of the default', () => { + config.setConfig({ + rubicon: { + int_type: 'testType' + } + }) + + performStandardAuction(); + + expect(server.requests.length).to.equal(1); + const request = server.requests[0]; + const message = JSON.parse(request.requestBody); + expect(message.integration).to.equal('testType'); + }); + + it('should correctly pass bid.source when is s2s', () => { + // Run auction + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + + const bidReq = utils.deepClone(MOCK.BID_REQUESTED); + bidReq.bids[0].src = 's2s'; + + events.emit(BID_REQUESTED, bidReq); + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + + // emmit gpt events and bidWon + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + events.emit(BID_WON, MOCK.BID_WON); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + + // bid source should be 'server' + expectedMessage.auctions[0].adUnits[0].bids[0].source = 'server'; + expectedMessage.bidsWon[0].source = 'server'; + expect(message).to.deep.equal(expectedMessage); + }); + + describe('when handling bid caching', () => { + let auctionInits, bidRequests, bidResponses, bidsWon; + beforeEach(function () { + // set timing stuff to 0 so we clearly know when things fire + config.setConfig({ + useBidCache: true, + rubicon: { + analyticsEventDelay: 0, + analyticsBatchTimeout: 0, + analyticsProcessDelay: 0 + } + }); + + // setup 3 auctions + auctionInits = [ + { ...MOCK.AUCTION_INIT, auctionId: 'auctionId-1', adUnits: [{ ...MOCK.AUCTION_INIT.adUnits[0], transactionId: 'tid-1' }] }, + { ...MOCK.AUCTION_INIT, auctionId: 'auctionId-2', adUnits: [{ ...MOCK.AUCTION_INIT.adUnits[0], transactionId: 'tid-2' }] }, + { ...MOCK.AUCTION_INIT, auctionId: 'auctionId-3', adUnits: [{ ...MOCK.AUCTION_INIT.adUnits[0], transactionId: 'tid-3' }] } + ]; + bidRequests = [ + { ...MOCK.BID_REQUESTED, auctionId: 'auctionId-1', bids: [{ ...MOCK.BID_REQUESTED.bids[0], bidId: 'bidId-1', transactionId: 'tid-1' }] }, + { ...MOCK.BID_REQUESTED, auctionId: 'auctionId-2', bids: [{ ...MOCK.BID_REQUESTED.bids[0], bidId: 'bidId-2', transactionId: 'tid-2' }] }, + { ...MOCK.BID_REQUESTED, auctionId: 'auctionId-3', bids: [{ ...MOCK.BID_REQUESTED.bids[0], bidId: 'bidId-3', transactionId: 'tid-3' }] } + ]; + bidResponses = [ + { ...MOCK.BID_RESPONSE, auctionId: 'auctionId-1', transactionId: 'tid-1', requestId: 'bidId-1' }, + { ...MOCK.BID_RESPONSE, auctionId: 'auctionId-2', transactionId: 'tid-2', requestId: 'bidId-2' }, + { ...MOCK.BID_RESPONSE, auctionId: 'auctionId-3', transactionId: 'tid-3', requestId: 'bidId-3' }, + ]; + bidsWon = [ + { ...MOCK.BID_WON, auctionId: 'auctionId-1', transactionId: 'tid-1', bidId: 'bidId-1', requestId: 'bidId-1' }, + { ...MOCK.BID_WON, auctionId: 'auctionId-2', transactionId: 'tid-2', bidId: 'bidId-2', requestId: 'bidId-2' }, + { ...MOCK.BID_WON, auctionId: 'auctionId-3', transactionId: 'tid-3', bidId: 'bidId-3', requestId: 'bidId-3' }, + ]; + }); + function runBasicAuction(auctionNum) { + events.emit(AUCTION_INIT, auctionInits[auctionNum]); + events.emit(BID_REQUESTED, bidRequests[auctionNum]); + events.emit(BID_RESPONSE, bidResponses[auctionNum]); + events.emit(BIDDER_DONE, { ...MOCK.BIDDER_DONE, auctionId: auctionInits[auctionNum].auctionId }); + events.emit(AUCTION_END, { ...MOCK.AUCTION_END, auctionId: auctionInits[auctionNum].auctionId }); + } + it('should select earliest auction to attach to', () => { + // get 3 auctions pending to send events + runBasicAuction(0); + runBasicAuction(1); + runBasicAuction(2); + + // emmit a gptEvent should attach to first auction + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + + // should be 4 requests so far (3 auctions + 1 gamRender) + expect(server.requests.length).to.equal(4); + + // 4th should be gamRender and should have Auciton # 1's id's + const message = JSON.parse(server.requests[3].requestBody); + const expectedMessage = { + ...ANALYTICS_MESSAGE.gamRenders[0], + auctionId: 'auctionId-1', + transactionId: 'tid-1' + }; + expect(message.gamRenders).to.deep.equal([expectedMessage]); + + // emit bidWon from first auction + events.emit(BID_WON, bidsWon[0]); + + // another request which is bidWon + expect(server.requests.length).to.equal(5); + const message1 = JSON.parse(server.requests[4].requestBody); + const expectedMessage1 = { + ...ANALYTICS_MESSAGE.bidsWon[0], + sourceAuctionId: 'auctionId-1', + renderAuctionId: 'auctionId-1', + sourceTransactionId: 'tid-1', + renderTransactionId: 'tid-1', + transactionId: 'tid-1', + bidId: 'bidId-1', + }; + expect(message1.bidsWon).to.deep.equal([expectedMessage1]); + }); + + [ + { useBidCache: true, expectedRenderId: 3 }, + { useBidCache: false, expectedRenderId: 2 } + ].forEach(test => { + it(`should match bidWon to correct render auction if useBidCache is ${test.useBidCache}`, () => { + config.setConfig({ useBidCache: test.useBidCache }); + // get 3 auctions pending to send events + runBasicAuction(0); + runBasicAuction(1); + runBasicAuction(2); + + // emmit 3 gpt Events, first two "empty" + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, { + slot: gptSlot0, + isEmpty: true, + }); + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, { + slot: gptSlot0, + isEmpty: true, + }); + // last one is valid + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + + // should be 6 requests so far (3 auctions + 3 gamRender) + expect(server.requests.length).to.equal(6); + + // 4th should be gamRender and should have Auciton # 1's id's + const message = JSON.parse(server.requests[3].requestBody); + const expectedMessage = { + auctionId: 'auctionId-1', + transactionId: 'tid-1', + isSlotEmpty: true, + adSlot: 'box' + }; + expect(message.gamRenders).to.deep.equal([expectedMessage]); + + // 5th should be gamRender and should have Auciton # 2's id's + const message1 = JSON.parse(server.requests[4].requestBody); + const expectedMessage1 = { + auctionId: 'auctionId-2', + transactionId: 'tid-2', + isSlotEmpty: true, + adSlot: 'box' + }; + expect(message1.gamRenders).to.deep.equal([expectedMessage1]); + + // 6th should be gamRender and should have Auciton # 3's id's + const message2 = JSON.parse(server.requests[5].requestBody); + const expectedMessage2 = { + ...ANALYTICS_MESSAGE.gamRenders[0], + auctionId: 'auctionId-3', + transactionId: 'tid-3' + }; + expect(message2.gamRenders).to.deep.equal([expectedMessage2]); + + // emit bidWon from second auction + // it should pick out render information from 3rd auction and source from 1st + events.emit(BID_WON, bidsWon[1]); + + // another request which is bidWon + expect(server.requests.length).to.equal(7); + const message3 = JSON.parse(server.requests[6].requestBody); + const expectedMessage3 = { + ...ANALYTICS_MESSAGE.bidsWon[0], + sourceAuctionId: 'auctionId-2', + renderAuctionId: `auctionId-${test.expectedRenderId}`, + sourceTransactionId: 'tid-2', + renderTransactionId: `tid-${test.expectedRenderId}`, + transactionId: 'tid-2', + bidId: 'bidId-2' + }; + if (test.useBidCache) expectedMessage3.isCachedBid = true + expect(message3.bidsWon).to.deep.equal([expectedMessage3]); + }); + }); + + it('should still fire bidWon if no gam match found', () => { + // get 3 auctions pending to send events + runBasicAuction(0); + runBasicAuction(1); + runBasicAuction(2); + + // emit bidWon from 3rd auction - it should still fire even though no associated gamRender found + events.emit(BID_WON, bidsWon[2]); + + // another request which is bidWon + expect(server.requests.length).to.equal(4); + const message1 = JSON.parse(server.requests[3].requestBody); + const expectedMessage1 = { + ...ANALYTICS_MESSAGE.bidsWon[0], + sourceAuctionId: 'auctionId-3', + renderAuctionId: 'auctionId-3', + sourceTransactionId: 'tid-3', + renderTransactionId: 'tid-3', + transactionId: 'tid-3', + bidId: 'bidId-3', + }; + expect(message1.bidsWon).to.deep.equal([expectedMessage1]); + }); + }); + }); + + describe('billing events integration', () => { + beforeEach(function () { + magniteAdapter.enableAnalytics({ + options: { + endpoint: '//localhost:9999/event', + accountId: 1001 + } + }); + // default dmBilling + config.setConfig({ + rubicon: { + dmBilling: { + enabled: false, + vendors: [], + waitForAuction: true + } + } + }) + }); + afterEach(function () { + magniteAdapter.disableAnalytics(); + }); + const basicBillingAuction = (billingEvents = []) => { + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + + billingEvents.forEach(ev => events.emit(BILLABLE_EVENT, ev)); + + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + + mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params); + events.emit(BID_WON, MOCK.BID_WON); + + // tick the event delay time plus processing delay + clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay); + } + it('should ignore billing events when not enabled', () => { + basicBillingAuction([{ + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965' + }]); + expect(server.requests.length).to.equal(1); + const request = server.requests[0]; + const message = JSON.parse(request.requestBody); + expect(message.billableEvents).to.be.undefined; + }); + it('should ignore billing events when enabled but vendor is not whitelisted', () => { + // off by default + config.setConfig({ + rubicon: { + dmBilling: { + enabled: true + } + } + }); + basicBillingAuction([{ + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965' + }]); + expect(server.requests.length).to.equal(1); + const request = server.requests[0]; + const message = JSON.parse(request.requestBody); + expect(message.billableEvents).to.be.undefined; + }); + it('should ignore billing events if billingId is not defined or billingId is not a string', () => { + // off by default + config.setConfig({ + rubicon: { + dmBilling: { + enabled: true, + vendors: ['vendorName'] + } + } + }); + basicBillingAuction([ + { + vendor: 'vendorName', + type: 'auction', + }, + { + vendor: 'vendorName', + type: 'auction', + billingId: true + }, + { + vendor: 'vendorName', + type: 'auction', + billingId: 1233434 + }, + { + vendor: 'vendorName', + type: 'auction', + billingId: null + } + ]); + expect(server.requests.length).to.equal(1); + const request = server.requests[0]; + const message = JSON.parse(request.requestBody); + expect(message.billableEvents).to.be.undefined; + }); + it('should pass along billing event in same payload if same auctionId', () => { + // off by default + config.setConfig({ + rubicon: { + dmBilling: { + enabled: true, + vendors: ['vendorName'] + } + } + }); + basicBillingAuction([{ + vendor: 'vendorName', + type: 'pageView', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965', + auctionId: MOCK.AUCTION_INIT.auctionId + }]); + expect(server.requests.length).to.equal(1); + const request = server.requests[0]; + const message = JSON.parse(request.requestBody); + expect(message).to.haveOwnProperty('auctions'); + expect(message.billableEvents).to.deep.equal([{ + accountId: 1001, + vendor: 'vendorName', + type: 'pageView', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965', + auctionId: MOCK.AUCTION_INIT.auctionId + }]); + }); + it('should pass NOT pass along billing event in same payload if no auctionId', () => { + // off by default + config.setConfig({ + rubicon: { + dmBilling: { + enabled: true, + vendors: ['vendorName'] + } + } + }); + basicBillingAuction([{ + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965', + }]); + expect(server.requests.length).to.equal(2); + + // first is the billing event + let message = JSON.parse(server.requests[0].requestBody); + expect(message).to.not.haveOwnProperty('auctions'); + expect(message.billableEvents).to.deep.equal([{ + accountId: 1001, + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965' + }]); + + // second is auctions + message = JSON.parse(server.requests[1].requestBody); + expect(message).to.haveOwnProperty('auctions'); + expect(message).to.not.haveOwnProperty('billableEvents'); + }); + it('should pass along multiple billing events but filter out duplicates', () => { + // off by default + config.setConfig({ + rubicon: { + dmBilling: { + enabled: true, + vendors: ['vendorName'] + } + } + }); + basicBillingAuction([ + { + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965', + auctionId: MOCK.AUCTION_INIT.auctionId + }, + { + vendor: 'vendorName', + type: 'impression', + billingId: '743db6e3-21f2-44d4-917f-cb3488c6076f', + auctionId: MOCK.AUCTION_INIT.auctionId + }, + { + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965', + auctionId: MOCK.AUCTION_INIT.auctionId + } + ]); + expect(server.requests.length).to.equal(1); + const request = server.requests[0]; + const message = JSON.parse(request.requestBody); + expect(message).to.haveOwnProperty('auctions'); + expect(message.billableEvents).to.deep.equal([ + { + accountId: 1001, + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965', + auctionId: MOCK.AUCTION_INIT.auctionId + }, + { + accountId: 1001, + vendor: 'vendorName', + type: 'impression', + billingId: '743db6e3-21f2-44d4-917f-cb3488c6076f', + auctionId: MOCK.AUCTION_INIT.auctionId + } + ]); + }); + it('should pass along event right away if no pending auction', () => { + // off by default + config.setConfig({ + rubicon: { + analyticsEventDelay: 0, + dmBilling: { + enabled: true, + vendors: ['vendorName'] + } + } + }); + + events.emit(BILLABLE_EVENT, { + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965' + }); + expect(server.requests.length).to.equal(1); + const request = server.requests[0]; + const message = JSON.parse(request.requestBody); + expect(message).to.not.haveOwnProperty('auctions'); + expect(message.billableEvents).to.deep.equal([ + { + accountId: 1001, + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965' + } + ]); + }); + it('should pass along event right away if pending auction but not waiting', () => { + // off by default + config.setConfig({ + rubicon: { + dmBilling: { + enabled: true, + vendors: ['vendorName'], + waitForAuction: false + } + } + }); + // should fire right away, and then auction later + basicBillingAuction([{ + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965' + }]); + expect(server.requests.length).to.equal(2); + const billingRequest = server.requests[0]; + const billingMessage = JSON.parse(billingRequest.requestBody); + expect(billingMessage).to.not.haveOwnProperty('auctions'); + expect(billingMessage.billableEvents).to.deep.equal([ + { + accountId: 1001, + vendor: 'vendorName', + type: 'auction', + billingId: 'f8558d41-62de-4349-bc7b-2dbee1e69965' + } + ]); + // auction event after + const auctionRequest = server.requests[1]; + const auctionMessage = JSON.parse(auctionRequest.requestBody); + // should not double pass events! + expect(auctionMessage).to.not.haveOwnProperty('billableEvents'); + }); + }); + + 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'); + }); + + describe(`handle currency conversions`, () => { + const origConvertCurrency = getGlobal().convertCurrency; + afterEach(() => { + if (origConvertCurrency != null) { + getGlobal().convertCurrency = origConvertCurrency; + } else { + delete getGlobal().convertCurrency; + } + }); + + it(`should convert successfully`, () => { + getGlobal().convertCurrency = () => 1.0; + const bidCopy = utils.deepClone(MOCK.BID_RESPONSE); + bidCopy.currency = 'JPY'; + bidCopy.cpm = 100; + + const bidResponseObj = parseBidResponse(bidCopy); + expect(bidResponseObj.conversionError).to.equal(undefined); + expect(bidResponseObj.ogCurrency).to.equal(undefined); + expect(bidResponseObj.ogPrice).to.equal(undefined); + expect(bidResponseObj.bidPriceUSD).to.equal(1.0); + }); + + it(`should catch error and set to zero with conversionError flag true`, () => { + getGlobal().convertCurrency = () => { + throw new Error('I am an error'); + }; + const bidCopy = utils.deepClone(MOCK.BID_RESPONSE); + bidCopy.currency = 'JPY'; + bidCopy.cpm = 100; + + const bidResponseObj = parseBidResponse(bidCopy); + expect(bidResponseObj.conversionError).to.equal(true); + expect(bidResponseObj.ogCurrency).to.equal('JPY'); + expect(bidResponseObj.ogPrice).to.equal(100); + expect(bidResponseObj.bidPriceUSD).to.equal(0); + }); + }); +}); diff --git a/test/spec/modules/rubiconAnalyticsAdapter_spec.js b/test/spec/modules/rubiconAnalyticsAdapter_spec.js index fdbb8235f5f..05b6cc6b6f4 100644 --- a/test/spec/modules/rubiconAnalyticsAdapter_spec.js +++ b/test/spec/modules/rubiconAnalyticsAdapter_spec.js @@ -4,6 +4,7 @@ import rubiconAnalyticsAdapter, { getHostNameFromReferer, storage, rubiConf, + resetRubiConf } from 'modules/rubiconAnalyticsAdapter.js'; import CONSTANTS from 'src/constants.json'; import { config } from 'src/config.js'; @@ -667,6 +668,7 @@ describe('rubicon analytics adapter', function () { expect(utils.generateUUID.called).to.equal(true); }); it('should merge in and preserve older set configs', function () { + resetRubiConf(); config.setConfig({ rubicon: { wrapperName: '1001_general', @@ -689,7 +691,6 @@ describe('rubicon analytics adapter', function () { fpkvs: { source: 'fb' }, - updatePageView: true }); // update it with stuff @@ -714,7 +715,6 @@ describe('rubicon analytics adapter', function () { source: 'fb', link: 'email' }, - updatePageView: true }); // overwriting specific edge keys should update them @@ -740,7 +740,6 @@ describe('rubicon analytics adapter', function () { link: 'iMessage', source: 'twitter' }, - updatePageView: true }); }); }); From b9e060746d81688f41f3d67be081f384202f518b Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Wed, 12 Oct 2022 15:02:02 -0700 Subject: [PATCH 010/367] UserID: call gpt `setPublisherProvidedId` only when PPID is available (#9099) --- modules/userId/index.js | 35 +++++++++++++++----------- test/spec/modules/userId_spec.js | 43 +++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/modules/userId/index.js b/modules/userId/index.js index ca4a67019ec..73295011089 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -425,6 +425,7 @@ function processSubmoduleCallbacks(submodules, cb) { } // cache decoded value (this is copied to every adUnit bid) submodule.idObj = submodule.submodule.decode(idObj, submodule.config); + updatePPID(submodule.idObj); } else { logInfo(`${MODULE_NAME}: ${submodule.submodule.name} - request id responded with an empty value`); } @@ -613,9 +614,9 @@ function idSystemInitializer({delay = GreedyPromise.timeout} = {}) { let initIdSystem; -function getPPID() { +function getPPID(eids = getUserIdsAsEids() || []) { // userSync.ppid should be one of the 'source' values in getUserIdsAsEids() eg pubcid.org or id5-sync.com - const matchingUserId = ppidSource && (getUserIdsAsEids() || []).find(userID => userID.source === ppidSource); + const matchingUserId = ppidSource && eids.find(userID => userID.source === ppidSource); if (matchingUserId && typeof deepAccess(matchingUserId, 'uids.0.id') === 'string') { const ppidValue = matchingUserId.uids[0].id.replace(/[\W_]/g, ''); if (ppidValue.length >= 32 && ppidValue.length <= 150) { @@ -642,18 +643,6 @@ export const requestBidsHook = timedAuctionHook('userId', function requestBidsHo ]).then(() => { // pass available user id data to bid adapters addIdDataToAdUnitBids(reqBidsConfigObj.adUnits || getGlobal().adUnits, initializedSubmodules); - const ppid = getPPID(); - if (ppid) { - if (isGptPubadsDefined()) { - window.googletag.pubads().setPublisherProvidedId(ppid); - } else { - window.googletag = window.googletag || {}; - window.googletag.cmd = window.googletag.cmd || []; - window.googletag.cmd.push(function() { - window.googletag.pubads().setPublisherProvidedId(ppid); - }); - } - } uidMetrics().join(useMetrics(reqBidsConfigObj.metrics), {propagate: false, includeGroups: true}); // calling fn allows prebid to continue processing fn.call(this, reqBidsConfigObj); @@ -853,6 +842,24 @@ function populateSubmoduleId(submodule, consentData, storedConsentData, forceRef if (response.id) { submodule.idObj = submodule.submodule.decode(response.id, submodule.config); } } } + updatePPID(submodule.idObj); +} + +function updatePPID(userIds = getUserIds()) { + if (userIds && ppidSource) { + const ppid = getPPID(createEidsArray(userIds)); + if (ppid) { + if (isGptPubadsDefined()) { + window.googletag.pubads().setPublisherProvidedId(ppid); + } else { + window.googletag = window.googletag || {}; + window.googletag.cmd = window.googletag.cmd || []; + window.googletag.cmd.push(function() { + window.googletag.pubads().setPublisherProvidedId(ppid); + }); + } + } + } } function initSubmodules(dest, submodules, consentData, forceRefresh = false) { diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index e6058673d41..4e9be5417e2 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -405,6 +405,9 @@ describe('User ID', function () { init(config); setSubmoduleRegistry([amxIdSubmodule, sharedIdSystemSubmodule, identityLinkSubmodule, imuIdSubmodule]); + // before ppid should not be set + expect(window.googletag._ppid).to.equal(undefined); + config.setConfig({ userSync: { ppid: 'pubcid.org', @@ -416,19 +419,52 @@ describe('User ID', function () { ] } }); - // before ppid should not be set - expect(window.googletag._ppid).to.equal(undefined); return expectImmediateBidHook(() => {}, {adUnits}).then(() => { // ppid should have been set without dashes and stuff expect(window.googletag._ppid).to.equal('pubCommonidvaluepubCommonidvalue'); }); }); + it('should set PPID when the source needs to call out to the network', () => { + let adUnits = [getAdUnitMock()]; + init(config); + const callback = sinon.stub(); + setSubmoduleRegistry([{ + name: 'sharedId', + getId: function () { + return {callback} + }, + decode(d) { + return d + } + }]); + config.setConfig({ + userSync: { + ppid: 'pubcid.org', + auctionDelay: 10, + userIds: [ + { + name: 'sharedId', + } + ] + } + }); + return expectImmediateBidHook(() => {}, {adUnits}).then(() => { + expect(window.googletag._ppid).to.be.undefined; + const uid = 'thismustbelongerthan32characters' + callback.yield({pubcid: uid}); + expect(window.googletag._ppid).to.equal(uid); + }); + }); + it('should set googletag ppid correctly for imuIdSubmodule', function () { let adUnits = [getAdUnitMock()]; init(config); setSubmoduleRegistry([imuIdSubmodule]); + // before ppid should not be set + expect(window.googletag._ppid).to.equal(undefined); + config.setConfig({ userSync: { ppid: 'ppid.intimatemerger.com', @@ -437,8 +473,7 @@ describe('User ID', function () { ] } }); - // before ppid should not be set - expect(window.googletag._ppid).to.equal(undefined); + return expectImmediateBidHook(() => {}, {adUnits}).then(() => { // ppid should have been set without dashes and stuff expect(window.googletag._ppid).to.equal('imppidvalueimppidvalueimppidvalue'); From 0e8dcb395ca59c1d2a2c3170309cbae09ddb8741 Mon Sep 17 00:00:00 2001 From: vrtcal-dev <50931150+vrtcal-dev@users.noreply.github.com> Date: Thu, 13 Oct 2022 09:22:44 -0500 Subject: [PATCH 011/367] Added support for 3rd party user IDs (#9105) Co-authored-by: Ubuntu --- modules/vrtcalBidAdapter.js | 8 +++++++- test/spec/modules/vrtcalBidAdapter_spec.js | 13 ++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/modules/vrtcalBidAdapter.js b/modules/vrtcalBidAdapter.js index 36276973c20..301d278493b 100644 --- a/modules/vrtcalBidAdapter.js +++ b/modules/vrtcalBidAdapter.js @@ -27,6 +27,11 @@ export const spec = { let ccpa = ''; let coppa = 0; let tmax = 0; + let eids = []; + + if (bidRequests[0].userIdAsEids && bidRequests[0].userIdAsEids.length > 0) { + eids = bidRequests[0].userIdAsEids; + } if (bid && bid.gdprConsent) { gdprApplies = bid.gdprConsent.gdprApplies ? 1 : 0; @@ -74,7 +79,8 @@ export const spec = { }, user: { ext: { - consent: gdprConsent + consent: gdprConsent, + eids: eids } } }; diff --git a/test/spec/modules/vrtcalBidAdapter_spec.js b/test/spec/modules/vrtcalBidAdapter_spec.js index 2f9f1b96142..d911745d378 100644 --- a/test/spec/modules/vrtcalBidAdapter_spec.js +++ b/test/spec/modules/vrtcalBidAdapter_spec.js @@ -2,6 +2,7 @@ import { expect } from 'chai' import { spec } from 'modules/vrtcalBidAdapter' import { newBidder } from 'src/adapters/bidderFactory' import { config } from 'src/config.js'; +import { createEidsArray } from 'modules/userId/eids.js'; describe('vrtcalBidAdapter', function () { const adapter = newBidder(spec) @@ -27,6 +28,7 @@ describe('vrtcalBidAdapter', function () { 'bidId': 'bidID0001', 'bidderRequestId': 'br0001', 'auctionId': 'auction0001', + 'userIdAsEids': {} } ]; @@ -58,7 +60,7 @@ describe('vrtcalBidAdapter', function () { config.setConfig({ coppa: false }); request = spec.buildRequests(bidRequests); - expect(request[0].data).to.match(/"user":{"ext":{"consent":"gdpr-consent-string"}}/); + expect(request[0].data).to.match(/"user":{"ext":{"consent":"gdpr-consent-string"/); expect(request[0].data).to.match(/"regs":{"coppa":0,"ext":{"gdpr":1,"us_privacy":"ccpa-consent-string"}}/); }); @@ -67,6 +69,15 @@ describe('vrtcalBidAdapter', function () { request = spec.buildRequests(bidRequests); expect(request[0].data).to.match(/"tmax":435/); }); + + it('pass 3rd party IDs with the request when present', function () { + bidRequests[0].userIdAsEids = createEidsArray({ + tdid: 'TTD_ID_FROM_USER_ID_MODULE' + }); + + request = spec.buildRequests(bidRequests); + expect(request[0].data).to.include(JSON.stringify({ext: {consent: 'gdpr-consent-string', eids: [{source: 'adserver.org', uids: [{id: 'TTD_ID_FROM_USER_ID_MODULE', atype: 1, ext: {rtiPartner: 'TDID'}}]}]}})); + }); }); describe('interpretResponse', function () { From eb00d839eb198c6155a26a3c415600c575c90102 Mon Sep 17 00:00:00 2001 From: radubarbos Date: Thu, 13 Oct 2022 17:42:17 +0300 Subject: [PATCH 012/367] Yahoossp and Aol Bid Adapters: Added epsilon.com user id source (#9096) * Added epsilon.com user id source to yahoossp and aol bid adapters. * Added epsilon.com user id source to yahoossp and aol bid adapters- unit test. * Added epsilon.com user id source to yahoossp and aol bid adapters- unit test. Co-authored-by: dumitrubarbos --- modules/aolBidAdapter.js | 27 ++++++++++- modules/yahoosspBidAdapter.js | 2 +- test/spec/modules/aolBidAdapter_spec.js | 51 ++++++++++++++++---- test/spec/modules/yahoosspBidAdapter_spec.js | 45 +++++++++++++++++ 4 files changed, 113 insertions(+), 12 deletions(-) diff --git a/modules/aolBidAdapter.js b/modules/aolBidAdapter.js index c9f64ab66b0..d38c373ff1f 100644 --- a/modules/aolBidAdapter.js +++ b/modules/aolBidAdapter.js @@ -31,15 +31,38 @@ const SYNC_TYPES = { }; const SUPPORTED_USER_ID_SOURCES = [ + 'admixer.net', 'adserver.org', + 'adtelligent.com', + 'akamai.com', + 'amxrtb.com', + 'audigent.com', + 'britepool.com', 'criteo.com', + 'crwdcntrl.net', + 'deepintent.com', + 'epsilon.com', + 'hcn.health', 'id5-sync.com', + 'idx.lat', 'intentiq.com', + 'intimatemerger.com', 'liveintent.com', + 'liveramp.com', + 'mediawallahscript.com', + 'merkleinc.com', + 'netid.de', + 'neustar.biz', + 'nextroll.com', + 'novatiq.com', + 'parrable.com', + 'pubcid.org', 'quantcast.com', + 'tapad.com', + 'uidapi.com', 'verizonmedia.com', - 'liveramp.com', - 'yahoo.com' + 'yahoo.com', + 'zeotap.com' ]; const pubapiTemplate = template`${'host'}/pubapi/3.0/${'network'}/${'placement'}/${'pageid'}/${'sizeid'}/ADTECH;v=2;cmd=bid;cors=yes;alias=${'alias'};misc=${'misc'};${'dynamicParams'}`; diff --git a/modules/yahoosspBidAdapter.js b/modules/yahoosspBidAdapter.js index 51d9bd30b84..8f9ede4fccc 100644 --- a/modules/yahoosspBidAdapter.js +++ b/modules/yahoosspBidAdapter.js @@ -30,6 +30,7 @@ const SUPPORTED_USER_ID_SOURCES = [ 'criteo.com', 'crwdcntrl.net', 'deepintent.com', + 'epsilon.com', 'hcn.health', 'id5-sync.com', 'idx.lat', @@ -46,7 +47,6 @@ const SUPPORTED_USER_ID_SOURCES = [ 'parrable.com', 'pubcid.org', 'quantcast.com', - 'quantcast.com', 'tapad.com', 'uidapi.com', 'verizonmedia.com', diff --git a/test/spec/modules/aolBidAdapter_spec.js b/test/spec/modules/aolBidAdapter_spec.js index 50622180ad0..57ce37145f4 100644 --- a/test/spec/modules/aolBidAdapter_spec.js +++ b/test/spec/modules/aolBidAdapter_spec.js @@ -81,20 +81,46 @@ describe('AolAdapter', function () { const ONE_DISPLAY_TTL = 60; const ONE_MOBILE_TTL = 3600; const SUPPORTED_USER_ID_SOURCES = { - 'adserver.org': '100', - 'criteo.com': '200', - 'id5-sync.com': '300', - 'intentiq.com': '400', - 'liveintent.com': '500', - 'quantcast.com': '600', - 'verizonmedia.com': '700', - 'liveramp.com': '800' + 'admixer.net': '100', + 'adserver.org': '200', + 'adtelligent.com': '300', + 'amxrtb.com': '500', + 'audigent.com': '600', + 'britepool.com': '700', + 'criteo.com': '800', + 'crwdcntrl.net': '900', + 'deepintent.com': '1000', + 'epsilon.com': '1100', + 'hcn.health': '1200', + 'id5-sync.com': '1300', + 'idx.lat': '1400', + 'intentiq.com': '1500', + 'intimatemerger.com': '1600', + 'liveintent.com': '1700', + 'liveramp.com': '1800', + 'mediawallahscript.com': '1900', + 'netid.de': '2100', + 'neustar.biz': '2200', + 'pubcid.org': '2600', + 'quantcast.com': '2700', + 'tapad.com': '2800', + 'zeotap.com': '3200' }; const USER_ID_DATA = { + admixerId: SUPPORTED_USER_ID_SOURCES['admixer.net'], + adtelligentId: SUPPORTED_USER_ID_SOURCES['adtelligent.com'], + amxId: SUPPORTED_USER_ID_SOURCES['amxrtb.com'], + britepoolid: SUPPORTED_USER_ID_SOURCES['britepool.com'], criteoId: SUPPORTED_USER_ID_SOURCES['criteo.com'], connectid: SUPPORTED_USER_ID_SOURCES['verizonmedia.com'], + dmdId: SUPPORTED_USER_ID_SOURCES['hcn.health'], + hadronId: SUPPORTED_USER_ID_SOURCES['audigent.com'], + lotamePanoramaId: SUPPORTED_USER_ID_SOURCES['crwdcntrl.net'], + deepintentId: SUPPORTED_USER_ID_SOURCES['deepintent.com'], + fabrickId: SUPPORTED_USER_ID_SOURCES['neustar.biz'], idl_env: SUPPORTED_USER_ID_SOURCES['liveramp.com'], + IDP: SUPPORTED_USER_ID_SOURCES['zeotap.com'], lipb: { lipbid: SUPPORTED_USER_ID_SOURCES['liveintent.com'], segments: ['100', '200'] @@ -104,8 +130,15 @@ describe('AolAdapter', function () { uid: SUPPORTED_USER_ID_SOURCES['id5-sync.com'], ext: {foo: 'bar'} }, + idx: SUPPORTED_USER_ID_SOURCES['idx.lat'], + imuid: SUPPORTED_USER_ID_SOURCES['intimatemerger.com'], intentIqId: SUPPORTED_USER_ID_SOURCES['intentiq.com'], - quantcastId: SUPPORTED_USER_ID_SOURCES['quantcast.com'] + mwOpenLinkId: SUPPORTED_USER_ID_SOURCES['mediawallahscript.com'], + netId: SUPPORTED_USER_ID_SOURCES['netid.de'], + quantcastId: SUPPORTED_USER_ID_SOURCES['quantcast.com'], + publinkId: SUPPORTED_USER_ID_SOURCES['epsilon.com'], + pubcid: SUPPORTED_USER_ID_SOURCES['pubcid.org'], + tapadId: SUPPORTED_USER_ID_SOURCES['tapad.com'] }; function createCustomBidRequest({bids, params} = {}) { diff --git a/test/spec/modules/yahoosspBidAdapter_spec.js b/test/spec/modules/yahoosspBidAdapter_spec.js index e0b6390832b..32bc94b73fa 100644 --- a/test/spec/modules/yahoosspBidAdapter_spec.js +++ b/test/spec/modules/yahoosspBidAdapter_spec.js @@ -2,6 +2,7 @@ import { expect } from 'chai'; import { config } from 'src/config.js'; import { BANNER, VIDEO } from 'src/mediaTypes.js'; import { spec } from 'modules/yahoosspBidAdapter.js'; +import {createEidsArray} from '../../../modules/userId/eids'; const DEFAULT_BID_ID = '84ab500420319d'; const DEFAULT_BID_DCN = '2093845709823475'; @@ -835,6 +836,50 @@ describe('YahooSSP Bid Adapter:', () => { }); }); + describe('User data', () => { + it('should set the allowed sources user eids', () => { + const { validBidRequests, bidderRequest } = generateBuildRequestMock({}); + validBidRequests[0].userIdAsEids = createEidsArray({ + admixerId: 'admixerId_FROM_USER_ID_MODULE', + adtelligentId: 'adtelligentId_FROM_USER_ID_MODULE', + amxId: 'amxId_FROM_USER_ID_MODULE', + britepoolid: 'britepoolid_FROM_USER_ID_MODULE', + deepintentId: 'deepintentId_FROM_USER_ID_MODULE', + publinkId: 'publinkId_FROM_USER_ID_MODULE', + intentIqId: 'intentIqId_FROM_USER_ID_MODULE', + idl_env: 'idl_env_FROM_USER_ID_MODULE', + imuid: 'imuid_FROM_USER_ID_MODULE', + criteoId: 'criteoId_FROM_USER_ID_MODULE', + fabrickId: 'fabrickId_FROM_USER_ID_MODULE', + }); + const data = spec.buildRequests(validBidRequests, bidderRequest).data; + + expect(data.user.ext.eids).to.deep.equal([ + {source: 'admixer.net', uids: [{id: 'admixerId_FROM_USER_ID_MODULE', atype: 3}]}, + {source: 'adtelligent.com', uids: [{id: 'adtelligentId_FROM_USER_ID_MODULE', atype: 3}]}, + {source: 'amxrtb.com', uids: [{id: 'amxId_FROM_USER_ID_MODULE', atype: 1}]}, + {source: 'britepool.com', uids: [{id: 'britepoolid_FROM_USER_ID_MODULE', atype: 3}]}, + {source: 'deepintent.com', uids: [{id: 'deepintentId_FROM_USER_ID_MODULE', atype: 3}]}, + {source: 'epsilon.com', uids: [{id: 'publinkId_FROM_USER_ID_MODULE', atype: 3}]}, + {source: 'intentiq.com', uids: [{id: 'intentIqId_FROM_USER_ID_MODULE', atype: 1}]}, + {source: 'liveramp.com', uids: [{id: 'idl_env_FROM_USER_ID_MODULE', atype: 3}]}, + {source: 'intimatemerger.com', uids: [{id: 'imuid_FROM_USER_ID_MODULE', atype: 1}]}, + {source: 'criteo.com', uids: [{id: 'criteoId_FROM_USER_ID_MODULE', atype: 1}]}, + {source: 'neustar.biz', uids: [{id: 'fabrickId_FROM_USER_ID_MODULE', atype: 1}]} + ]); + }); + + it('should not set not allowed user eids sources', () => { + const { validBidRequests, bidderRequest } = generateBuildRequestMock({}); + validBidRequests[0].userIdAsEids = createEidsArray({ + justId: 'justId_FROM_USER_ID_MODULE' + }); + const data = spec.buildRequests(validBidRequests, bidderRequest).data; + + expect(data.user.ext.eids).to.deep.equal([]); + }); + }); + describe('Request Payload oRTB bid validation:', () => { it('should generate a valid openRTB bid-request object in the data field', () => { const { validBidRequests, bidderRequest } = generateBuildRequestMock({}); From 091fa06ea3c08fb9ad131a9d551a5720e9a7bfe3 Mon Sep 17 00:00:00 2001 From: github-tom-kuhnen <101572885+github-tom-kuhnen@users.noreply.github.com> Date: Thu, 13 Oct 2022 17:15:06 +0200 Subject: [PATCH 013/367] New Teads User ID Module (#9048) --- modules/.submodules.json | 1 + modules/teadsIdSystem.js | 234 ++++++++++++++++++++ modules/teadsIdSystem.md | 22 ++ test/spec/modules/teadsIdSystem_spec.js | 271 ++++++++++++++++++++++++ 4 files changed, 528 insertions(+) create mode 100644 modules/teadsIdSystem.js create mode 100644 modules/teadsIdSystem.md create mode 100644 test/spec/modules/teadsIdSystem_spec.js diff --git a/modules/.submodules.json b/modules/.submodules.json index d3665dd38f4..bd00333a1d9 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -36,6 +36,7 @@ "quantcastIdSystem", "sharedIdSystem", "tapadIdSystem", + "teadsIdSystem", "tncIdSystem", "trustpidSystem", "uid2IdSystem", diff --git a/modules/teadsIdSystem.js b/modules/teadsIdSystem.js new file mode 100644 index 00000000000..20ca4dca460 --- /dev/null +++ b/modules/teadsIdSystem.js @@ -0,0 +1,234 @@ +/** + * This module adds TeadsId to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/teadsIdSystem + * @requires module:modules/userId + */ + +import {isStr, isNumber, logError, logInfo, isEmpty, timestamp} from '../src/utils.js' +import {ajax} from '../src/ajax.js'; +import {submodule} from '../src/hook.js'; +import {getStorageManager} from '../src/storageManager.js'; +import {uspDataHandler} from '../src/adapterManager.js'; + +const MODULE_NAME = 'teadsId'; +const GVL_ID = 132; +const FP_TEADS_ID_COOKIE_NAME = '_tfpvi'; +const EXPIRED_COOKIE_DATE = 'Thu, 01 Jan 1970 00:00:01 GMT'; + +export const gdprStatus = { + GDPR_DOESNT_APPLY: 0, + CMP_NOT_FOUND_OR_ERROR: 22, + GDPR_APPLIES_PUBLISHER: 12, +}; + +export const gdprReason = { + GDPR_DOESNT_APPLY: 0, + CMP_NOT_FOUND: 220, + GDPR_APPLIES_PUBLISHER_CLASSIC: 120, +}; + +export const storage = getStorageManager({gvlid: GVL_ID, moduleName: MODULE_NAME}); + +/** @type {Submodule} */ +export const teadsIdSubmodule = { + /** + * 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 {{teadsId:string}} + */ + decode(value) { + return {teadsId: value} + }, + /** + * performs action to obtain id and return a value in the callback's response argument + * @function + * @param {SubmoduleConfig} [submoduleConfig] + * @param {ConsentData} [consentData] + * @returns {IdResponse|undefined} + */ + getId(submoduleConfig, consentData) { + const resp = function (callback) { + const url = buildAnalyticsTagUrl(submoduleConfig, consentData); + + const callbacks = { + success: (bodyResponse, responseObj) => { + if (responseObj && responseObj.status === 200) { + if (isStr(bodyResponse) && !isEmpty(bodyResponse)) { + const cookiesMaxAge = getTimestampFromDays(365); // 1 year + const expirationCookieDate = getCookieExpirationDate(cookiesMaxAge); + storage.setCookie(FP_TEADS_ID_COOKIE_NAME, bodyResponse, expirationCookieDate); + callback(bodyResponse); + } else { + storage.setCookie(FP_TEADS_ID_COOKIE_NAME, '', EXPIRED_COOKIE_DATE); + callback(); + } + } else { + logInfo(`${MODULE_NAME}: Server error while fetching ID`); + callback(); + } + }, + error: error => { + logError(`${MODULE_NAME}: ID fetch encountered an error`, error); + callback(); + } + }; + + ajax(url, callbacks, undefined, {method: 'GET'}); + }; + return {callback: resp}; + } +}; + +/** + * Build the full URL from the Submodule config & consentData + * @param submoduleConfig + * @param consentData + * @returns {string} + */ +export function buildAnalyticsTagUrl(submoduleConfig, consentData) { + const pubId = getPublisherId(submoduleConfig); + const teadsViewerId = getTeadsViewerId(); + const status = getGdprStatus(consentData); + const gdprConsentString = getGdprConsentString(consentData); + const ccpaConsentString = getCcpaConsentString(uspDataHandler?.getConsentData()); + const gdprReason = getGdprReasonFromStatus(status); + const params = { + analytics_tag_id: pubId, + tfpvi: teadsViewerId, + gdpr_consent: gdprConsentString, + gdpr_status: status, + gdpr_reason: gdprReason, + ccpa_consent: ccpaConsentString, + sv: 'prebid-v1', + }; + + const url = 'https://at.teads.tv/fpc'; + const queryParams = new URLSearchParams(); + + for (const param in params) { + queryParams.append(param, params[param]); + } + + return url + '?' + queryParams.toString(); +} + +/** + * Extract the Publisher ID from the Submodule config + * @returns {string} + * @param submoduleConfig + */ +export function getPublisherId(submoduleConfig) { + const pubId = submoduleConfig?.params?.pubId; + const prefix = 'PUB_'; + if (isNumber(pubId)) { + return prefix + pubId.toString(); + } + if (isStr(pubId) && parseInt(pubId)) { + return prefix + pubId; + } + return ''; +} + +/** + * Extract the GDPR status from the given consentData + * @param consentData + * @returns {number} + */ +export function getGdprStatus(consentData) { + const gdprApplies = consentData?.gdprApplies; + if (gdprApplies === true) { + return gdprStatus.GDPR_APPLIES_PUBLISHER; + } else if (gdprApplies === false) { + return gdprStatus.GDPR_DOESNT_APPLY; + } else { + return gdprStatus.CMP_NOT_FOUND_OR_ERROR; + } +} + +/** + * Extract the GDPR consent string from the given consentData + * @param consentData + * @returns {string} + */ +export function getGdprConsentString(consentData) { + const consentString = consentData?.consentString; + if (isStr(consentString)) { + return consentString; + } else { + return ''; + } +} + +/** + * Map the GDPR reason from the given GDPR status + * @param status + * @returns {number} + */ +function getGdprReasonFromStatus(status) { + switch (status) { + case gdprStatus.GDPR_DOESNT_APPLY: + return gdprReason.GDPR_DOESNT_APPLY; + case gdprStatus.CMP_NOT_FOUND_OR_ERROR: + return gdprReason.CMP_NOT_FOUND; + case gdprStatus.GDPR_APPLIES_PUBLISHER: + return gdprReason.GDPR_APPLIES_PUBLISHER_CLASSIC; + default: + return -1; + } +} + +/** + * Return the well formatted CCPA consent string + * @param ccpaConsentString + * @returns {string|*} + */ +export function getCcpaConsentString(ccpaConsentString) { + if (isStr(ccpaConsentString)) { + return ccpaConsentString; + } else { + return ''; + } +} + +/** + * Get the cookie expiration date string from a given Date and a max age + * @param {number} maxAge + * @returns {string} + */ +export function getCookieExpirationDate(maxAge) { + return new Date(timestamp() + maxAge).toUTCString() +} + +/** + * Get cookie from Cookie or Local Storage + * @returns {string} + */ +function getTeadsViewerId() { + const teadsViewerId = readCookie() + if (isStr(teadsViewerId)) { + return teadsViewerId + } else { + return ''; + } +} + +function readCookie() { + return storage.cookiesAreEnabled(null) ? storage.getCookie(FP_TEADS_ID_COOKIE_NAME, null) : null; +} + +/** + * Return a number of milliseconds from given days number + * @param days + * @returns {number} + */ +export function getTimestampFromDays(days) { + return days * 24 * 60 * 60 * 1000; +} +submodule('userId', teadsIdSubmodule); diff --git a/modules/teadsIdSystem.md b/modules/teadsIdSystem.md new file mode 100644 index 00000000000..b898ceaeacf --- /dev/null +++ b/modules/teadsIdSystem.md @@ -0,0 +1,22 @@ +# Overview + +Module Name: Teads Id System +Module Type: User Id System +Maintainer: innov-ssp@teads.com + +# Description + +Teads user identification system. GDPR & CCPA compliant. + +## Example configuration for publishers: + + pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'teadsId', + params: { + pubId: 1234 + } + }] + } + }); diff --git a/test/spec/modules/teadsIdSystem_spec.js b/test/spec/modules/teadsIdSystem_spec.js new file mode 100644 index 00000000000..7b977e2fb2b --- /dev/null +++ b/test/spec/modules/teadsIdSystem_spec.js @@ -0,0 +1,271 @@ +import { + teadsIdSubmodule, + storage, + buildAnalyticsTagUrl, + getGdprStatus, + gdprStatus, + getPublisherId, + getGdprConsentString, + getCookieExpirationDate, getTimestampFromDays, getCcpaConsentString +} from 'modules/teadsIdSystem.js'; +import {server} from 'test/mocks/xhr.js'; +import * as utils from '../../../src/utils.js'; + +const FP_TEADS_ID_COOKIE_NAME = '_tfpvi'; +const teadsCookieIdSent = 'teadsCookieIdSent'; +const EXPIRED_COOKIE_DATE = 'Thu, 01 Jan 1970 00:00:01 GMT'; + +describe('TeadsIdSystem', function () { + describe('buildAnalyticsTagUrl', function () { + it('return complete URL of server request', function () { + const submoduleConfig = { + params: { + pubId: 1234 + } + }; + + const consentData = { + gdprApplies: true, + consentString: 'abc123==' + } + + const result = buildAnalyticsTagUrl(submoduleConfig, consentData); + const expected = 'https://at.teads.tv/fpc?analytics_tag_id=PUB_1234&tfpvi=&gdpr_consent=abc123%3D%3D&gdpr_status=12&gdpr_reason=120&ccpa_consent=&sv=prebid-v1' + expect(result).to.be.equal(expected); + }) + }); + + describe('getPublisherId', function () { + it('return empty string if params.pubId param is missing', function () { + const submoduleConfig = {}; + const result = getPublisherId(submoduleConfig); + const expected = ''; + expect(result).to.be.equal(expected); + }); + it('return empty string if params.pubId param has a wrong value', function () { + const pubIdDifferentValues = [null, undefined, false, true, {}, [], 'abc123']; + + pubIdDifferentValues.forEach((value) => { + const submoduleConfig = { + params: { + pubId: value + } + }; + const result = getPublisherId(submoduleConfig); + const expected = ''; + expect(result).to.be.equal(expected); + }); + }); + it('return a publisherId prefixed by PUB_ string if params.pubId has a good value', function () { + const pubIdDifferentValues = [1234, '1234']; + + pubIdDifferentValues.forEach((value) => { + const submoduleConfig = { + params: { + pubId: value + } + }; + const result = getPublisherId(submoduleConfig); + const expected = 'PUB_1234'; + expect(result).to.be.equal(expected); + }); + }); + }); + + describe('getGdprConsentString', function () { + it('return empty consentString if no consentData given', function () { + const consentDataDifferentValues = [{}, undefined, null]; + + consentDataDifferentValues.forEach((value) => { + const result = getGdprConsentString(value); + const expected = ''; + expect(result).to.be.equal(expected); + }); + }); + it('return empty consentString if consentString has a wrong format', function () { + const consentStringDifferentValues = [1, 0, undefined, null, {}]; + + consentStringDifferentValues.forEach((value) => { + const consentData = { + consentString: value + }; + const result = getGdprConsentString(consentData); + const expected = ''; + expect(result).to.be.equal(expected); + }); + }); + it('return a good consentString if present and a correct format', function () { + const consentData = { + consentString: 'consent-string-teads-O1' + }; + const result = getGdprConsentString(consentData); + const expected = 'consent-string-teads-O1'; + expect(result).to.be.equal(expected); + }); + }); + + describe('getCcpaConsentString', function () { + it('return empty CCPA consentString if no CCPA data is available or a wrong format', function () { + const consentDataDifferentValues = [{}, undefined, null, 123]; + + consentDataDifferentValues.forEach((value) => { + const result = getCcpaConsentString(value); + const expected = ''; + expect(result).to.be.equal(expected); + }); + }); + it('return CCPA consentString if CCPA data is available and a good format', function () { + const consentData = '1NYN'; + const result = getCcpaConsentString(consentData); + const expected = '1NYN'; + expect(result).to.be.equal(expected); + }); + }); + + describe('getGdprStatus', function () { + it('return CMP_NOT_FOUND_OR_ERROR if no given consentData', function () { + const consentDataDifferentValues = [{}, undefined, null]; + + consentDataDifferentValues.forEach((value) => { + const result = getGdprStatus(value); + const expected = gdprStatus.CMP_NOT_FOUND_OR_ERROR; + expect(result).to.be.equal(expected); + }); + }); + it('return CMP_NOT_FOUND_OR_ERROR if gdprApplies param has a wrong format', function () { + const gdprAppliesDifferentValues = ['yes', 'true', 1, 0, undefined, null, {}]; + + gdprAppliesDifferentValues.forEach((value) => { + const consentData = { + gdprApplies: value + }; + const result = getGdprStatus(consentData); + const expected = gdprStatus.CMP_NOT_FOUND_OR_ERROR; + expect(result).to.be.equal(expected); + }); + }); + it('return GDPR_DOESNT_APPLY if gdprApplies are false', function () { + const consentData = { + gdprApplies: false + }; + const result = getGdprStatus(consentData); + const expected = gdprStatus.GDPR_DOESNT_APPLY; + expect(result).to.be.equal(expected); + }); + it('return GDPR_APPLIES_PUBLISHER if gdprApplies are true', function () { + const consentData = { + gdprApplies: true + }; + const result = getGdprStatus(consentData); + const expected = gdprStatus.GDPR_APPLIES_PUBLISHER; + expect(result).to.be.equal(expected); + }) + }); + + describe('getExpirationDate', function () { + it('return Date Formatted if no given consentData', function () { + let timeStampStub; + timeStampStub = sinon.stub(utils, 'timestamp').returns(Date.UTC(2022, 8, 19, 14, 30, 50, 0)); + const cookiesMaxAge = getTimestampFromDays(365); + + const result = getCookieExpirationDate(cookiesMaxAge); + const expected = 'Tue, 19 Sep 2023 14:30:50 GMT'; + expect(result).to.be.equal(expected); + timeStampStub.restore(); + }); + }); + + describe('getId', function () { + let setCookieStub, setLocalStorageStub, removeFromLocalStorageStub, logErrorStub, logInfoStub, timeStampStub; + const teadsUrl = 'https://at.teads.tv/fpc'; + const timestampNow = new Date().getTime(); + + beforeEach(function () { + setCookieStub = sinon.stub(storage, 'setCookie'); + timeStampStub = sinon.stub(utils, 'timestamp').returns(timestampNow); + logErrorStub = sinon.stub(utils, 'logError'); + logInfoStub = sinon.stub(utils, 'logInfo'); + }); + + afterEach(function () { + setCookieStub.restore(); + timeStampStub.restore(); + logErrorStub.restore(); + logInfoStub.restore(); + }); + + it('should log an error and continue to callback if request errors', function () { + const config = { + params: {} + }; + + const callbackSpy = sinon.spy(); + const callback = teadsIdSubmodule.getId(config).callback; + callback(callbackSpy); + const request = server.requests[0]; + expect(request.url).to.include(teadsUrl); + request.respond(503, null, 'Unavailable'); + expect(logErrorStub.calledOnce).to.be.true; + }); + + it('should log an info and continue to callback if status 204 is sent', function () { + const config = { + params: {} + }; + + const callbackSpy = sinon.spy(); + const callback = teadsIdSubmodule.getId(config).callback; + callback(callbackSpy); + const request = server.requests[0]; + expect(request.url).to.include(teadsUrl); + request.respond(204, null, 'Unavailable'); + expect(logInfoStub.calledOnce).to.be.true; + }); + + it('should call the callback with the response body if status 200 is sent', function () { + const config = { + params: {} + }; + + const callbackSpy = sinon.spy(); + const callback = teadsIdSubmodule.getId(config).callback; + callback(callbackSpy); + const request = server.requests[0]; + expect(request.url).to.include(teadsUrl); + request.respond(200, {'Content-Type': 'application/json'}, teadsCookieIdSent); + expect(callbackSpy.lastCall.lastArg).to.deep.equal(teadsCookieIdSent); + }); + + it('should save teadsId in cookie and local storage if it was returned by API', function () { + const config = { + params: {} + }; + const result = teadsIdSubmodule.getId(config, {}); + result.callback((id) => { + expect(id).to.be.deep.equal(teadsCookieIdSent); + }); + + let request = server.requests[0]; + request.respond(200, {'Content-Type': 'application/json'}, teadsCookieIdSent); + + const cookiesMaxAge = getTimestampFromDays(365); // 1 year + const expirationCookieDate = getCookieExpirationDate(cookiesMaxAge); + expect(setCookieStub.calledWith(FP_TEADS_ID_COOKIE_NAME, teadsCookieIdSent, expirationCookieDate)).to.be.true; + }); + + it('should delete teadsId in cookie and local storage if it was not returned by API', function () { + const config = { + params: {} + }; + const result = teadsIdSubmodule.getId(config, {}); + result.callback((id) => { + expect(id).to.be.undefined + }); + + let request = server.requests[0]; + request.respond(200, {'Content-Type': 'application/json'}, ''); + + expect(setCookieStub.calledWith(FP_TEADS_ID_COOKIE_NAME, '', EXPIRED_COOKIE_DATE)).to.be.true; + }); + }); +}); From 3bf0535847c484a22fc7d428623d42d578b3796e Mon Sep 17 00:00:00 2001 From: Oleksandr <114110452+PolishchukPixFuture@users.noreply.github.com> Date: Thu, 13 Oct 2022 12:32:47 -0400 Subject: [PATCH 014/367] PixFuture Bid Adapter: redisigned user sync (#9067) * - Redisigned User Sync; - Added GVLID; * Delete modules.json * MD file cleanup * MD file cleanup * kick off cicrleci Co-authored-by: Vitali Ioussoupov <84333122+pixfuture-media@users.noreply.github.com> Co-authored-by: Chris Huie --- modules/pixfutureBidAdapter.js | 61 +++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/modules/pixfutureBidAdapter.js b/modules/pixfutureBidAdapter.js index 4c4935e93a4..41b1151e72a 100644 --- a/modules/pixfutureBidAdapter.js +++ b/modules/pixfutureBidAdapter.js @@ -1,8 +1,8 @@ -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {getStorageManager} from '../src/storageManager.js'; -import {BANNER} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; -import {find, includes} from '../src/polyfill.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; +import { find, includes } from '../src/polyfill.js'; import { convertCamelToUnderscore, deepAccess, @@ -13,14 +13,17 @@ import { isPlainObject, transformBidderParamKeywords } from '../src/utils.js'; -import {auctionManager} from '../src/auctionManager.js'; -import {hasPurpose1Consent} from '../src/utils/gpdr.js'; +import { auctionManager } from '../src/auctionManager.js'; const SOURCE = 'pbjs'; const storageManager = getStorageManager({bidderCode: 'pixfuture'}); const USER_PARAMS = ['age', 'externalUid', 'segments', 'gender', 'dnt', 'language']; +let pixID = ''; +const GVLID = 839; + export const spec = { code: 'pixfuture', + gvlid: GVLID, hostname: 'https://gosrv.pixfuture.com', getHostname() { @@ -41,6 +44,10 @@ export const spec = { const tags = validBidRequests.map(bidToTag); const hostname = this.getHostname(); return validBidRequests.map((bidRequest) => { + if (bidRequest.params.pix_id) { + pixID = bidRequest.params.pix_id + } + let referer = ''; if (bidderRequest && bidderRequest.refererInfo) { referer = bidderRequest.refererInfo.page || ''; @@ -123,7 +130,7 @@ export const spec = { const ret = { url: `${hostname}/pixservices`, method: 'POST', - options: {withCredentials: false}, + options: {withCredentials: true}, data: { v: $$PREBID_GLOBAL$$.version, pageUrl: referer, @@ -162,15 +169,39 @@ export const spec = { return bids; }, - getUserSyncs: function (syncOptions, bid, gdprConsent) { - var pixid = ''; - if (typeof bid[0] === 'undefined' || bid[0] === null) { pixid = '0'; } else { pixid = bid[0].body.pix_id; } - if (syncOptions.iframeEnabled && hasPurpose1Consent(gdprConsent)) { - return [{ + getUserSyncs: function (syncOptions, bid, gdprConsent, uspConsent) { + const syncs = []; + + let syncurl = 'pixid=' + pixID; + let gdpr = (gdprConsent && gdprConsent.gdprApplies) ? 1 : 0; + let consent = gdprConsent ? encodeURIComponent(gdprConsent.consentString || '') : ''; + + // Attaching GDPR Consent Params in UserSync url + syncurl += '&gdprconcent=' + gdpr + '&adsync=' + consent; + + // CCPA + if (uspConsent) { + syncurl += '&us_privacy=' + encodeURIComponent(uspConsent); + } + + // coppa compliance + if (config.getConfig('coppa') === true) { + syncurl += '&coppa=1'; + } + + if (syncOptions.iframeEnabled) { + syncs.push({ type: 'iframe', - url: 'https://gosrv.pixfuture.com/cookiesync?adsync=' + gdprConsent.consentString + '&pixid=' + pixid + '&gdprconcent=' + gdprConsent.gdprApplies - }]; + url: 'https://gosrv.pixfuture.com/cookiesync?f=b&' + syncurl + }); + } else { + syncs.push({ + type: 'image', + url: 'https://gosrv.pixfuture.com/cookiesync?f=i&' + syncurl + }); } + + return syncs; } }; From 35549ae23d6af3f751e87865dc70ce8ee75e051a Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 13 Oct 2022 16:49:33 +0000 Subject: [PATCH 015/367] Prebid 7.20.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9a4b993de72..3e7fa29fa35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.20.0-pre", + "version": "7.20.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 5fe3556a11e..1968e68c130 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.20.0-pre", + "version": "7.20.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 1ec822051546333fbb51e22d9b587c038c0e1689 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 13 Oct 2022 16:49:33 +0000 Subject: [PATCH 016/367] Increment version to 7.21.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3e7fa29fa35..a33d475f355 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.20.0", + "version": "7.21.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 1968e68c130..2310cb73311 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.20.0", + "version": "7.21.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From ec662d0fae2a31e4e39a9d2122d5dd9631466eac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Oct 2022 10:12:59 -0700 Subject: [PATCH 017/367] Bump minimist, gulp-clean and mocha (#9111) Bumps [minimist](https://github.com/minimistjs/minimist) to 1.2.6 and updates ancestor dependencies [minimist](https://github.com/minimistjs/minimist), [gulp-clean](https://github.com/peter-vilja/gulp-clean) and [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together. Updates `minimist` from 0.0.8 to 1.2.6 - [Release notes](https://github.com/minimistjs/minimist/releases) - [Changelog](https://github.com/minimistjs/minimist/blob/main/CHANGELOG.md) - [Commits](https://github.com/minimistjs/minimist/compare/v0.0.8...v1.2.6) Updates `gulp-clean` from 0.3.2 to 0.4.0 - [Release notes](https://github.com/peter-vilja/gulp-clean/releases) - [Commits](https://github.com/peter-vilja/gulp-clean/compare/v0.3.2...v0.4.0) Updates `mocha` from 5.2.0 to 10.0.0 - [Release notes](https://github.com/mochajs/mocha/releases) - [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md) - [Commits](https://github.com/mochajs/mocha/compare/v5.2.0...v10.0.0) --- updated-dependencies: - dependency-name: minimist dependency-type: indirect - dependency-name: gulp-clean dependency-type: direct:development - dependency-name: mocha dependency-type: direct:development ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 1900 ++++++++++++++------------------------------- package.json | 4 +- 2 files changed, 604 insertions(+), 1300 deletions(-) diff --git a/package-lock.json b/package-lock.json index a33d475f355..2ae7f9f3931 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.19.0-pre", + "version": "7.21.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -55,7 +55,7 @@ "faker": "^5.5.3", "fs.extra": "^1.3.2", "gulp": "^4.0.0", - "gulp-clean": "^0.3.2", + "gulp-clean": "^0.4.0", "gulp-concat": "^2.6.0", "gulp-connect": "^5.7.0", "gulp-eslint": "^6.0.0", @@ -88,7 +88,7 @@ "karma-spec-reporter": "^0.0.32", "karma-webpack": "^5.0.0", "lodash": "^4.17.21", - "mocha": "^5.0.0", + "mocha": "^10.0.0", "morgan": "^1.10.0", "opn": "^5.4.0", "resolve-from": "^5.0.0", @@ -1673,18 +1673,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -3052,15 +3040,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/mocha-framework/node_modules/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, - "bin": { - "he": "bin/he" - } - }, "node_modules/@wdio/mocha-framework/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -3216,18 +3195,6 @@ "node": ">=8" } }, - "node_modules/@wdio/mocha-framework/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@wdio/mocha-framework/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -3734,6 +3701,18 @@ "node": ">=6" } }, + "node_modules/ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha512-eCjan3AVo/SxZ0/MyIYRtkpxIu/H3xZN7URr1vXVrISxeyz8fUFz0FJziamK4sS8I+t35y4rHg1b2PklyBe/7A==", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -3761,6 +3740,18 @@ "node": ">=0.10.0" } }, + "node_modules/ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -3967,15 +3958,6 @@ "node": ">=0.10.0" } }, - "node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -6039,12 +6021,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/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 - }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -6437,18 +6413,6 @@ "node": ">=0.10.0" } }, - "node_modules/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, - "dependencies": { - "array-find-index": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -8008,18 +7972,6 @@ "node": ">=10" } }, - "node_modules/eslint/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9347,15 +9299,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -9896,381 +9839,84 @@ } }, "node_modules/gulp-clean": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/gulp-clean/-/gulp-clean-0.3.2.tgz", - "integrity": "sha512-1pSOrC+PLKkEQz1HFl5L+TG0LV3/Tz/Y25lRk1IjTsE/agXWcqeeicBFJ1vDgokF+musc0vSBdm3xLXUU8cP1Q==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/gulp-clean/-/gulp-clean-0.4.0.tgz", + "integrity": "sha512-DARK8rNMo4lHOFLGTiHEJdf19GuoBDHqGUaypz+fOhrvOs3iFO7ntdYtdpNxv+AzSJBx/JfypF0yEj9ks1IStQ==", "dev": true, "dependencies": { - "gulp-util": "^2.2.14", - "rimraf": "^2.2.8", - "through2": "^0.4.2" + "fancy-log": "^1.3.2", + "plugin-error": "^0.1.2", + "rimraf": "^2.6.2", + "through2": "^2.0.3", + "vinyl": "^2.1.0" }, "engines": { "node": ">=0.9" } }, - "node_modules/gulp-clean/node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/ansi-styles": { + "node_modules/gulp-clean/node_modules/arr-diff": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", - "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/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, - "dependencies": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/chalk": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", - "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", "dev": true, "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/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 - }, - "node_modules/gulp-clean/node_modules/dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", - "dev": true, - "dependencies": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" - }, - "bin": { - "dateformat": "bin/cli.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/gulp-clean/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/gulp-util": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-2.2.20.tgz", - "integrity": "sha512-9rtv4sj9EtCWYGD15HQQvWtRBtU9g1t0+w29tphetHxjxEAuBKQJkhGqvlLkHEtUjEgoqIpsVwPKU1yMZAa+wA==", - "deprecated": "gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">= 0.9" - } - }, - "node_modules/gulp-clean/node_modules/gulp-util/node_modules/through2": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", - "integrity": "sha1-390BLrnHAOIyP9M084rGIqs3Lac=", - "dev": true, - "dependencies": { - "readable-stream": "~1.0.17", - "xtend": "~3.0.0" - } - }, - "node_modules/gulp-clean/node_modules/gulp-util/node_modules/xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/gulp-clean/node_modules/has-ansi": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", - "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", - "dev": true, - "dependencies": { - "ansi-regex": "^0.2.0" - }, - "bin": { - "has-ansi": "cli.js" + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/gulp-clean/node_modules/indent-string": { + "node_modules/gulp-clean/node_modules/arr-union": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", "dev": true, - "dependencies": { - "repeating": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "node_modules/gulp-clean/node_modules/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, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/gulp-clean/node_modules/lodash._reinterpolate": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz", - "integrity": "sha1-TxInqlqHEfxjL1sHofRgequLMiI=", - "dev": true - }, - "node_modules/gulp-clean/node_modules/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, - "dependencies": { - "lodash._objecttypes": "~2.4.1", - "lodash.keys": "~2.4.1" - } - }, - "node_modules/gulp-clean/node_modules/lodash.template": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-2.4.1.tgz", - "integrity": "sha512-5yLOQwlS69xbaez3g9dA1i0GMAj8pLDHp8lhA4V7M1vRam1lqD76f0jg5EV+65frbqrXo1WH9ZfKalfYBzJ5yQ==", - "dev": true, - "dependencies": { - "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" - } - }, - "node_modules/gulp-clean/node_modules/lodash.templatesettings": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz", - "integrity": "sha1-6nbHXRHrhtTb6JqDiTu4YZKaxpk=", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "~2.4.1", - "lodash.escape": "~2.4.1" - } - }, - "node_modules/gulp-clean/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/meow/node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/gulp-clean/node_modules/minimist": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.1.tgz", - "integrity": "sha512-GY8fANSrTMfBVfInqJAY41QkOM+upUTytK1jZ0c8+3HdHrJxBJ3rF5i9moClXTE8uUSnUo8cAsCoxDXvSY4DHg==", - "dev": true - }, - "node_modules/gulp-clean/node_modules/object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", - "dev": true - }, - "node_modules/gulp-clean/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "node_modules/gulp-clean/node_modules/array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/gulp-clean/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "node_modules/gulp-clean/node_modules/extend-shallow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "kind-of": "^1.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/gulp-clean/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/read-pkg": { + "node_modules/gulp-clean/node_modules/kind-of": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/gulp-clean/node_modules/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, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/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, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/gulp-clean/node_modules/redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "node_modules/gulp-clean/node_modules/plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", "dev": true, "dependencies": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" + "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" }, "engines": { "node": ">=0.10.0" @@ -10288,107 +9934,14 @@ "rimraf": "bin.js" } }, - "node_modules/gulp-clean/node_modules/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 - }, - "node_modules/gulp-clean/node_modules/strip-ansi": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", - "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", - "dev": true, - "dependencies": { - "ansi-regex": "^0.2.1" - }, - "bin": { - "strip-ansi": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/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, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "dependencies": { - "get-stdin": "^4.0.1" - }, - "bin": { - "strip-indent": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/supports-color": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", - "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", - "dev": true, - "bin": { - "supports-color": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/gulp-clean/node_modules/through2": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", - "integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=", - "dev": true, - "dependencies": { - "readable-stream": "~1.0.17", - "xtend": "~2.1.1" - } - }, - "node_modules/gulp-clean/node_modules/trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/vinyl": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.2.3.tgz", - "integrity": "sha1-vKk4IJWC7FpJrVOKAPofEl5RMlI=", - "dev": true, - "dependencies": { - "clone-stats": "~0.0.1" - }, - "engines": { - "node": ">= 0.9" - } - }, - "node_modules/gulp-clean/node_modules/xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "dependencies": { - "object-keys": "~0.4.0" - }, - "engines": { - "node": ">=0.4" + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, "node_modules/gulp-cli": { @@ -11253,18 +10806,6 @@ "node": ">=6" } }, - "node_modules/gulp-eslint/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gulp-eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -12068,9 +11609,9 @@ } }, "node_modules/he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, "bin": { "he": "bin/he" @@ -14478,51 +14019,18 @@ "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", "dev": true }, - "node_modules/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, - "dependencies": { - "lodash._htmlescapes": "~2.4.1" - } - }, - "node_modules/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 - }, "node_modules/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 }, - "node_modules/lodash._htmlescapes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz", - "integrity": "sha1-MtFL8IRLbeb4tioFG09nwii2JMs=", - "dev": true - }, "node_modules/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 }, - "node_modules/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 - }, - "node_modules/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 - }, "node_modules/lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", @@ -14541,31 +14049,12 @@ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "dev": true }, - "node_modules/lodash._reunescapedhtml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz", - "integrity": "sha1-dHxPxAED6zu4oJduVx96JlnpO6c=", - "dev": true, - "dependencies": { - "lodash._htmlescapes": "~2.4.1", - "lodash.keys": "~2.4.1" - } - }, "node_modules/lodash._root": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", "dev": true }, - "node_modules/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, - "dependencies": { - "lodash._objecttypes": "~2.4.1" - } - }, "node_modules/lodash.clone": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", @@ -14595,17 +14084,6 @@ "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", "dev": true }, - "node_modules/lodash.escape": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.4.1.tgz", - "integrity": "sha1-LOEsXghNsKV92l5dHu659dF1o7Q=", - "dev": true, - "dependencies": { - "lodash._escapehtmlchar": "~2.4.1", - "lodash._reunescapedhtml": "~2.4.1", - "lodash.keys": "~2.4.1" - } - }, "node_modules/lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", @@ -14648,26 +14126,6 @@ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", "dev": true }, - "node_modules/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, - "dependencies": { - "lodash._isnative": "~2.4.1", - "lodash._shimkeys": "~2.4.1", - "lodash.isobject": "~2.4.1" - } - }, - "node_modules/lodash.keys/node_modules/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, - "dependencies": { - "lodash._objecttypes": "~2.4.1" - } - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -14723,15 +14181,6 @@ "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", "dev": true }, - "node_modules/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, - "dependencies": { - "lodash.keys": "~2.4.1" - } - }, "node_modules/lodash.zip": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", @@ -14822,19 +14271,6 @@ "loose-envify": "cli.js" } }, - "node_modules/loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "dependencies": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/loupe": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", @@ -16145,122 +15581,316 @@ "dev": true }, "node_modules/mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", + "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", "dev": true, "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", "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" + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" }, "bin": { "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 4.0.0" + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" } }, - "node_modules/mocha/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "node_modules/mocha/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "ms": "2.0.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/mocha/node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=0.3.1" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/mocha/node_modules/glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "node_modules/mocha/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "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-flag": "^4.0.0" }, "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/mocha/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/mocha/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=4" + "node": ">=7.0.0" } }, - "node_modules/mocha/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "node_modules/mocha/node_modules/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 + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "ms": "2.1.2" }, "engines": { - "node": "*" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/mocha/node_modules/minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", + "node_modules/mocha/node_modules/debug/node_modules/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 }, - "node_modules/mocha/node_modules/mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "minimist": "0.0.8" + "argparse": "^2.0.1" }, "bin": { - "mkdirp": "bin/cmd.js" + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/mocha/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/mocha/node_modules/supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "node_modules/mocha/node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" } }, "node_modules/morgan": { @@ -19988,6 +19618,18 @@ "node": ">=0.10.0" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/suffix": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", @@ -21580,16 +21222,6 @@ "he": "^1.2.0" } }, - "node_modules/vue-template-compiler/node_modules/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, - "optional": true, - "bin": { - "he": "bin/he" - } - }, "node_modules/walk": { "version": "2.3.15", "resolved": "https://registry.npmjs.org/walk/-/walk-2.3.15.tgz", @@ -23576,12 +23208,6 @@ "type-fest": "^0.20.2" } }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -24742,12 +24368,6 @@ "path-exists": "^4.0.0" } }, - "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 - }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -24853,12 +24473,6 @@ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -25281,6 +24895,15 @@ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, + "ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha512-eCjan3AVo/SxZ0/MyIYRtkpxIu/H3xZN7URr1vXVrISxeyz8fUFz0FJziamK4sS8I+t35y4rHg1b2PklyBe/7A==", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -25299,6 +24922,15 @@ "ansi-wrap": "0.1.0" } }, + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -25459,12 +25091,6 @@ "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", "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", @@ -27095,12 +26721,6 @@ "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==", "dev": true }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -27417,15 +27037,6 @@ "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=", "dev": true }, - "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", @@ -28476,12 +28087,6 @@ "lru-cache": "^6.0.0" } }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -29726,12 +29331,6 @@ "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", "dev": true }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -30171,315 +29770,66 @@ } }, "gulp-clean": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/gulp-clean/-/gulp-clean-0.3.2.tgz", - "integrity": "sha512-1pSOrC+PLKkEQz1HFl5L+TG0LV3/Tz/Y25lRk1IjTsE/agXWcqeeicBFJ1vDgokF+musc0vSBdm3xLXUU8cP1Q==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/gulp-clean/-/gulp-clean-0.4.0.tgz", + "integrity": "sha512-DARK8rNMo4lHOFLGTiHEJdf19GuoBDHqGUaypz+fOhrvOs3iFO7ntdYtdpNxv+AzSJBx/JfypF0yEj9ks1IStQ==", "dev": true, "requires": { - "gulp-util": "^2.2.14", - "rimraf": "^2.2.8", - "through2": "^0.4.2" + "fancy-log": "^1.3.2", + "plugin-error": "^0.1.2", + "rimraf": "^2.6.2", + "through2": "^2.0.3", + "vinyl": "^2.1.0" }, "dependencies": { - "ansi-regex": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", - "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", - "dev": true - }, - "ansi-styles": { + "arr-diff": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", - "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", - "dev": true - }, - "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=", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", "dev": true, "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - } - }, - "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 - }, - "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" - } - }, - "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" + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" } }, - "gulp-util": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-2.2.20.tgz", - "integrity": "sha512-9rtv4sj9EtCWYGD15HQQvWtRBtU9g1t0+w29tphetHxjxEAuBKQJkhGqvlLkHEtUjEgoqIpsVwPKU1yMZAa+wA==", - "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" - } - }, - "xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=", - "dev": true - } - } - }, - "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" - } - }, - "indent-string": { + "arr-union": { "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" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "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" - } - }, - "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.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.template": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-2.4.1.tgz", - "integrity": "sha512-5yLOQwlS69xbaez3g9dA1i0GMAj8pLDHp8lhA4V7M1vRam1lqD76f0jg5EV+65frbqrXo1WH9ZfKalfYBzJ5yQ==", - "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" - } - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", "dev": true }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", - "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": { - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "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=", + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", "dev": true }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "extend-shallow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", "dev": true, "requires": { - "pinkie-promise": "^2.0.0" + "kind-of": "^1.1.0" } }, - "path-type": { + "kind-of": { "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=", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", "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" - } - }, - "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" - } - }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", "dev": true, "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" + "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" } }, "rimraf": { @@ -30491,77 +29841,14 @@ "glob": "^7.1.3" } }, - "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" - } - }, - "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-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" - } - }, - "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" - } - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==", - "dev": true - }, - "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": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "requires": { - "object-keys": "~0.4.0" + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } } } @@ -31265,12 +30552,6 @@ "is-fullwidth-code-point": "^2.0.0" } }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -31927,9 +31208,9 @@ "dev": true }, "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "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": { @@ -33759,51 +33040,18 @@ "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", @@ -33822,31 +33070,12 @@ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "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", @@ -33876,17 +33105,6 @@ "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", @@ -33929,28 +33147,6 @@ "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" - } - } - } - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -34006,15 +33202,6 @@ "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", @@ -34082,16 +33269,6 @@ "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" - } - }, "loupe": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", @@ -35004,97 +34181,227 @@ "dev": true }, "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", + "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", "dev": true, "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", "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" + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" }, "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "ms": "2.0.0" + "color-convert": "^2.0.1" } }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "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" + "balanced-match": "^1.0.0" } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.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 }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "ms": "2.1.2" + }, + "dependencies": { + "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 + } } }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { - "minimist": "0.0.8" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "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 + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true } } }, @@ -38032,6 +37339,12 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "suffix": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", @@ -39279,15 +38592,6 @@ "requires": { "de-indent": "^1.0.2", "he": "^1.2.0" - }, - "dependencies": { - "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, - "optional": true - } } }, "walk": { diff --git a/package.json b/package.json index 2310cb73311..ed80a9c94a7 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "faker": "^5.5.3", "fs.extra": "^1.3.2", "gulp": "^4.0.0", - "gulp-clean": "^0.3.2", + "gulp-clean": "^0.4.0", "gulp-concat": "^2.6.0", "gulp-connect": "^5.7.0", "gulp-eslint": "^6.0.0", @@ -97,7 +97,7 @@ "karma-spec-reporter": "^0.0.32", "karma-webpack": "^5.0.0", "lodash": "^4.17.21", - "mocha": "^5.0.0", + "mocha": "^10.0.0", "morgan": "^1.10.0", "opn": "^5.4.0", "resolve-from": "^5.0.0", From e7dd6dd46876bb48b5700d997e412ca5f900369d Mon Sep 17 00:00:00 2001 From: pm-nitin-shirsat <107102698+pm-nitin-shirsat@users.noreply.github.com> Date: Fri, 14 Oct 2022 19:50:53 +0530 Subject: [PATCH 018/367] Pubmatic Bid Adapter: use new dealpriority in deal tier module execution (#9103) * Implement functionality for deal priority * Update test cases * kick off test manually Co-authored-by: Chris Huie --- modules/pubmaticBidAdapter.js | 30 ++++++++- test/spec/modules/pubmaticBidAdapter_spec.js | 65 ++++++++++++++++++-- 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 7f346b1c7b0..02198042474 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -1,7 +1,7 @@ -import { logWarn, _each, isBoolean, isStr, isArray, inIframe, mergeDeep, deepAccess, isNumber, deepSetValue, logInfo, logError, deepClone, convertTypes, uniques } from '../src/utils.js'; +import { getBidRequest, logWarn, _each, isBoolean, isStr, isArray, inIframe, mergeDeep, deepAccess, isNumber, deepSetValue, logInfo, logError, deepClone, convertTypes, uniques } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; +import { BANNER, VIDEO, NATIVE, ADPOD } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; import { bidderSettings } from '../src/bidderSettings.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; @@ -953,6 +953,29 @@ function _assignRenderer(newBid, request) { } } +/** + * In case of adpod video context, assign prebiddealpriority to the dealtier property of adpod-video bid, + * so that adpod module can set the hb_pb_cat_dur targetting key. + * @param {*} newBid + * @param {*} bid + * @param {*} request + * @returns + */ +export function assignDealTier(newBid, bid, request) { + if (!bid?.ext?.prebiddealpriority) return; + const bidRequest = getBidRequest(newBid.requestId, [request.bidderRequest]); + const videoObj = deepAccess(bidRequest, 'mediaTypes.video'); + if (videoObj?.context != ADPOD) return; + + const duration = bid?.ext?.video?.duration || videoObj?.maxduration; + // if (!duration) return; + newBid.video = { + context: ADPOD, + durationSeconds: duration, + dealTier: bid.ext.prebiddealpriority + }; +} + function isNonEmptyArray(test) { if (isArray(test) === true) { if (test.length > 0) { @@ -1265,6 +1288,7 @@ export const spec = { newBid.height = bid.hasOwnProperty('h') ? bid.h : req.video.h; newBid.vastXml = bid.adm; _assignRenderer(newBid, request); + assignDealTier(newBid, bid, request); break; case NATIVE: _parseNativeResponse(bid, newBid); diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index 3f341fd259f..13b4e31b5c7 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -1,7 +1,7 @@ -import {expect} from 'chai'; -import {spec, checkVideoPlacement, _getDomainFromURL} from 'modules/pubmaticBidAdapter.js'; +import { expect } from 'chai'; +import { spec, checkVideoPlacement, _getDomainFromURL, assignDealTier } from 'modules/pubmaticBidAdapter.js'; import * as utils from 'src/utils.js'; -import {config} from 'src/config.js'; +import { config } from 'src/config.js'; import { createEidsArray } from 'modules/userId/eids.js'; import { bidderSettings } from 'src/bidderSettings.js'; const constants = require('src/constants.json'); @@ -4063,9 +4063,64 @@ describe('PubMatic adapter', function () { expect(data.imp[0]['video']['h']).to.equal(videoBidRequests[0].mediaTypes.video.playerSize[1]); expect(data.imp[0]['video']['battr']).to.equal(undefined); }); + + describe('Assign Deal Tier (i.e. prebidDealPriority)', function () { + let videoSeatBid, request, newBid; + // let data = JSON.parse(request.data); + beforeEach(function () { + videoSeatBid = videoBidResponse.body.seatbid[0].bid[0]; + // const adpodValidOutstreamBidRequest = validOutstreamBidRequest.bids[0].mediaTypes.video.context = 'adpod'; + request = spec.buildRequests(bidRequests, validOutstreamBidRequest); + newBid = { + requestId: '47acc48ad47af5' + }; + videoSeatBid.ext = videoSeatBid.ext || {}; + videoSeatBid.ext.video = videoSeatBid.ext.video || {}; + // videoBidRequests[0].mediaTypes.video = videoBidRequests[0].mediaTypes.video || {}; + }); + + it('should not assign video object if deal priority is missing', function () { + assignDealTier(newBid, videoSeatBid, request); + expect(newBid.video).to.equal(undefined); + expect(newBid.video).to.not.exist; + }); + + it('should not assign video object if context is not a adpod', function () { + videoSeatBid.ext.prebiddealpriority = 5; + assignDealTier(newBid, videoSeatBid, request); + expect(newBid.video).to.equal(undefined); + expect(newBid.video).to.not.exist; + }); + + describe('when video deal tier object is present', function () { + beforeEach(function () { + videoSeatBid.ext.prebiddealpriority = 5; + request.bidderRequest.bids[0].mediaTypes.video = { + ...request.bidderRequest.bids[0].mediaTypes.video, + context: 'adpod', + maxduration: 50 + }; + }); + + it('should set video deal tier object, when maxduration is present in ext', function () { + assignDealTier(newBid, videoSeatBid, request); + expect(newBid.video.durationSeconds).to.equal(50); + expect(newBid.video.context).to.equal('adpod'); + expect(newBid.video.dealTier).to.equal(5); + }); + + it('should set video deal tier object, when duration is present in ext', function () { + videoSeatBid.ext.video.duration = 20; + assignDealTier(newBid, videoSeatBid, request); + expect(newBid.video.durationSeconds).to.equal(20); + expect(newBid.video.context).to.equal('adpod'); + expect(newBid.video.dealTier).to.equal(5); + }); + }); + }); }); - describe('Marketplace params', function() { + describe('Marketplace params', function () { let sandbox, utilsMock, newBidRequests, newBidResponses; beforeEach(() => { utilsMock = sinon.mock(utils); @@ -4082,7 +4137,7 @@ describe('PubMatic adapter', function () { sandbox.restore(); }) - it('Should add bidder code as groupm for marketplace groupm response', function () { + it('Should add bidder code as groupm for marketplace groupm response ', function () { let request = spec.buildRequests(newBidRequests, { auctionId: 'new-auction-id' }); From 301a82f8c26c2e16c59689ccc2299b7a901f75b6 Mon Sep 17 00:00:00 2001 From: Carlos Felix Date: Fri, 14 Oct 2022 09:47:08 -0500 Subject: [PATCH 019/367] 33Across Bid Adapter: Add structured user agent information to RTB payload (#9112) * Add UA high entropy values to the request * 33x specs: use the right format for "sua" version values --- modules/33acrossBidAdapter.js | 29 ++++++++----- test/spec/modules/33acrossBidAdapter_spec.js | 45 +++++++++++++++++++- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/modules/33acrossBidAdapter.js b/modules/33acrossBidAdapter.js index 89c00897571..d9524a281f8 100644 --- a/modules/33acrossBidAdapter.js +++ b/modules/33acrossBidAdapter.js @@ -11,6 +11,7 @@ import { logWarn, getWindowSelf, mergeDeep, + pick } from '../src/utils.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; @@ -242,7 +243,8 @@ function _getMRAKey(bidRequest) { // Infer the necessary data from valid bid for a minimal ttxRequest and create HTTP request function _createServerRequest({ bidRequests, gdprConsent = {}, uspConsent, pageUrl, ttxSettings }) { const ttxRequest = {}; - const { siteId, test } = bidRequests[0].params; + const firstBidRequest = bidRequests[0]; + const { siteId, test } = firstBidRequest.params; /* * Infer data for the request payload @@ -254,13 +256,13 @@ function _createServerRequest({ bidRequests, gdprConsent = {}, uspConsent, pageU }); ttxRequest.site = { id: siteId }; - ttxRequest.device = _buildDeviceORTB(); + ttxRequest.device = _buildDeviceORTB(firstBidRequest.ortb2?.device); if (pageUrl) { ttxRequest.site.page = pageUrl; } - ttxRequest.id = bidRequests[0].auctionId; + ttxRequest.id = firstBidRequest.auctionId; if (gdprConsent.consentString) { ttxRequest.user = setExtensions(ttxRequest.user, { @@ -268,9 +270,9 @@ function _createServerRequest({ bidRequests, gdprConsent = {}, uspConsent, pageU }); } - if (Array.isArray(bidRequests[0].userIdAsEids) && bidRequests[0].userIdAsEids.length > 0) { + if (Array.isArray(firstBidRequest.userIdAsEids) && firstBidRequest.userIdAsEids.length > 0) { ttxRequest.user = setExtensions(ttxRequest.user, { - 'eids': bidRequests[0].userIdAsEids + 'eids': firstBidRequest.userIdAsEids }); } @@ -294,9 +296,9 @@ function _createServerRequest({ bidRequests, gdprConsent = {}, uspConsent, pageU } }; - if (bidRequests[0].schain) { + if (firstBidRequest.schain) { ttxRequest.source = setExtensions(ttxRequest.source, { - 'schain': bidRequests[0].schain + 'schain': firstBidRequest.schain }); } @@ -739,10 +741,9 @@ function _createSync({ siteId = 'zzz000000000003zzz', gdprConsent = {}, uspConse } // BUILD REQUESTS: DEVICE -function _buildDeviceORTB() { +function _buildDeviceORTB(device = {}) { const win = getWindowSelf(); - - return { + const deviceProps = { ext: { ttx: { ...getScreenDimensions(), @@ -752,7 +753,13 @@ function _buildDeviceORTB() { mtp: win.navigator.maxTouchPoints } } - }; + } + + if (device.sua) { + deviceProps.sua = pick(device.sua, [ 'browsers', 'platform', 'model' ]); + } + + return deviceProps; } function getTopMostAccessibleWindow() { diff --git a/test/spec/modules/33acrossBidAdapter_spec.js b/test/spec/modules/33acrossBidAdapter_spec.js index 3657f7da912..2680544d00b 100644 --- a/test/spec/modules/33acrossBidAdapter_spec.js +++ b/test/spec/modules/33acrossBidAdapter_spec.js @@ -43,6 +43,17 @@ describe('33acrossBidAdapter:', function () { ah: 500, mtp: 0 } + }, + sua: { + browsers: [{ + brand: 'Google Chrome', + version: ['104', '0', '5112', '79'] + }], + platform: { + brand: 'macOS', + version: ['11', '6', '8'] + }, + model: '' } }, id: 'r1', @@ -305,7 +316,23 @@ describe('33acrossBidAdapter:', function () { adUnitCode: 'div-id', auctionId: 'r1', mediaTypes: {}, - transactionId: 't1' + transactionId: 't1', + ortb2: { + device: { + sua: { + browsers: [{ + brand: 'Google Chrome', + version: ['104', '0', '5112', '79'] + }], + platform: { + brand: 'macOS', + version: ['11', '6', '8'] + }, + model: '', + mobile: false + } + } + } } ]; @@ -322,6 +349,22 @@ describe('33acrossBidAdapter:', function () { auctionId: 'r1', mediaTypes: {}, transactionId: 't2', + ortb2: { + device: { + sua: { + browsers: [{ + brand: 'Google Chrome', + version: ['104', '0', '5112', '79'] + }], + platform: { + brand: 'macOS', + version: ['11', '6', '8'] + }, + model: '', + mobile: false + } + } + }, ...bidParams }); From 9aa8e61e1862de600647af061dec7d3b4660b525 Mon Sep 17 00:00:00 2001 From: guiann Date: Fri, 14 Oct 2022 17:11:52 +0200 Subject: [PATCH 020/367] AdYouLike Bid Adapter : fix page and ref Url values (#9109) * add required clickurl in every native adrequest * allows the native response to be given as is to prebid if possible * add unit tests on new Native case * Handle meta object in bid response with default addomains array * fix icon retrieval in Native case * Update priorities in case of multiple mediatypes given * improve robustness and fix associated unit test on picture urls * add support for params.size parameter * add unit test on new size format * Makes sure the playerSize format is consistent * enable Vast response on bidder adapter * fix lint errors * add test on Vast format case * add userId to bidrequest * revert package-lock.json changes * improve multiple mediatype handling * Expose adyoulike GVL id * fix icurl issue when retreiving icon for Native mediatype * update unit tests on icon url in native mediatype * target video endpoint when video mediatype is present * add unit test on video endpoint * detect if bid request has video * remove console log * Add size information in Video bid + unit tests * Remove unused method (old video retrieval) * update pagereferrer and pageUrl values * improve null robustness in native getAssetValue * change function body and add unit test * fix pageUrl in case not given i ortb2 * adjust pageUrl and referrer values * add unit tests on new priority behaviour Co-authored-by: GuillaumeA --- modules/adyoulikeBidAdapter.js | 18 ++++++++++++------ test/spec/modules/adyoulikeBidAdapter_spec.js | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/adyoulikeBidAdapter.js b/modules/adyoulikeBidAdapter.js index b0b132abd1c..f7473b3bad4 100644 --- a/modules/adyoulikeBidAdapter.js +++ b/modules/adyoulikeBidAdapter.js @@ -227,17 +227,23 @@ function createEndpointQS(bidderRequest) { const qs = {}; if (bidderRequest) { const ref = bidderRequest.refererInfo; - if (ref?.location) { - // RefererUrl will be removed in a future version. - qs.RefererUrl = encodeURIComponent(ref.location); - if (ref.numIframes > 0) { - qs.SafeFrame = true; + if (ref) { + if (ref.location) { + // RefererUrl will be removed in a future version. + qs.RefererUrl = encodeURIComponent(ref.location); + if (!ref.reachedTop) { + qs.SafeFrame = true; + } } + + qs.PageUrl = encodeURIComponent(ref.topmostLocation); + qs.PageReferrer = encodeURIComponent(ref.location); } + // retreive info from ortb2 object if present (prebid7) const siteInfo = bidderRequest.ortb2?.site; if (siteInfo) { - qs.PageUrl = encodeURIComponent(siteInfo.page); + qs.PageUrl = encodeURIComponent(siteInfo.page || ref?.topmostLocation); qs.PageReferrer = encodeURIComponent(siteInfo.ref || ref?.location); } } diff --git a/test/spec/modules/adyoulikeBidAdapter_spec.js b/test/spec/modules/adyoulikeBidAdapter_spec.js index bab0776a5f4..e6a153d501a 100644 --- a/test/spec/modules/adyoulikeBidAdapter_spec.js +++ b/test/spec/modules/adyoulikeBidAdapter_spec.js @@ -18,7 +18,7 @@ describe('Adyoulike Adapter', function () { consentString: consentString, gdprApplies: true }, - refererInfo: {location: referrerUrl, canonicalUrl, domain}, + refererInfo: {location: referrerUrl, canonicalUrl, domain, topmostLocation: 'fakePageURL'}, ortb2: {site: {page: pageUrl, ref: referrerUrl}} }; const bidRequestWithEmptyPlacement = [ From ced1a9dac8a1e97911c89dea699a4b1488a38b7e Mon Sep 17 00:00:00 2001 From: matthieularere-msq <63732822+matthieularere-msq@users.noreply.github.com> Date: Fri, 14 Oct 2022 21:44:23 +0200 Subject: [PATCH 021/367] Mediasquare Bid Adapter: add video renderer + change with floors (#9079) --- modules/mediasquareBidAdapter.js | 45 +++++++++++++++++-- .../modules/mediasquareBidAdapter_spec.js | 6 ++- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/modules/mediasquareBidAdapter.js b/modules/mediasquareBidAdapter.js index c431fe2059e..819ff280e35 100644 --- a/modules/mediasquareBidAdapter.js +++ b/modules/mediasquareBidAdapter.js @@ -3,6 +3,7 @@ import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import {Renderer} from '../src/Renderer.js'; const BIDDER_CODE = 'mediasquare'; const BIDDER_URL_PROD = 'https://pbs-front.mediasquare.fr/' @@ -10,6 +11,8 @@ const BIDDER_URL_TEST = 'https://bidder-test.mediasquare.fr/' const BIDDER_ENDPOINT_AUCTION = 'msq_prebid'; const BIDDER_ENDPOINT_WINNING = 'winning'; +const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; + export const spec = { code: BIDDER_CODE, gvlid: 791, @@ -40,11 +43,15 @@ export const spec = { const test = config.getConfig('debug') ? 1 : 0; let adunitValue = null; Object.keys(validBidRequests).forEach(key => { + floor = {}; adunitValue = validBidRequests[key]; if (typeof adunitValue.getFloor === 'function') { - floor = adunitValue.getFloor({currency: 'EUR', mediaType: '*', size: '*'}); - } else { - floor = {}; + if (Array.isArray(adunitValue.sizes)) { + adunitValue.sizes.forEach(value => { + let tmpFloor = adunitValue.getFloor({currency: 'USD', mediaType: '*', size: value}); + if (tmpFloor != {}) { floor[value.join('x')] = tmpFloor; } + }); + } } codes.push({ owner: adunitValue.params.owner, @@ -132,6 +139,7 @@ export const spec = { if ('url' in value['video']) { bidResponse['vastUrl'] = value['video']['url'] } if ('xml' in value['video']) { bidResponse['vastXml'] = value['video']['xml'] } bidResponse['mediaType'] = 'video'; + bidResponse['renderer'] = createRenderer(value, OUTSTREAM_RENDERER_URL); } if (value.hasOwnProperty('deal_id')) { bidResponse['dealId'] = value['deal_id']; } bidResponses.push(bidResponse); @@ -182,4 +190,35 @@ export const spec = { } } + +function outstreamRender(bid) { + bid.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + sizes: [bid.width, bid.height], + targetId: bid.adUnitCode, + adResponse: bid.adResponse, + rendererOptions: { + showBigPlayButton: false, + showProgressBar: 'bar', + showVolume: false, + allowFullscreen: true, + skippable: false, + content: bid.vastXml + } + }); + }); +} + +function createRenderer(bid, url) { + const renderer = Renderer.install({ + id: bid.bidId, + url: url, + loaded: false, + adUnitCode: bid.adUnitCode, + targetId: bid.adUnitCode + }); + renderer.setRender(outstreamRender); + return renderer; +} + registerBidder(spec); diff --git a/test/spec/modules/mediasquareBidAdapter_spec.js b/test/spec/modules/mediasquareBidAdapter_spec.js index eeab047a405..346d02d91d0 100644 --- a/test/spec/modules/mediasquareBidAdapter_spec.js +++ b/test/spec/modules/mediasquareBidAdapter_spec.js @@ -78,7 +78,8 @@ describe('MediaSquare bid adapter tests', function () { owner: 'test', code: 'publishername_atf_desktop_rg_pave' }, - getFloor: function (a) { return { currency: 'EUR', floor: 1.0 }; }, + sizes: [[300, 250]], + getFloor: function (a) { return { currency: 'USD', floor: 1.0 }; }, }]; var BID_RESPONSE = {'body': { 'responses': [{ @@ -142,7 +143,7 @@ describe('MediaSquare bid adapter tests', function () { const requestfloor = spec.buildRequests(FLOORS_PARAMS, DEFAULT_OPTIONS); const responsefloor = JSON.parse(requestfloor.data); expect(responsefloor.codes[0]).to.have.property('floor').exist; - expect(responsefloor.codes[0].floor).to.have.property('floor').and.to.equal(1.0); + expect(responsefloor.codes[0].floor).to.have.property('300x250').and.to.have.property('floor').and.to.equal(1); }); it('Verify parse response', function () { @@ -239,6 +240,7 @@ describe('MediaSquare bid adapter tests', function () { const bid = response[0]; expect(bid).to.have.property('vastXml'); expect(bid).to.have.property('vastUrl'); + expect(bid).to.have.property('renderer'); delete BID_RESPONSE.body.responses[0].video; }); }); From d8f25b92ed2d04ab578681076a35217548fc5df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Fermeaux?= <32789499+fermeaux@users.noreply.github.com> Date: Mon, 17 Oct 2022 18:29:58 +0200 Subject: [PATCH 022/367] Ogury Bid Adapter: Add xandr sync (#9118) --- modules/oguryBidAdapter.js | 8 +++- test/spec/modules/oguryBidAdapter_spec.js | 50 +++++++++++++++-------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/modules/oguryBidAdapter.js b/modules/oguryBidAdapter.js index f0ed3c24a31..cb082f2d9a9 100644 --- a/modules/oguryBidAdapter.js +++ b/modules/oguryBidAdapter.js @@ -11,7 +11,7 @@ const DEFAULT_TIMEOUT = 1000; const BID_HOST = 'https://mweb-hb.presage.io/api/header-bidding-request'; const TIMEOUT_MONITORING_HOST = 'https://ms-ads-monitoring-events.presage.io'; const MS_COOKIE_SYNC_DOMAIN = 'https://ms-cookie-sync.presage.io'; -const ADAPTER_VERSION = '1.2.13'; +const ADAPTER_VERSION = '1.3.0'; function getClientWidth() { const documentElementClientWidth = window.top.document.documentElement.clientWidth @@ -56,6 +56,10 @@ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { { type: 'image', url: `${MS_COOKIE_SYNC_DOMAIN}/ttd/init-sync?iab_string=${(gdprConsent && gdprConsent.consentString) || ''}&source=prebid` + }, + { + type: 'image', + url: `${MS_COOKIE_SYNC_DOMAIN}/xandr/init-sync?iab_string=${(gdprConsent && gdprConsent.consentString) || ''}&source=prebid` } ] } @@ -209,6 +213,6 @@ export const spec = { onBidWon, getWindowContext, onTimeout -}; +} registerBidder(spec); diff --git a/test/spec/modules/oguryBidAdapter_spec.js b/test/spec/modules/oguryBidAdapter_spec.js index 8871d2d0886..b9e4b44b571 100644 --- a/test/spec/modules/oguryBidAdapter_spec.js +++ b/test/spec/modules/oguryBidAdapter_spec.js @@ -119,26 +119,30 @@ describe('OguryBidAdapter', function () { }; }); - it('should return syncs array with two elements of type image', () => { + it('should return syncs array with three elements of type image', () => { const userSyncs = spec.getUserSyncs(syncOptions, [], gdprConsent); - expect(userSyncs).to.have.lengthOf(2); + expect(userSyncs).to.have.lengthOf(3); expect(userSyncs[0].type).to.equal('image'); expect(userSyncs[0].url).to.contain('https://ms-cookie-sync.presage.io/v1/init-sync/bid-switch'); expect(userSyncs[1].type).to.equal('image'); expect(userSyncs[1].url).to.contain('https://ms-cookie-sync.presage.io/ttd/init-sync'); + expect(userSyncs[2].type).to.equal('image'); + expect(userSyncs[2].url).to.contain('https://ms-cookie-sync.presage.io/xandr/init-sync'); }); it('should set the source as query param', () => { const userSyncs = spec.getUserSyncs(syncOptions, [], gdprConsent); expect(userSyncs[0].url).to.contain('source=prebid'); expect(userSyncs[1].url).to.contain('source=prebid'); + expect(userSyncs[2].url).to.contain('source=prebid'); }); it('should set the tcString as query param', () => { const userSyncs = spec.getUserSyncs(syncOptions, [], gdprConsent); expect(userSyncs[0].url).to.contain(`iab_string=${gdprConsent.consentString}`); expect(userSyncs[1].url).to.contain(`iab_string=${gdprConsent.consentString}`); + expect(userSyncs[2].url).to.contain(`iab_string=${gdprConsent.consentString}`); }); it('should return an empty array when pixel is disable', () => { @@ -146,82 +150,94 @@ describe('OguryBidAdapter', function () { expect(spec.getUserSyncs(syncOptions, [], gdprConsent)).to.have.lengthOf(0); }); - it('should return syncs array with two elements of type image when consentString is undefined', () => { + it('should return syncs array with three elements of type image when consentString is undefined', () => { gdprConsent = { gdprApplies: true, consentString: undefined }; const userSyncs = spec.getUserSyncs(syncOptions, [], gdprConsent); - expect(userSyncs).to.have.lengthOf(2); + expect(userSyncs).to.have.lengthOf(3); expect(userSyncs[0].type).to.equal('image'); expect(userSyncs[0].url).to.equal('https://ms-cookie-sync.presage.io/v1/init-sync/bid-switch?iab_string=&source=prebid') expect(userSyncs[1].type).to.equal('image'); expect(userSyncs[1].url).to.equal('https://ms-cookie-sync.presage.io/ttd/init-sync?iab_string=&source=prebid') + expect(userSyncs[2].type).to.equal('image'); + expect(userSyncs[2].url).to.equal('https://ms-cookie-sync.presage.io/xandr/init-sync?iab_string=&source=prebid') }); - it('should return syncs array with two elements of type image when consentString is null', () => { + it('should return syncs array with three elements of type image when consentString is null', () => { gdprConsent = { gdprApplies: true, consentString: null }; const userSyncs = spec.getUserSyncs(syncOptions, [], gdprConsent); - expect(userSyncs).to.have.lengthOf(2); + expect(userSyncs).to.have.lengthOf(3); expect(userSyncs[0].type).to.equal('image'); expect(userSyncs[0].url).to.equal('https://ms-cookie-sync.presage.io/v1/init-sync/bid-switch?iab_string=&source=prebid') expect(userSyncs[1].type).to.equal('image'); expect(userSyncs[1].url).to.equal('https://ms-cookie-sync.presage.io/ttd/init-sync?iab_string=&source=prebid') + expect(userSyncs[2].type).to.equal('image'); + expect(userSyncs[2].url).to.equal('https://ms-cookie-sync.presage.io/xandr/init-sync?iab_string=&source=prebid') }); - it('should return syncs array with two elements of type image when gdprConsent is undefined', () => { + it('should return syncs array with three elements of type image when gdprConsent is undefined', () => { gdprConsent = undefined; const userSyncs = spec.getUserSyncs(syncOptions, [], gdprConsent); - expect(userSyncs).to.have.lengthOf(2); + expect(userSyncs).to.have.lengthOf(3); expect(userSyncs[0].type).to.equal('image'); expect(userSyncs[0].url).to.equal('https://ms-cookie-sync.presage.io/v1/init-sync/bid-switch?iab_string=&source=prebid') expect(userSyncs[1].type).to.equal('image'); expect(userSyncs[1].url).to.equal('https://ms-cookie-sync.presage.io/ttd/init-sync?iab_string=&source=prebid') + expect(userSyncs[2].type).to.equal('image'); + expect(userSyncs[2].url).to.equal('https://ms-cookie-sync.presage.io/xandr/init-sync?iab_string=&source=prebid') }); - it('should return syncs array with two elements of type image when gdprConsent is null', () => { + it('should return syncs array with three elements of type image when gdprConsent is null', () => { gdprConsent = null; const userSyncs = spec.getUserSyncs(syncOptions, [], gdprConsent); - expect(userSyncs).to.have.lengthOf(2); + expect(userSyncs).to.have.lengthOf(3); expect(userSyncs[0].type).to.equal('image'); expect(userSyncs[0].url).to.equal('https://ms-cookie-sync.presage.io/v1/init-sync/bid-switch?iab_string=&source=prebid') expect(userSyncs[1].type).to.equal('image'); expect(userSyncs[1].url).to.equal('https://ms-cookie-sync.presage.io/ttd/init-sync?iab_string=&source=prebid') + expect(userSyncs[2].type).to.equal('image'); + expect(userSyncs[2].url).to.equal('https://ms-cookie-sync.presage.io/xandr/init-sync?iab_string=&source=prebid') }); - it('should return syncs array with two elements of type image when gdprConsent is null and gdprApplies is false', () => { + it('should return syncs array with three elements of type image when gdprConsent is null and gdprApplies is false', () => { gdprConsent = { gdprApplies: false, consentString: null }; const userSyncs = spec.getUserSyncs(syncOptions, [], gdprConsent); - expect(userSyncs).to.have.lengthOf(2); + expect(userSyncs).to.have.lengthOf(3); expect(userSyncs[0].type).to.equal('image'); expect(userSyncs[0].url).to.equal('https://ms-cookie-sync.presage.io/v1/init-sync/bid-switch?iab_string=&source=prebid') expect(userSyncs[1].type).to.equal('image'); expect(userSyncs[1].url).to.equal('https://ms-cookie-sync.presage.io/ttd/init-sync?iab_string=&source=prebid') + expect(userSyncs[2].type).to.equal('image'); + expect(userSyncs[2].url).to.equal('https://ms-cookie-sync.presage.io/xandr/init-sync?iab_string=&source=prebid') }); - it('should return syncs array with two elements of type image when gdprConsent is empty string and gdprApplies is false', () => { + it('should return syncs array with three elements of type image when gdprConsent is empty string and gdprApplies is false', () => { gdprConsent = { gdprApplies: false, consentString: '' }; const userSyncs = spec.getUserSyncs(syncOptions, [], gdprConsent); - expect(userSyncs).to.have.lengthOf(2); + expect(userSyncs).to.have.lengthOf(3); expect(userSyncs[0].type).to.equal('image'); expect(userSyncs[0].url).to.equal('https://ms-cookie-sync.presage.io/v1/init-sync/bid-switch?iab_string=&source=prebid') expect(userSyncs[1].type).to.equal('image'); expect(userSyncs[1].url).to.equal('https://ms-cookie-sync.presage.io/ttd/init-sync?iab_string=&source=prebid') + expect(userSyncs[2].type).to.equal('image'); + expect(userSyncs[2].url).to.equal('https://ms-cookie-sync.presage.io/xandr/init-sync?iab_string=&source=prebid') }); }); @@ -279,7 +295,7 @@ describe('OguryBidAdapter', function () { }, ext: { prebidversion: '$prebid.version$', - adapterversion: '1.2.13' + adapterversion: '1.3.0' }, device: { w: stubbedWidth, @@ -659,7 +675,7 @@ describe('OguryBidAdapter', function () { advertiserDomains: openRtbBidResponse.body.seatbid[0].bid[0].adomain }, nurl: openRtbBidResponse.body.seatbid[0].bid[0].nurl, - adapterVersion: '1.2.13', + adapterVersion: '1.3.0', prebidVersion: '$prebid.version$' }, { requestId: openRtbBidResponse.body.seatbid[0].bid[1].impid, @@ -676,7 +692,7 @@ describe('OguryBidAdapter', function () { advertiserDomains: openRtbBidResponse.body.seatbid[0].bid[1].adomain }, nurl: openRtbBidResponse.body.seatbid[0].bid[1].nurl, - adapterVersion: '1.2.13', + adapterVersion: '1.3.0', prebidVersion: '$prebid.version$' }] From 86bc747fa65c4ab0adeee2f136567fb0bf0dc9a1 Mon Sep 17 00:00:00 2001 From: haruka-yamashita2 <39541428+haruka-yamashita2@users.noreply.github.com> Date: Tue, 18 Oct 2022 04:31:35 +0900 Subject: [PATCH 023/367] Dac ID Module: (#9040) * update dacIdSystem module and related files * modify decoded id and related files * remove useless import * update dacIdSystem.md * fix the linting errors --- modules/dacIdSystem.js | 172 ++++++++++++++++--- modules/dacIdSystem.md | 9 +- modules/yieldoneBidAdapter.js | 11 +- test/spec/modules/dacIdSystem_spec.js | 104 +++++++++-- test/spec/modules/yieldoneBidAdapter_spec.js | 5 +- 5 files changed, 254 insertions(+), 47 deletions(-) diff --git a/modules/dacIdSystem.js b/modules/dacIdSystem.js index 73b5c7420cf..856e1976bb1 100644 --- a/modules/dacIdSystem.js +++ b/modules/dacIdSystem.js @@ -5,12 +5,111 @@ * @requires module:modules/userId */ -import { submodule } from '../src/hook.js'; -import { getStorageManager } from '../src/storageManager.js'; +import { + logError, + logInfo, + logWarn +} from '../src/utils.js'; +import { + ajax +} from '../src/ajax.js' +import { + submodule +} from '../src/hook.js'; +import { + getStorageManager +} from '../src/storageManager.js'; export const storage = getStorageManager(); -export const cookieKey = '_a1_f'; +export const FUUID_COOKIE_NAME = '_a1_f'; +export const AONEID_COOKIE_NAME = '_a1_d'; +export const API_URL = 'https://penta.a.one.impact-ad.jp/aud'; +const COOKIES_EXPIRES = 60 * 60 * 24 * 1000; // 24h +const LOG_PREFIX = 'User ID - dacId submodule: '; + +/** + * @returns {{fuuid: string, uid: string}} - + */ +function getCookieId() { + return { + fuuid: storage.getCookie(FUUID_COOKIE_NAME), + uid: storage.getCookie(AONEID_COOKIE_NAME) + }; +} + +/** + * set uid to cookie. + * @param {string} uid - + * @returns {void} - + */ +function setAoneidToCookie(uid) { + if (uid) { + const expires = new Date(Date.now() + COOKIES_EXPIRES).toUTCString(); + storage.setCookie( + AONEID_COOKIE_NAME, + uid, + expires, + 'none' + ); + } +} + +/** + * @param {string} oid - + * @param {string} fuuid - + * @returns {string} - + */ +function getApiUrl(oid, fuuid) { + return `${API_URL}?oid=${oid}&fu=${fuuid}`; +} + +/** + * @param {string} oid - + * @param {string} fuuid - + * @returns {{callback: function}} - + */ +function fetchAoneId(oid, fuuid) { + return { + callback: (callback) => { + const ret = { + fuuid, + uid: undefined + }; + const callbacks = { + success: (response) => { + if (response) { + try { + const responseObj = JSON.parse(response); + if (responseObj.error) { + logWarn(LOG_PREFIX + 'There is no permission to use API: ' + responseObj.error); + return callback(ret); + } + if (!responseObj.uid) { + logWarn(LOG_PREFIX + 'AoneId is null'); + return callback(ret); + } + ret.uid = responseObj.uid; + setAoneidToCookie(ret.uid); + } catch (error) { + logError(LOG_PREFIX + error); + } + } + callback(ret); + }, + error: (error) => { + logError(LOG_PREFIX + error); + callback(ret); + } + }; + const apiUrl = getApiUrl(oid, fuuid); + ajax(apiUrl, callbacks, undefined, { + method: 'GET', + withCredentials: true + }); + }, + }; +} export const dacIdSystemSubmodule = { /** @@ -20,38 +119,57 @@ export const dacIdSystemSubmodule = { name: 'dacId', /** - * performs action to obtain id - * @function - * @returns { {id: {dacId: string}} | undefined } + * decode the stored id value for passing to bid requests + * @param { {fuuid: string, uid: string} } id + * @returns { {dacId: {fuuid: string, dacId: string} } | undefined } */ - getId: function() { - const newId = storage.getCookie(cookieKey); - if (!newId) { - return undefined; - } - const result = { - dacId: newId + decode(id) { + if (id && typeof id === 'object') { + return { + dacId: { + fuuid: id.fuuid, + id: id.uid + } + } } - return {id: result}; }, /** - * decode the stored id value for passing to bid requests + * performs action to obtain id * @function - * @param { {dacId: string} } value - * @returns { {dacId: {id: string} } | undefined } + * @returns { {id: {fuuid: string, uid: string}} | undefined } */ - decode: function(value) { - if (value && typeof value === 'object') { - const result = {}; - if (value.dacId) { - result.id = value.dacId - } - return {dacId: result}; + getId(config) { + const cookie = getCookieId(); + + if (!cookie.fuuid) { + logInfo(LOG_PREFIX + 'There is no fuuid in cookie') + return undefined; } - return undefined; - }, -} + if (cookie.fuuid && cookie.uid) { + logInfo(LOG_PREFIX + 'There is fuuid and AoneId in cookie') + return { + id: { + fuuid: cookie.fuuid, + uid: cookie.uid + } + }; + } + + const configParams = (config && config.params) || {}; + if (!configParams || typeof configParams.oid !== 'string') { + logWarn(LOG_PREFIX + 'oid is not defined'); + return { + id: { + fuuid: cookie.fuuid, + uid: undefined + } + }; + } + + return fetchAoneId(configParams.oid, cookie.fuuid); + } +}; submodule('userId', dacIdSystemSubmodule); diff --git a/modules/dacIdSystem.md b/modules/dacIdSystem.md index 0239b4557e9..c78b8ff2741 100644 --- a/modules/dacIdSystem.md +++ b/modules/dacIdSystem.md @@ -1,7 +1,7 @@ ## AudienceOne User ID Submodule AudienceOne ID, provided by [D.A.Consortium Inc.](https://www.dac.co.jp/), is ID for ad targeting by using 1st party cookie. -Please contact D.A.Consortium Inc. before using this ID. +Please visit [https://solutions.dac.co.jp/audienceone](https://solutions.dac.co.jp/audienceone) and request your Owner ID to get started. ## Building Prebid with AudienceOne ID Support @@ -17,7 +17,10 @@ The following configuration parameters are available: pbjs.setConfig({ userSync: { userIds: [{ - name: 'dacId' + name: 'dacId', + params: { + 'oid': '55h67qm4ck37vyz5' + } }] } }); @@ -26,3 +29,5 @@ pbjs.setConfig({ | Param under userSync.userIds[] | Scope | Type | Description | Example | | --- | --- | --- | --- | --- | | name | Required | String | The name of this module. | `"dacId"` | +| params | Required | Object | Details of module params. | | +| params.oid | Required | String | This is the Owner ID value obtained via D.A.Consortium Inc. | `"55h67qm4ck37vyz5"` | \ No newline at end of file diff --git a/modules/yieldoneBidAdapter.js b/modules/yieldoneBidAdapter.js index c07911c9e1f..4c5f1687641 100644 --- a/modules/yieldoneBidAdapter.js +++ b/modules/yieldoneBidAdapter.js @@ -74,10 +74,13 @@ export const spec = { } // DACID - const dacId = deepAccess(bidRequest, 'userId.dacId.id'); - if (isStr(dacId) && !isEmpty(dacId)) { - payload.dac_id = dacId; - payload.fuuid = dacId; + const fuuid = deepAccess(bidRequest, 'userId.dacId.fuuid'); + const dacid = deepAccess(bidRequest, 'userId.dacId.id'); + if (isStr(fuuid) && !isEmpty(fuuid)) { + payload.fuuid = fuuid; + } + if (isStr(dacid) && !isEmpty(dacid)) { + payload.dac_id = dacid; } // ID5 diff --git a/test/spec/modules/dacIdSystem_spec.js b/test/spec/modules/dacIdSystem_spec.js index d78b4a69000..0246e65a310 100644 --- a/test/spec/modules/dacIdSystem_spec.js +++ b/test/spec/modules/dacIdSystem_spec.js @@ -1,8 +1,16 @@ -import { dacIdSystemSubmodule, storage, cookieKey } from 'modules/dacIdSystem.js'; +import { + dacIdSystemSubmodule, + storage, + FUUID_COOKIE_NAME, + AONEID_COOKIE_NAME +} from 'modules/dacIdSystem.js'; +import { server } from 'test/mocks/xhr.js'; -const DACID_DUMMY_VALUE = 'dacIdTest'; +const FUUID_DUMMY_VALUE = 'dacIdTest'; +const AONEID_DUMMY_VALUE = '12345' const DACID_DUMMY_OBJ = { - dacId: DACID_DUMMY_VALUE + fuuid: FUUID_DUMMY_VALUE, + uid: AONEID_DUMMY_VALUE }; describe('dacId module', function () { @@ -23,24 +31,98 @@ describe('dacId module', function () { '' ] + const configParamTestCase = { + params: { + oid: [ + '637c1b6fc26bfad0', // valid + 'e8316b39c08029e1' // invalid + ] + } + } + describe('getId()', function () { - it('should return the uid when it exists in cookie', function () { - getCookieStub.withArgs(cookieKey).returns(DACID_DUMMY_VALUE); + it('should return undefined when oid & fuuid not exist', function () { + // no oid, no fuuid const id = dacIdSystemSubmodule.getId(); - expect(id).to.be.deep.equal({id: {dacId: DACID_DUMMY_VALUE}}); + expect(id).to.equal(undefined); }); - cookieTestCasesForEmpty.forEach(testCase => it('should return the uid when it not exists in cookie', function () { - getCookieStub.withArgs(cookieKey).returns(testCase); + it('should return fuuid when oid not exists but fuuid exists', function () { + // no oid, fuuid + getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(FUUID_DUMMY_VALUE); const id = dacIdSystemSubmodule.getId(); - expect(id).to.be.deep.equal(undefined); + expect(id).to.be.deep.equal({ + id: { + fuuid: FUUID_DUMMY_VALUE, + uid: undefined + } + }); + }); + + it('should return fuuid when oid is invalid but fuuid exists', function () { + // invalid oid, fuuid, no AoneId + getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(FUUID_DUMMY_VALUE); + const id = dacIdSystemSubmodule.getId(configParamTestCase.params.oid[1]); + expect(id).to.be.deep.equal({ + id: { + fuuid: FUUID_DUMMY_VALUE, + uid: undefined + } + }); + }); + + cookieTestCasesForEmpty.forEach(testCase => it('should return undefined when fuuid not exists', function () { + // valid oid, no fuuid, no AoneId + getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(testCase); + const id = dacIdSystemSubmodule.getId(configParamTestCase.params.oid[0]); + expect(id).to.equal(undefined); })); + + it('should return AoneId when AoneId not exists', function () { + // valid oid, fuuid, no AoneId + getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(FUUID_DUMMY_VALUE); + const callbackSpy = sinon.spy(); + const callback = dacIdSystemSubmodule.getId({params: {oid: configParamTestCase.params.oid[0]}}).callback; + callback(callbackSpy); + const request = server.requests[0]; + request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({'uid': AONEID_DUMMY_VALUE})); + expect(callbackSpy.lastCall.lastArg).to.deep.equal({fuuid: 'dacIdTest', uid: AONEID_DUMMY_VALUE}); + }); + + cookieTestCasesForEmpty.forEach(testCase => it('should return undefined when AoneId not exists & API result is empty', function () { + // valid oid, fuuid, no AoneId, API result empty + getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(FUUID_DUMMY_VALUE); + const callbackSpy = sinon.spy(); + const callback = dacIdSystemSubmodule.getId({params: {oid: configParamTestCase.params.oid[0]}}).callback; + callback(callbackSpy); + const request = server.requests[0]; + request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({'uid': testCase})); + expect(callbackSpy.lastCall.lastArg).to.deep.equal({fuuid: 'dacIdTest', uid: undefined}); + })); + + it('should return the fuuid & AoneId when they exist', function () { + // valid oid, fuuid, AoneId + getCookieStub.withArgs(FUUID_COOKIE_NAME).returns(FUUID_DUMMY_VALUE); + getCookieStub.withArgs(AONEID_COOKIE_NAME).returns(AONEID_DUMMY_VALUE); + const id = dacIdSystemSubmodule.getId(configParamTestCase.params.oid[0]); + expect(id).to.be.deep.equal({ + id: { + fuuid: FUUID_DUMMY_VALUE, + uid: AONEID_DUMMY_VALUE + } + }); + }); }); describe('decode()', function () { - it('should return the uid when it exists in cookie', function () { + it('should return fuuid & AoneId when they exist', function () { const decoded = dacIdSystemSubmodule.decode(DACID_DUMMY_OBJ); - expect(decoded).to.be.deep.equal({dacId: {id: DACID_DUMMY_VALUE}}); + expect(decoded).to.be.deep.equal({ + dacId: { + fuuid: FUUID_DUMMY_VALUE, + id: AONEID_DUMMY_VALUE + } + }); }); it('should return the undefined when decode id is not "string"', function () { diff --git a/test/spec/modules/yieldoneBidAdapter_spec.js b/test/spec/modules/yieldoneBidAdapter_spec.js index e41764b2876..59bd4a80081 100644 --- a/test/spec/modules/yieldoneBidAdapter_spec.js +++ b/test/spec/modules/yieldoneBidAdapter_spec.js @@ -1,7 +1,6 @@ import { expect } from 'chai'; import { spec } from 'modules/yieldoneBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; -import { deepClone } from 'src/utils.js'; const ENDPOINT = 'https://y.one.impact-ad.jp/h_bid'; const USER_SYNC_URL = 'https://y.one.impact-ad.jp/push_sync'; @@ -428,12 +427,12 @@ describe('yieldoneBidAdapter', function() { const bidRequests = [ { params: {placementId: '0'}, - userId: {dacId: {id: 'dacId_sample'}}, + userId: {dacId: {fuuid: 'fuuid_sample', id: 'dacId_sample'}}, }, ]; const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request[0].data.fuuid).to.equal('fuuid_sample'); expect(request[0].data.dac_id).to.equal('dacId_sample'); - expect(request[0].data.fuuid).to.equal('dacId_sample'); }); }); From 5de1a29e0c8a69875d3da4cc52f6573b2899be6d Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Mon, 17 Oct 2022 15:41:09 -0400 Subject: [PATCH 024/367] TTD Bid Adapter: add support for site.ref & user.data (#9107) * Update ttdBidAdapter.js * Update ttdBidAdapter.js * Update ttdBidAdapter.js --- modules/ttdBidAdapter.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/ttdBidAdapter.js b/modules/ttdBidAdapter.js index 882f7e58960..a855c07dc86 100644 --- a/modules/ttdBidAdapter.js +++ b/modules/ttdBidAdapter.js @@ -121,12 +121,20 @@ function getUser(bidderRequest) { utils.deepSetValue(user, 'ext.eids', eids); } + // gather user.data + const ortb2UserData = utils.deepAccess(bidderRequest, 'ortb2.user.data'); + if (ortb2UserData && ortb2UserData.length) { + user = utils.mergeDeep(user, { + data: [...ortb2UserData] + }); + }; return user; } function getSite(bidderRequest, firstPartyData) { var site = { page: utils.deepAccess(bidderRequest, 'refererInfo.page'), + ref: utils.deepAccess(bidderRequest, 'refererInfo.ref'), publisher: { id: utils.deepAccess(bidderRequest, 'bids.0.params.publisherId'), }, From 86db8ebd1065a077af35eed57abde6274cb3da89 Mon Sep 17 00:00:00 2001 From: Luca Lavarini <89019372+luca1x@users.noreply.github.com> Date: Tue, 18 Oct 2022 00:04:59 +0200 Subject: [PATCH 025/367] init (#9115) --- modules/1plusXRtdProvider.js | 37 ++++++++++++++--- test/spec/modules/1plusXRtdProvider_spec.js | 44 ++++++++++++++------- 2 files changed, 62 insertions(+), 19 deletions(-) diff --git a/modules/1plusXRtdProvider.js b/modules/1plusXRtdProvider.js index 317bb4a47af..390f4f4cd81 100644 --- a/modules/1plusXRtdProvider.js +++ b/modules/1plusXRtdProvider.js @@ -13,6 +13,7 @@ const MODULE_NAME = '1plusX'; const ORTB2_NAME = '1plusX.com' const PAPI_VERSION = 'v1.0'; const LOG_PREFIX = '[1plusX RTD Module]: '; +const OPE_FPID = 'ope_fpid' const LEGACY_SITE_KEYWORDS_BIDDERS = ['appnexus']; export const segtaxes = { // cf. https://github.com/InteractiveAdvertisingBureau/openrtb/pull/108 @@ -57,6 +58,12 @@ export const extractConfig = (moduleConfig, reqBidsConfigObj) => { return { customerId, timeout, bidders }; } +/** + * Extracts consent from the prebid consent object and translates it + * into a 1plusX profile api query parameter parameter dict + * @param {object} prebid gdpr object + * @returns dictionary of papi gdpr query parameters + */ export const extractConsent = ({ gdpr }) => { if (!gdpr) { return null @@ -65,8 +72,8 @@ export const extractConsent = ({ gdpr }) => { if (!(gdprApplies == '0' || gdprApplies == '1')) { throw 'TCF Consent: gdprApplies has wrong format' } - if (!(typeof consentString === 'string')) { - throw 'TCF Consent: consentString is not string' + if (consentString && typeof consentString != 'string') { + throw 'TCF Consent: consentString must be string if defined' } const result = { 'gdpr_applies': gdprApplies, @@ -74,13 +81,30 @@ export const extractConsent = ({ gdpr }) => { } return result } + +/** + * Extracts the OPE first party id field from local storage + * @returns fpid string if found, else null + */ +export const extractFpid = () => { + try { + const fpid = window.localStorage.getItem(OPE_FPID); + if (fpid) { + return fpid; + } + return null; + } catch (error) { + return null; + } +} /** * Gets the URL of Profile Api from which targeting data will be fetched - * @param {Object} config * @param {string} config.customerId + * @param {object} consent query params as dict + * @param {string} oneplusx first party id (nullable) * @returns {string} URL to access 1plusX Profile API */ -export const getPapiUrl = (customerId, consent) => { +export const getPapiUrl = (customerId, consent, fpid) => { // https://[yourClientId].profiles.tagger.opecloud.com/[VERSION]/targeting?url= const currentUrl = encodeURIComponent(window.location.href); var papiUrl = `https://${customerId}.profiles.tagger.opecloud.com/${PAPI_VERSION}/targeting?url=${currentUrl}`; @@ -89,6 +113,9 @@ export const getPapiUrl = (customerId, consent) => { papiUrl += `&${key}=${value}` }) } + if (fpid) { + papiUrl += `&fpid=${fpid}` + } return papiUrl; } @@ -246,7 +273,7 @@ const getBidRequestData = (reqBidsConfigObj, callback, moduleConfig, userConsent // Get the required config const { customerId, bidders } = extractConfig(moduleConfig, reqBidsConfigObj); // Get PAPI URL - const papiUrl = getPapiUrl(customerId, extractConsent(userConsent) || {}) + const papiUrl = getPapiUrl(customerId, extractConsent(userConsent) || {}, extractFpid()) // Call PAPI getTargetingDataFromPapi(papiUrl) .then((papiResponse) => { diff --git a/test/spec/modules/1plusXRtdProvider_spec.js b/test/spec/modules/1plusXRtdProvider_spec.js index dae0e313387..496c005f470 100644 --- a/test/spec/modules/1plusXRtdProvider_spec.js +++ b/test/spec/modules/1plusXRtdProvider_spec.js @@ -9,6 +9,8 @@ import { extractConsent, getPapiUrl } from 'modules/1plusXRtdProvider'; +import assert from 'assert'; +import { extractFpid } from '../../../modules/1plusXRtdProvider'; describe('1plusXRtdProvider', () => { // Fake server config @@ -276,41 +278,50 @@ describe('1plusXRtdProvider', () => { it('throws an error if the consent is malformed', () => { const consent1 = { - gdpr: { - gdprApplies: 1 - } - } - const consent2 = { gdpr: { consentString: 'myConsent' } } - const consent3 = { + const consent2 = { gdpr: { gdprApplies: 1, consentString: 3 } } - const consent4 = { + const consent3 = { gdpr: { gdprApplies: 'yes', consentString: 'myConsent' } } - const consent5 = { - gdprApplies: 1, - consentString: 'myConsent' + const consent4 = { + gdpr: {} } - for (const consent in [consent1, consent2, consent3, consent4, consent5]) { + for (const consent of [consent1, consent2, consent3, consent4]) { + var failed = false; try { extractConsent(consent) - assert(false, 'Should be throwing an exception') - } catch (e) { } + } catch (e) { + failed = true; + } finally { + assert(failed, 'Should be throwing an exception') + } } }) }) + describe('extractFpid', () => { + it('correctly extracts an ope fpid if present', () => { + window.localStorage.setItem('ope_fpid', 'oneplusx_test_key') + const id1 = extractFpid() + window.localStorage.removeItem('ope_fpid') + const id2 = extractFpid() + expect(id1).to.equal('oneplusx_test_key') + expect(id2).to.equal(null) + }) + }) + describe('getPapiUrl', () => { const customer = 'acme' const consent = { @@ -320,11 +331,16 @@ describe('1plusXRtdProvider', () => { } } - it('correctly builds URLs based on consent', () => { + it('correctly builds URLs if gdpr parameters are present', () => { const url1 = getPapiUrl(customer) const url2 = getPapiUrl(customer, extractConsent(consent)) expect(['&consent_string=myConsent&gdpr_applies=1', '&gdpr_applies=1&consent_string=myConsent']).to.contain(url2.replace(url1, '')) }) + + it('correctly builds URLs if fpid parameters are present') + const url1 = getPapiUrl(customer) + const url2 = getPapiUrl(customer, {}, 'my_first_party_id') + expect(url2.replace(url1, '')).to.equal('&fpid=my_first_party_id') }) describe('updateBidderConfig', () => { From 4fc33aae6be21ace8ef81be176f8014390dcc7ae Mon Sep 17 00:00:00 2001 From: Ryan Schweitzer <50628828+r-schweitzer@users.noreply.github.com> Date: Tue, 18 Oct 2022 15:17:55 +0200 Subject: [PATCH 026/367] PBS Bid Adapter: alias Fix (#9100) * Added adjustment for aliasing unregistered bidders for server-side * removed import --- modules/prebidServerBidAdapter/index.js | 2 +- .../modules/prebidServerBidAdapter_spec.js | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 856b962e8a0..3a082b3199f 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -558,7 +558,7 @@ Object.assign(ORTB2.prototype, { const bidder = adapterManager.bidderRegistry[bid.bidder]; // adding alias only if alias source bidder exists and alias isn't configured to be standalone // pbs adapter - if (bidder && !bidder.getSpec().skipPbsAliasing) { + if (!bidder || !bidder.getSpec().skipPbsAliasing) { aliases[bid.bidder] = adapterManager.aliasRegistry[bid.bidder]; } } diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index b5209e5be12..4b9efa72e61 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1466,6 +1466,30 @@ describe('S2S Adapter', function () { }); }); + it('unregistered bidder should alias', function () { + const adjustedConfig = utils.deepClone(CONFIG); + adjustedConfig.bidders = 'bidderD' + config.setConfig({ s2sConfig: adjustedConfig }); + + const aliasBidder = { + bidder: 'bidderD', + params: { + unit: '10433394', + } + }; + + $$PREBID_GLOBAL$$.aliasBidder('mockBidder', aliasBidder.bidder); + + const request = utils.deepClone(REQUEST); + request.ad_units[0].bids = [aliasBidder]; + request.s2sConfig = adjustedConfig; + + adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax); + + const requestBid = JSON.parse(server.requests[0].requestBody); + expect(requestBid.ext.prebid.aliases).to.deep.equal({ bidderD: 'mockBidder' }); + }); + it('adds dynamic aliases to request', function () { config.setConfig({ s2sConfig: CONFIG }); From f351c708e7501adeb493b039e957257374e4c6d9 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 18 Oct 2022 06:28:59 -0700 Subject: [PATCH 027/367] Grid & MGID bid adapters: set `spec.gvlid` (#9124) --- modules/gridBidAdapter.js | 1 + modules/mgidBidAdapter.js | 1 + 2 files changed, 2 insertions(+) diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index e46d6e352fa..181ce0ebab2 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -39,6 +39,7 @@ let hasSynced = false; export const spec = { code: BIDDER_CODE, + gvlid: GVLID, aliases: ['playwire', 'adlivetech', { code: 'trustx', skipPbsAliasing: true }], supportedMediaTypes: [ BANNER, VIDEO ], /** diff --git a/modules/mgidBidAdapter.js b/modules/mgidBidAdapter.js index 2653f157196..bca9ae49892 100644 --- a/modules/mgidBidAdapter.js +++ b/modules/mgidBidAdapter.js @@ -66,6 +66,7 @@ _each(NATIVE_ASSETS, anAsset => { _NATIVE_ASSET_KEY_TO_ASSET_MAP[anAsset.KEY] = export const spec = { VERSION: '1.5', code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: [BANNER, NATIVE], reId: /^[1-9][0-9]*$/, NATIVE_ASSET_ID_TO_KEY_MAP: _NATIVE_ASSET_ID_TO_KEY_MAP, From caf162e083541eaaad9be52aee33020954e1138f Mon Sep 17 00:00:00 2001 From: Rocco Barbini <46724608+rbarbini-ias@users.noreply.github.com> Date: Tue, 18 Oct 2022 15:38:03 +0200 Subject: [PATCH 028/367] IAS RTD Module: custom adUnitPath mapping (#9058) * maintainer updated * getAdUnitPath extracted to manage the adUnitPath option getAdUnitPath obtains the p parameter using the exact same technique used before. After obtaining it, it checks if there is an adUnitPath configuration parameter, and if it has a non-empty string mapped to a property named like the ad slot id. If and only if this is the case, it overwrites the p parameter with that string. Since different adservers may have different conventions, no check is run on the formatting of the ad unit path proper. * faster getAdUnitPath logic Only check the map if a value was not retrieved "the usual way". Use utils functions instead of vanilla JavaScript. * faster getAdUnitPath logic Only check the map if a value was not retrieved "the usual way". Use utils functions instead of vanilla JavaScript. * removed unnecessary comment * updated the maintainer email --- modules/iasRtdProvider.js | 27 ++++++++--- modules/iasRtdProvider.md | 2 +- test/spec/modules/iasRtdProvider_spec.js | 58 +++++++++++++++++++++++- 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/modules/iasRtdProvider.js b/modules/iasRtdProvider.js index 605fff8898e..994be7c0804 100644 --- a/modules/iasRtdProvider.js +++ b/modules/iasRtdProvider.js @@ -38,7 +38,7 @@ const IAS_KEY_MAPPINGS = { /** * Module init - * @param {Object} provider + * @param {Object} config * @param {Object} userConsent * @return {boolean} */ @@ -71,12 +71,26 @@ function stringifySlotSizes(sizes) { return result; } -function stringifySlot(bidRequest) { +function getAdUnitPath(adSlot, bidRequest, adUnitPath) { + let p = bidRequest.code; + if (!utils.isEmpty(adSlot)) { + p = adSlot.gptSlot; + } else { + if (!utils.isEmpty(adUnitPath) && utils.hasOwn(adUnitPath, bidRequest.code)) { + if (utils.isStr(adUnitPath[bidRequest.code]) && !utils.isEmpty(adUnitPath[bidRequest.code])) { + p = adUnitPath[bidRequest.code]; + } + } + } + return p; +} + +function stringifySlot(bidRequest, adUnitPath) { const sizes = utils.getAdUnitSizes(bidRequest); const id = bidRequest.code; const ss = stringifySlotSizes(sizes); const adSlot = utils.getGptSlotInfoForAdUnitCode(bidRequest.code); - const p = utils.isEmpty(adSlot) ? bidRequest.code : adSlot.gptSlot; + const p = getAdUnitPath(adSlot, bidRequest, adUnitPath); const slot = { id, ss, p }; const keyValues = utils.getKeys(slot).map(function (key) { return [key, slot[key]].join(':'); @@ -119,12 +133,12 @@ function formatTargetingData(adUnit) { return renameKeyValues(result); } -function constructQueryString(anId, adUnits, pageUrl) { +function constructQueryString(anId, adUnits, pageUrl, adUnitPath) { let queries = []; queries.push(['anId', anId]); queries = queries.concat(adUnits.reduce(function (acc, request) { - acc.push(['slot', stringifySlot(request)]); + acc.push(['slot', stringifySlot(request, adUnitPath)]); return acc; }, [])); @@ -191,10 +205,11 @@ function getBidRequestData(reqBidsConfigObj, callback, config, userConsent) { const adUnits = reqBidsConfigObj.adUnits || getGlobal().adUnits; const { pubId } = config.params; let { pageUrl } = config.params; + const { adUnitPath } = config.params; if (!isValidHttpUrl(pageUrl)) { pageUrl = document.location.href; } - const queryString = constructQueryString(pubId, adUnits, pageUrl); + const queryString = constructQueryString(pubId, adUnits, pageUrl, adUnitPath); ajax( `${IAS_HOST}?${queryString}`, getApiCallback(), diff --git a/modules/iasRtdProvider.md b/modules/iasRtdProvider.md index d8c46ff2697..be47822eb58 100644 --- a/modules/iasRtdProvider.md +++ b/modules/iasRtdProvider.md @@ -2,7 +2,7 @@ Module Name: Integral Ad Science(IAS) Rtd Provider Module Type: Rtd Provider -Maintainer: raguilar@integralads.com +Maintainer: punereporting@integralads.com # Description diff --git a/test/spec/modules/iasRtdProvider_spec.js b/test/spec/modules/iasRtdProvider_spec.js index feb4c1093a8..ec4d2bd437a 100644 --- a/test/spec/modules/iasRtdProvider_spec.js +++ b/test/spec/modules/iasRtdProvider_spec.js @@ -54,6 +54,59 @@ describe('iasRtdProvider is a RTD provider that', function () { const value = iasSubModule.init(config); expect(value).to.equal(true); }); + it('returns true with the pubId, keyMappings and adUnitPath params', function () { + const config = { + name: 'ias', + waitForIt: true, + params: { + pubId: '123456', + keyMappings: { + 'id': 'ias_id' + }, + adUnitPath: {'one-div-id': '/012345/ad/unit/path'} + } + }; + const value = iasSubModule.init(config); + expect(value).to.equal(true); + }); + it('returns true with the pubId and adUnitPath params with multiple keys', function () { + const config = { + name: 'ias', + waitForIt: true, + params: { + pubId: '123456', + keyMappings: { + 'id': 'ias_id' + }, + adUnitPath: { + 'one-div-id': '/012345/ad/unit/path', + 'another-div-id': '/012345/ad/unit/path', + 'third-div-id': '/012345/another/ad/unit/path' + } + } + }; + const value = iasSubModule.init(config); + expect(value).to.equal(true); + }); + it('returns true with the pubId and adUnitPath params with empty values', function () { + const config = { + name: 'ias', + waitForIt: true, + params: { + pubId: '123456', + keyMappings: { + 'id': 'ias_id' + }, + adUnitPath: { + 'one-div-id': '/012345/ad/unit/path', + 'another-div-id': '', + 'third-div-id': '' + } + } + }; + const value = iasSubModule.init(config); + expect(value).to.equal(true); + }); }); describe('has a method `getBidRequestData` that', function () { it('exists', function () { @@ -138,7 +191,10 @@ const config = { keyMappings: { 'id': 'ias_id' }, - pageUrl: 'https://integralads.com/test' + pageUrl: 'https://integralads.com/test', + adUnitPath: { + 'one-div-id': '/012345/ad/unit/path' + } } }; From e1aee0827ed5c7ba7bd402d649d84c941fdd5b26 Mon Sep 17 00:00:00 2001 From: Adish Rao <30475159+adish1997@users.noreply.github.com> Date: Tue, 18 Oct 2022 20:44:54 +0530 Subject: [PATCH 029/367] Medianet Bid Adapter: added AAX bidder alias (#9095) * added aax bidder alias * added test for aax alias Co-authored-by: adish --- modules/medianetBidAdapter.js | 6 +- test/spec/modules/medianetBidAdapter_spec.js | 76 ++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/modules/medianetBidAdapter.js b/modules/medianetBidAdapter.js index d19862d2f64..01652a3fac0 100644 --- a/modules/medianetBidAdapter.js +++ b/modules/medianetBidAdapter.js @@ -47,6 +47,10 @@ mnData.urlData = { isTop: refererInfo.reachedTop }; +const aliases = [ + { code: 'aax', gvlid: 720 }, +]; + $$PREBID_GLOBAL$$.medianetGlobals = $$PREBID_GLOBAL$$.medianetGlobals || {}; function getTopWindowReferrer() { @@ -418,7 +422,7 @@ export const spec = { code: BIDDER_CODE, gvlid: 142, - + aliases, supportedMediaTypes: [BANNER, NATIVE, VIDEO], /** diff --git a/test/spec/modules/medianetBidAdapter_spec.js b/test/spec/modules/medianetBidAdapter_spec.js index 7333900eedf..9180bbad68c 100644 --- a/test/spec/modules/medianetBidAdapter_spec.js +++ b/test/spec/modules/medianetBidAdapter_spec.js @@ -856,25 +856,50 @@ let VALID_BID_REQUEST = [{ cid: '8CUV090' } }, + VALID_PARAMS_AAX = { + bidder: 'aax', + params: { + cid: 'AAXG123' + } + }, PARAMS_MISSING = { bidder: 'medianet', }, + PARAMS_MISSING_AAX = { + bidder: 'aax', + }, PARAMS_WITHOUT_CID = { bidder: 'medianet', params: {} }, + PARAMS_WITHOUT_CID_AAX = { + bidder: 'aax', + params: {} + }, PARAMS_WITH_INTEGER_CID = { bidder: 'medianet', params: { cid: 8867587 } }, + PARAMS_WITH_INTEGER_CID_AAX = { + bidder: 'aax', + params: { + cid: 8867587 + } + }, PARAMS_WITH_EMPTY_CID = { bidder: 'medianet', params: { cid: '' } }, + PARAMS_WITH_EMPTY_CID_AAX = { + bidder: 'aax', + params: { + cid: '' + } + }, SYNC_OPTIONS_BOTH_ENABLED = { iframeEnabled: true, pixelEnabled: true, @@ -1571,4 +1596,55 @@ describe('Media.net bid adapter', function () { expect(requestObj.imp[0].hasOwnProperty('bidfloors')).to.equal(true); }); }); + + describe('isBidRequestValid aax', function () { + it('should accept valid bid params', function () { + let isValid = spec.isBidRequestValid(VALID_PARAMS_AAX); + expect(isValid).to.equal(true); + }); + + it('should reject bid if cid is not present', function () { + let isValid = spec.isBidRequestValid(PARAMS_WITHOUT_CID_AAX); + expect(isValid).to.equal(false); + }); + + it('should reject bid if cid is not a string', function () { + let isValid = spec.isBidRequestValid(PARAMS_WITH_INTEGER_CID_AAX); + expect(isValid).to.equal(false); + }); + + it('should reject bid if cid is a empty string', function () { + let isValid = spec.isBidRequestValid(PARAMS_WITH_EMPTY_CID_AAX); + expect(isValid).to.equal(false); + }); + + it('should have missing params', function () { + let isValid = spec.isBidRequestValid(PARAMS_MISSING_AAX); + expect(isValid).to.equal(false); + }); + }); + + describe('interpretResponse aax', function () { + it('should not push response if no-bid', function () { + let validBids = []; + let bids = spec.interpretResponse(SERVER_RESPONSE_NOBID, []); + expect(bids).to.deep.equal(validBids); + }); + + it('should have empty bid response', function() { + let bids = spec.interpretResponse(SERVER_RESPONSE_NOBODY, []); + expect(bids).to.deep.equal([]); + }); + + it('should have valid bids', function () { + let bids = spec.interpretResponse(SERVER_RESPONSE_VALID_BID, []); + expect(bids).to.deep.equal(SERVER_VALID_BIDS); + }); + + it('should have empty bid list', function() { + let validBids = []; + let bids = spec.interpretResponse(SERVER_RESPONSE_EMPTY_BIDLIST, []); + expect(bids).to.deep.equal(validBids); + }); + }); }); From f1131296d9ac6169d6bae602b19f8e59a7cacd23 Mon Sep 17 00:00:00 2001 From: Alexandru Date: Tue, 18 Oct 2022 18:19:39 +0300 Subject: [PATCH 030/367] Brightcom Bid adapter: add support for uspConsent, coppa, schain, userIdAsEids, userId (#9063) * Brightcom: add support for uspConsent, coppa, schain, userIdAsEids, userId * Brightcom: tests for updates --- modules/brightcomBidAdapter.js | 40 ++++++-- test/spec/modules/brightcomBidAdapter_spec.js | 95 ++++++++++++++++++- 2 files changed, 124 insertions(+), 11 deletions(-) diff --git a/modules/brightcomBidAdapter.js b/modules/brightcomBidAdapter.js index 64b3c3a9fc8..bbe0203772a 100644 --- a/modules/brightcomBidAdapter.js +++ b/modules/brightcomBidAdapter.js @@ -75,6 +75,26 @@ function buildRequests(bidReqs, bidderRequest) { deepSetValue(brightcomBidReq, 'user.ext.consent', bidderRequest.gdprConsent.consentString); } + if (bidderRequest && bidderRequest.uspConsent) { + deepSetValue(brightcomBidReq, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + + if (config.getConfig('coppa') === true) { + deepSetValue(brightcomBidReq, 'regs.coppa', 1); + } + + if (bidReqs[0] && bidReqs[0].schain) { + deepSetValue(brightcomBidReq, 'source.ext.schain', bidReqs[0].schain) + } + + if (bidReqs[0] && bidReqs[0].userIdAsEids) { + deepSetValue(brightcomBidReq, 'user.ext.eids', bidReqs[0].userIdAsEids || []) + } + + if (bidReqs[0] && bidReqs[0].userId) { + deepSetValue(brightcomBidReq, 'user.ext.ids', bidReqs[0].userId || []) + } + return { method: 'POST', url: URL, @@ -103,7 +123,7 @@ function interpretResponse(serverResponse) { logWarn('Brightcom server returned empty/non-json response: ' + JSON.stringify(serverResponse.body)); return []; } - const { body: {id, seatbid} } = serverResponse; + const {body: {id, seatbid}} = serverResponse; try { const brightcomBidResponses = []; if (id && @@ -164,9 +184,9 @@ function _isViewabilityMeasurable(element) { return !_isIframe() && element !== null; } -function _getViewability(element, topWin, { w, h } = {}) { +function _getViewability(element, topWin, {w, h} = {}) { return getWindowTop().document.visibilityState === 'visible' - ? _getPercentInView(element, topWin, { w, h }) + ? _getPercentInView(element, topWin, {w, h}) : 0; } @@ -182,8 +202,8 @@ function _getMinSize(sizes) { return sizes.reduce((min, size) => size.h * size.w < min.h * min.w ? size : min); } -function _getBoundingBox(element, { w, h } = {}) { - let { width, height, left, top, right, bottom } = element.getBoundingClientRect(); +function _getBoundingBox(element, {w, h} = {}) { + let {width, height, left, top, right, bottom} = element.getBoundingClientRect(); if ((width === 0 || height === 0) && w && h) { width = w; @@ -192,7 +212,7 @@ function _getBoundingBox(element, { w, h } = {}) { bottom = top + h; } - return { width, height, left, top, right, bottom }; + return {width, height, left, top, right, bottom}; } function _getIntersectionOfRects(rects) { @@ -225,16 +245,16 @@ function _getIntersectionOfRects(rects) { return bbox; } -function _getPercentInView(element, topWin, { w, h } = {}) { - const elementBoundingBox = _getBoundingBox(element, { w, h }); +function _getPercentInView(element, topWin, {w, h} = {}) { + const elementBoundingBox = _getBoundingBox(element, {w, h}); // Obtain the intersection of the element and the viewport - const elementInViewBoundingBox = _getIntersectionOfRects([ { + const elementInViewBoundingBox = _getIntersectionOfRects([{ left: 0, top: 0, right: topWin.innerWidth, bottom: topWin.innerHeight - }, elementBoundingBox ]); + }, elementBoundingBox]); let elementInViewArea, elementTotalArea; diff --git a/test/spec/modules/brightcomBidAdapter_spec.js b/test/spec/modules/brightcomBidAdapter_spec.js index 9354544ee5a..1ae73708d00 100644 --- a/test/spec/modules/brightcomBidAdapter_spec.js +++ b/test/spec/modules/brightcomBidAdapter_spec.js @@ -2,6 +2,7 @@ import { expect } from 'chai'; import * as utils from 'src/utils.js'; import { spec } from 'modules/brightcomBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; +import {config} from '../../../src/config'; const URL = 'https://brightcombid.marphezis.com/hb'; @@ -52,7 +53,21 @@ describe('brightcomBidAdapter', function() { }, 'bidId': '5fb26ac22bde4', 'bidderRequestId': '4bf93aeb730cb9', - 'auctionId': 'ffe9a1f7-7b67-4bda-a8e0-9ee5dc9f442e' + 'auctionId': 'ffe9a1f7-7b67-4bda-a8e0-9ee5dc9f442e', + 'schain': { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'exchange1.com', + 'sid': '1234', + 'hp': 1, + 'rid': 'bid-request-1', + 'name': 'publisher', + 'domain': 'publisher.com' + } + ] + }, }]; sandbox = sinon.sandbox.create(); @@ -167,6 +182,84 @@ describe('brightcomBidAdapter', function() { expect(data.user.ext.consent).to.equal(consentString); }); + it('sends us_privacy', function () { + const bidderRequest = { + uspConsent: '1YYY' + }; + const data = JSON.parse(spec.buildRequests(bidRequests, bidderRequest).data) + + expect(data.regs).to.not.equal(null); + expect(data.regs.ext).to.not.equal(null); + expect(data.regs.ext.us_privacy).to.equal('1YYY'); + }); + + it('sends coppa', function () { + sandbox.stub(config, 'getConfig').withArgs('coppa').returns(true); + + const data = JSON.parse(spec.buildRequests(bidRequests).data) + expect(data.regs).to.not.be.undefined; + expect(data.regs.coppa).to.equal(1); + }); + + it('sends schain', function () { + const data = JSON.parse(spec.buildRequests(bidRequests).data); + expect(data).to.not.be.undefined; + expect(data.source).to.not.be.undefined; + expect(data.source.ext).to.not.be.undefined; + expect(data.source.ext.schain).to.not.be.undefined; + expect(data.source.ext.schain.complete).to.equal(1); + expect(data.source.ext.schain.ver).to.equal('1.0'); + expect(data.source.ext.schain.nodes).to.not.be.undefined; + expect(data.source.ext.schain.nodes).to.lengthOf(1); + expect(data.source.ext.schain.nodes[0].asi).to.equal('exchange1.com'); + expect(data.source.ext.schain.nodes[0].sid).to.equal('1234'); + expect(data.source.ext.schain.nodes[0].hp).to.equal(1); + expect(data.source.ext.schain.nodes[0].rid).to.equal('bid-request-1'); + expect(data.source.ext.schain.nodes[0].name).to.equal('publisher'); + expect(data.source.ext.schain.nodes[0].domain).to.equal('publisher.com'); + }); + + it('sends user eid parameters', function () { + bidRequests[0].userIdAsEids = [{ + source: 'pubcid.org', + uids: [{ + id: 'userid_pubcid' + }] + }, { + source: 'adserver.org', + uids: [{ + id: 'userid_ttd', + ext: { + rtiPartner: 'TDID' + } + }] + } + ]; + + const data = JSON.parse(spec.buildRequests(bidRequests).data); + + expect(data.user).to.not.be.undefined; + expect(data.user.ext).to.not.be.undefined; + expect(data.user.ext.eids).to.not.be.undefined; + expect(data.user.ext.eids).to.deep.equal(bidRequests[0].userIdAsEids); + }); + + it('sends user id parameters', function () { + const userId = { + sharedid: { + id: '01*******', + third: '01E*******' + } + }; + + bidRequests[0].userId = userId; + + const data = JSON.parse(spec.buildRequests(bidRequests).data); + expect(data.user).to.not.be.undefined; + expect(data.user.ext).to.not.be.undefined; + expect(data.user.ext.ids).is.deep.equal(userId); + }); + context('when element is fully in view', function() { it('returns 100', function() { Object.assign(element, { width: 600, height: 400 }); From fcd1e3c01ef922d52ff3f221cbd1561033575107 Mon Sep 17 00:00:00 2001 From: Stephen Johnston Date: Tue, 18 Oct 2022 13:43:36 -0400 Subject: [PATCH 031/367] PubWise Bid Adapter: clean up and updates to adUnit parsing (#9066) * add pubwise bid adpater updates * Update pubwiseBidAdapter_spec.js * updates for feedback from review, adding imp.ext.tid and source.tid from appropriate locations --- modules/pubwiseBidAdapter.js | 26 +++++++++++---------- test/spec/modules/pubwiseBidAdapter_spec.js | 10 ++++---- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/modules/pubwiseBidAdapter.js b/modules/pubwiseBidAdapter.js index 7721fe10459..5e381e74a18 100644 --- a/modules/pubwiseBidAdapter.js +++ b/modules/pubwiseBidAdapter.js @@ -2,8 +2,7 @@ import { _each, isStr, deepClone, isArray, deepSetValue, inIframe, logMessage, l import { config } from '../src/config.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, NATIVE } from '../src/mediaTypes.js'; -import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; -const VERSION = '0.1.0'; +const VERSION = '0.2.0'; const GVLID = 842; const NET_REVENUE = true; const UNDEFINED = undefined; @@ -117,9 +116,6 @@ export const spec = { * @return ServerRequest Info describing the request to the server. */ buildRequests: function (validBidRequests, bidderRequest) { - // convert Native ORTB definition to old-style prebid native definition - validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); - var refererInfo; if (bidderRequest && bidderRequest.refererInfo) { refererInfo = bidderRequest.refererInfo; @@ -170,7 +166,7 @@ export const spec = { payload.user.geo.lon = _parseSlotParam('lon', conf.lon); payload.user.yob = _parseSlotParam('yob', conf.yob); payload.device.geo = payload.user.geo; - payload.site.page = payload.site.page.trim(); + payload.site.page = payload.site?.page?.trim(); payload.site.domain = _getDomainFromURL(payload.site.page); // add the content object from config in request @@ -184,7 +180,7 @@ export const spec = { } // passing transactionId in source.tid - deepSetValue(payload, 'source.tid', conf.transactionId); + deepSetValue(payload, 'source.tid', bidderRequest?.auctionId); // schain if (validBidRequests[0].schain) { @@ -440,7 +436,10 @@ function _createImpressionObject(bid, conf) { tagid: bid.params.adUnit || undefined, bidfloor: _parseSlotParam('bidFloor', bid.params.bidFloor), // capitalization dicated by 3.2.4 spec secure: 1, - bidfloorcur: bid.params.currency ? _parseSlotParam('currency', bid.params.currency) : DEFAULT_CURRENCY // capitalization dicated by 3.2.4 spec + bidfloorcur: bid.params.currency ? _parseSlotParam('currency', bid.params.currency) : DEFAULT_CURRENCY, // capitalization dicated by 3.2.4 spec + ext: { + tid: (bid.transactionId ? bid.transactionId : '') + } }; if (bid.hasOwnProperty('mediaTypes')) { @@ -494,7 +493,11 @@ function _parseSlotParam(paramName, paramValue) { function _parseAdSlot(bid) { _logInfo('parseAdSlot bid', bid) - bid.params.adUnit = ''; + if (bid.adUnitCode) { + bid.params.adUnit = bid.adUnitCode; + } else { + bid.params.adUnit = ''; + } bid.params.width = 0; bid.params.height = 0; bid.params.adSlot = _cleanSlotName(bid.params.adSlot); @@ -532,9 +535,8 @@ function _cleanSlotName(slotName) { function _initConf(refererInfo) { return { - // TODO: do the fallbacks make sense here? - pageURL: refererInfo?.page || window.location.href, - refURL: refererInfo?.ref || window.document.referrer + pageURL: refererInfo?.page, + refURL: refererInfo?.ref }; } diff --git a/test/spec/modules/pubwiseBidAdapter_spec.js b/test/spec/modules/pubwiseBidAdapter_spec.js index 1cf7a7dd280..d7b7a527485 100644 --- a/test/spec/modules/pubwiseBidAdapter_spec.js +++ b/test/spec/modules/pubwiseBidAdapter_spec.js @@ -238,7 +238,7 @@ const sampleBidderBannerRequest = { 'bidFloor': '1.00', 'currency': 'USD', 'adSlot': '', - 'adUnit': '', + 'adUnit': 'div-gpt-ad-1460505748561-0', 'bcat': [ 'IAB25-3', 'IAB26-1', @@ -535,13 +535,15 @@ describe('PubWiseAdapter', function () { describe('Handling Request Construction', function () { it('bid requests are not mutable', function() { - let sourceBidRequest = utils.deepClone(sampleValidBidRequests) - spec.buildRequests(sampleValidBidRequests, {auctinId: 'placeholder'}); + let sourceBidRequest = utils.deepClone(sampleValidBidRequests); + spec.buildRequests(sampleValidBidRequests, {auctionId: 'placeholder'}); expect(sampleValidBidRequests).to.deep.equal(sourceBidRequest, 'Should be unedited as they are used elsewhere'); }); it('should handle complex bidRequest', function() { let request = spec.buildRequests(sampleValidBidRequests, sampleBidderRequest); - expect(request.bidderRequest).to.equal(sampleBidderRequest); + expect(request.bidderRequest).to.equal(sampleBidderRequest, "Bid Request Doesn't Match Sample"); + expect(request.data.source.tid).to.equal(sampleBidderRequest.auctionId, 'AuctionId -> source.tid Mismatch'); + expect(request.data.imp[0].ext.tid).to.equal(sampleBidderRequest.bids[0].transactionId, 'TransactionId -> ext.tid Mismatch'); }); it('must conform to API for buildRequests', function() { let request = spec.buildRequests(sampleValidBidRequests); From c5ffc77fef16f7e956631d3af716d0c5e72c49de Mon Sep 17 00:00:00 2001 From: Anand Venkatraman Date: Wed, 19 Oct 2022 06:44:08 -0400 Subject: [PATCH 032/367] PulsePoint Bid Adapter: First party data (#9114) * ET-1691: Pulsepoint Analytics adapter for Prebid. (#1) * ET-1691: Adding pulsepoint analytics and tests for pulsepoint adapter * ET-1691: Adding pulsepoint analytics and tests for pulsepoint adapter * ET-1691: cleanup * ET-1691: minor * ET-1691: revert package.json change * Adding bidRequest to bidFactory.createBid method as per https://github.com/prebid/Prebid.js/issues/509 * ET-1765: Adding support for additional params in PulsePoint adapter (#2) * ET-1850: Fixing https://github.com/prebid/Prebid.js/issues/866 * Minor fix * Adding mandatory parameters to Bid * PulsePoint: Firstparty data support --- modules/pulsepointBidAdapter.js | 17 ++- .../spec/modules/pulsepointBidAdapter_spec.js | 123 ++++++++++++++++++ 2 files changed, 134 insertions(+), 6 deletions(-) diff --git a/modules/pulsepointBidAdapter.js b/modules/pulsepointBidAdapter.js index 52931be0078..25f82fb60d9 100644 --- a/modules/pulsepointBidAdapter.js +++ b/modules/pulsepointBidAdapter.js @@ -153,6 +153,8 @@ function bidResponseAvailable(request, response) { * Produces an OpenRTBImpression from a slot config. */ function impression(slot) { + var firstPartyData = slot.ortb2Imp?.ext || {}; + var ext = Object.assign({}, firstPartyData, slotUnknownParams(slot)); return { id: slot.bidId, banner: banner(slot), @@ -160,7 +162,7 @@ function impression(slot) { tagid: slot.params.ct.toString(), video: video(slot), bidfloor: bidFloor(slot), - ext: ext(slot), + ext: Object.keys(ext).length > 0 ? ext : null, }; } @@ -209,7 +211,7 @@ function video(slot) { /** * Unknown params are captured and sent on ext */ -function ext(slot) { +function slotUnknownParams(slot) { const ext = {}; const knownParamsMap = {}; KNOWN_PARAMS.forEach(value => knownParamsMap[value] = 1); @@ -330,14 +332,16 @@ function site(bidRequests, bidderRequest) { const pubId = bidRequests && bidRequests.length > 0 ? bidRequests[0].params.cp : '0'; const appParams = bidRequests[0].params.app; if (!appParams) { - return { + // use the first party data if available, and override only publisher/ref/page properties + var firstPartyData = bidderRequest?.ortb2?.site || {}; + return Object.assign({}, firstPartyData, { publisher: { id: pubId.toString(), }, // TODO: does the fallback make sense here? ref: bidderRequest?.refererInfo?.ref || window.document.referrer, page: bidderRequest?.refererInfo?.page || '' - } + }); } return null; } @@ -406,7 +410,8 @@ function adSize(slot, sizes) { * an openrtb User object. */ function user(bidRequest, bidderRequest) { - var ext = {}; + var user = bidderRequest?.ortb2?.user || { ext: {} }; + var ext = user.ext; if (bidderRequest) { if (bidderRequest.gdprConsent) { ext.consent = bidderRequest.gdprConsent.consentString; @@ -418,7 +423,7 @@ function user(bidRequest, bidderRequest) { ext.eids = eids; } } - return { ext }; + return user; } /** diff --git a/test/spec/modules/pulsepointBidAdapter_spec.js b/test/spec/modules/pulsepointBidAdapter_spec.js index 4426c91e1ec..825b3abf432 100644 --- a/test/spec/modules/pulsepointBidAdapter_spec.js +++ b/test/spec/modules/pulsepointBidAdapter_spec.js @@ -795,4 +795,127 @@ describe('PulsePoint Adapter Tests', function () { expect(ortbRequest.imp[0].video.minbitrate).to.equal(200); expect(ortbRequest.imp[0].video.protocols).to.eql([1, 2, 4]); }); + it('Verify user level first party data', function () { + const bidderRequest = { + refererInfo: { + page: 'https://publisher.com/home', + ref: 'https://referrer' + }, + gdprConsent: { + gdprApplies: true, + consentString: 'serialized_gpdr_data' + }, + ortb2: { + user: { + yob: 1985, + gender: 'm', + ext: { + data: { + registered: true, + interests: ['cars'] + } + } + } + } + }; + let request = spec.buildRequests(slotConfigs, bidderRequest); + let ortbRequest = request.data; + expect(ortbRequest).to.not.equal(null); + expect(ortbRequest.user).to.not.equal(null); + expect(ortbRequest.user).to.deep.equal({ + yob: 1985, + gender: 'm', + ext: { + data: { + registered: true, + interests: ['cars'] + }, + consent: 'serialized_gpdr_data' + } + }); + }); + it('Verify site level first party data', function () { + const bidderRequest = { + refererInfo: { + page: 'https://publisher.com/home', + ref: 'https://referrer' + }, + ortb2: { + site: { + content: { + data: [{ + name: 'www.iris.com', + ext: { + segtax: 500, + cids: ['iris_c73g5jq96mwso4d8'] + } + }] + }, + page: 'http://pub.com/news', + ref: 'http://google.com' + } + } + }; + let request = spec.buildRequests(slotConfigs, bidderRequest); + let ortbRequest = request.data; + expect(ortbRequest).to.not.equal(null); + expect(ortbRequest.site).to.not.equal(null); + expect(ortbRequest.site).to.deep.equal({ + content: { + data: [{ + name: 'www.iris.com', + ext: { + segtax: 500, + cids: ['iris_c73g5jq96mwso4d8'] + } + }] + }, + page: 'https://publisher.com/home', + ref: 'https://referrer', + publisher: { + id: 'p10000' + } + }); + }); + it('Verify impression/slot level first party data', function () { + const bidderRequests = [{ + placementCode: '/DfpAccount1/slot1', + mediaTypes: { + banner: { + sizes: [[1, 1]] + } + }, + bidId: 'bid12345', + params: { + cp: 'p10000', + ct: 't10000', + extra_key1: 'extra_val1', + extra_key2: 12345 + }, + ortb2Imp: { + ext: { + data: { + pbadslot: 'homepage-top-rect', + adUnitSpecificAttribute: '123' + } + } + } + }]; + let request = spec.buildRequests(bidderRequests, bidderRequest); + let ortbRequest = request.data; + expect(ortbRequest).to.not.equal(null); + expect(ortbRequest.imp).to.not.equal(null); + expect(ortbRequest.imp).to.have.lengthOf(1); + expect(ortbRequest.imp[0].ext).to.not.equal(null); + expect(ortbRequest.imp[0].ext).to.deep.equal({ + prebid: { + extra_key1: 'extra_val1', + extra_key2: 12345 + }, + data: { + pbadslot: 'homepage-top-rect', + adUnitSpecificAttribute: '123' + } + }); + }); }); From f90a8a11a304a78e7dc46b032ade5c407782d36f Mon Sep 17 00:00:00 2001 From: velichkin Date: Wed, 19 Oct 2022 14:47:08 +0300 Subject: [PATCH 033/367] Mgid Bid Adapter: fix usage of ortb2 data (#9117) * Fix Mgid Bid provider: 1. Use ortb2 data 2. Added gvlid to spec * Fix Mgid Bid provider. Unit-tests --- modules/mgidBidAdapter.js | 8 +++- test/spec/modules/mgidBidAdapter_spec.js | 50 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/modules/mgidBidAdapter.js b/modules/mgidBidAdapter.js index bca9ae49892..036effecd88 100644 --- a/modules/mgidBidAdapter.js +++ b/modules/mgidBidAdapter.js @@ -178,6 +178,8 @@ export const spec = { return; } + const ortb2Data = bidderRequest?.ortb2 || {}; + let request = { id: deepAccess(bidderRequest, 'bidderRequestId'), site: {domain, page}, @@ -191,7 +193,11 @@ export const spec = { w: screen.width, language: getLanguage() }, - ext: {mgid_ver: spec.VERSION, prebid_ver: '$prebid.version$'}, + ext: { + mgid_ver: spec.VERSION, + prebid_ver: '$prebid.version$', + ...ortb2Data + }, imp }; if (bidderRequest && bidderRequest.gdprConsent) { diff --git a/test/spec/modules/mgidBidAdapter_spec.js b/test/spec/modules/mgidBidAdapter_spec.js index 34ad29b3e92..c79cad6245d 100644 --- a/test/spec/modules/mgidBidAdapter_spec.js +++ b/test/spec/modules/mgidBidAdapter_spec.js @@ -31,6 +31,10 @@ describe('Mgid bid adapter', function () { const mgid_ver = spec.VERSION; const utcOffset = (new Date()).getTimezoneOffset().toString(); + it('should expose gvlid', function() { + expect(spec.gvlid).to.equal(358) + }); + describe('isBidRequestValid', function () { let bid = { 'adUnitCode': 'div', @@ -541,6 +545,52 @@ describe('Mgid bid adapter', function () { 'data': '{"site":{"domain":"' + domain + '","page":"' + page + '"},"cur":["USD"],"geo":{"utcoffset":' + utcOffset + '},"device":{"ua":"' + ua + '","js":1,"dnt":' + dnt + ',"h":' + screenHeight + ',"w":' + screenWidth + ',"language":"' + lang + '"},"ext":{"mgid_ver":"' + mgid_ver + '","prebid_ver":"' + version + '"},"imp":[{"tagid":"2/div","secure":' + secure + ',"banner":{"w":300,"h":600,"format":[{"w":300,"h":600},{"w":300,"h":250}],"pos":1}}]}', }); }); + it('should proper handle ortb2 data', function () { + let bid = Object.assign({}, abid); + bid.mediaTypes = { + banner: { + sizes: [[300, 250]] + } + }; + let bidRequests = [bid]; + + let bidderRequest = { + ortb2: { + site: { + content: { + data: [{ + name: 'mgid.com', + ext: { + segtax: 1, + }, + segment: [ + {id: '123'}, + {id: '456'}, + ], + }] + } + }, + user: { + data: [{ + name: 'mgid.com', + ext: { + segtax: 2, + }, + segment: [ + {'id': '789'}, + {'id': '987'}, + ], + }] + } + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.url).deep.equal('https://prebid.mgid.com/prebid/1'); + expect(request.method).deep.equal('POST'); + const data = JSON.parse(request.data); + expect(data.ext).deep.include(bidderRequest.ortb2); + }); }); describe('interpretResponse', function () { From b90ee9125fd332448453d1ba862d52fb5b2ce603 Mon Sep 17 00:00:00 2001 From: Jason Lydon <95770514+ftxmoJason@users.noreply.github.com> Date: Wed, 19 Oct 2022 09:48:31 -0400 Subject: [PATCH 034/367] FTRACK USER ID MODULE: tweaking the createEidsArray() method to accept two schema patterns (#9123) * JDB-563: tweaking the createEidsArray() method to accept two schema patterns * JDB-563: further cleanup now that I understand the the decode method should be used to prepare the data * JDB-563: adding shortcircuit back into decode method Co-authored-by: Jason Lydon --- modules/ftrackIdSystem.js | 37 ++- modules/userId/eids.js | 18 +- test/spec/modules/eids_spec.js | 18 +- test/spec/modules/ftrackIdSystem_spec.js | 290 ++++++++++++++++------- 4 files changed, 246 insertions(+), 117 deletions(-) diff --git a/modules/ftrackIdSystem.js b/modules/ftrackIdSystem.js index 55f04e6b1d3..244807a3164 100644 --- a/modules/ftrackIdSystem.js +++ b/modules/ftrackIdSystem.js @@ -48,20 +48,39 @@ export const ftrackIdSubmodule = { * similar to the module name and ending in id or Id */ decode (value, config) { - if (!value) { return } - const ext = {} + if (!value) { + return; + }; - for (var key in value) { - /** unpack the strings from the arrays */ - ext[key] = value[key][0] + const DECODE_RESPONSE = { + ftrackId: { + uid: '', + ext: {} + } } - return { - ftrackId: { - uid: value.DeviceID && value.DeviceID[0], - ext + // Loop over the value's properties: + // -- if string, assign value as is. + // -- if array, convert to string then assign value. + // -- If neither type, assign value as empty string + for (var key in value) { + let keyValue = value[key]; + if (Array.isArray(keyValue)) { + keyValue = keyValue.join('|'); + } else if (typeof value[key] !== 'string') { + // Unexpected value type, should be string or array + keyValue = ''; } + + DECODE_RESPONSE.ftrackId.ext[key] = keyValue; } + + // If we have DeviceId value, assign it to the uid property + if (DECODE_RESPONSE.ftrackId.ext.hasOwnProperty('DeviceID')) { + DECODE_RESPONSE.ftrackId.uid = DECODE_RESPONSE.ftrackId.ext.DeviceID; + } + + return DECODE_RESPONSE; }, /** diff --git a/modules/userId/eids.js b/modules/userId/eids.js index 23dc9809041..e0a076c313f 100644 --- a/modules/userId/eids.js +++ b/modules/userId/eids.js @@ -419,17 +419,12 @@ export function createEidsArray(bidRequestUserId) { if (subModuleKey === 'pubProvidedId') { eids = eids.concat(bidRequestUserId['pubProvidedId']); } else if (subModuleKey === 'ftrackId') { - // ftrack has multiple IDs so we add each one that exists - let eid = { - 'atype': 1, - 'id': (bidRequestUserId.ftrackId.DeviceID || []).join('|'), - 'ext': {} - } - for (let id in bidRequestUserId.ftrackId) { - eid.ext[id] = (bidRequestUserId.ftrackId[id] || []).join('|'); - } - - eids.push(eid); + // Schema based on the return value of ftrack decode() method + eids.push({ + atype: 1, + ext: bidRequestUserId.ftrackId.ext, + id: bidRequestUserId.ftrackId.uid + }); } else if (Array.isArray(bidRequestUserId[subModuleKey])) { bidRequestUserId[subModuleKey].forEach((config, index, arr) => { const eid = createEidObject(config, subModuleKey); @@ -446,6 +441,7 @@ export function createEidsArray(bidRequestUserId) { } } } + return eids; } diff --git a/test/spec/modules/eids_spec.js b/test/spec/modules/eids_spec.js index 6872145710c..ba9210dcb71 100644 --- a/test/spec/modules/eids_spec.js +++ b/test/spec/modules/eids_spec.js @@ -444,11 +444,15 @@ describe('eids array generation for known sub-modules', function() { describe('ftrackId', () => { it('should return the correct EID schema', () => { + // This is the schema returned from the ftrack decode() method expect(createEidsArray({ ftrackId: { - DeviceID: ['aaa', 'bbb'], - SingleDeviceID: ['ccc', 'ddd'], - HHID: ['eee', 'fff'] + uid: 'test-device-id', + ext: { + DeviceID: 'test-device-id', + SingleDeviceID: 'test-single-device-id', + HHID: 'test-household-id' + } }, foo: { bar: 'baz' @@ -458,11 +462,11 @@ describe('eids array generation for known sub-modules', function() { } })).to.deep.equal([{ atype: 1, - id: 'aaa|bbb', + id: 'test-device-id', ext: { - DeviceID: 'aaa|bbb', - SingleDeviceID: 'ccc|ddd', - HHID: 'eee|fff' + DeviceID: 'test-device-id', + SingleDeviceID: 'test-single-device-id', + HHID: 'test-household-id' } }]); }); diff --git a/test/spec/modules/ftrackIdSystem_spec.js b/test/spec/modules/ftrackIdSystem_spec.js index 2c3f3f8576c..79a11845a0f 100644 --- a/test/spec/modules/ftrackIdSystem_spec.js +++ b/test/spec/modules/ftrackIdSystem_spec.js @@ -275,10 +275,55 @@ describe('FTRACK ID System', () => { describe(`decode() method`, () => { it(`should respond with an object with the key 'ftrackId'`, () => { - expect(ftrackIdSubmodule.decode('value', configMock)).to.deep.equal({ + const MOCK_VALUE_STRINGS = { + HHID: 'household_test_id', + DeviceID: 'device_test_id', + SingleDeviceID: 'single_device_test_id' + }, + MOCK_VALUE_ARRAYS = { + HHID: ['household_test_id', 'a', 'b'], + DeviceID: ['device_test_id', 'c', 'd'], + SingleDeviceID: ['single_device_test_id', 'e', 'f'] + }, + MOCK_VALUE_BOTH = { + foo: ['foo', 'a', 'b'], + bar: 'bar', + baz: ['baz', 'baz', 'baz'] + }; + + // strings are just passed through + expect(ftrackIdSubmodule.decode(MOCK_VALUE_STRINGS, configMock)).to.deep.equal({ + ftrackId: { + ext: { + HHID: 'household_test_id', + DeviceID: 'device_test_id', + SingleDeviceID: 'single_device_test_id' + }, + uid: 'device_test_id', + }, + }); + + // arrays are converted to strings + expect(ftrackIdSubmodule.decode(MOCK_VALUE_ARRAYS, configMock)).to.deep.equal({ ftrackId: { - ext: { 0: 'v', 1: 'a', 2: 'l', 3: 'u', 4: 'e' }, - uid: undefined, + ext: { + HHID: 'household_test_id|a|b', + DeviceID: 'device_test_id|c|d', + SingleDeviceID: 'single_device_test_id|e|f' + }, + uid: 'device_test_id|c|d', + }, + }); + + // mix of both but uid should be empty string because DeviceId is not defined + expect(ftrackIdSubmodule.decode(MOCK_VALUE_BOTH, configMock)).to.deep.equal({ + ftrackId: { + ext: { + foo: 'foo|a|b', + bar: 'bar', + baz: 'baz|baz|baz' + }, + uid: '', }, }); }); @@ -309,56 +354,40 @@ describe('FTRACK ID System', () => { }); describe('pbjs "get id" methods', () => { - // The full set of ftrack IDs to test against - let expectedIds = { - HHID: ['household_test_id'], - DeviceID: ['device_test_id'], - SingleDeviceID: ['single_device_test_id'] - }; - // The full config mock - let userSyncConfigMock = { - userSync: { - auctionDelay: 10, - userIds: [{ - name: 'ftrack', - value: { - ftrackId: expectedIds - } - }] - } - }; - // The full eids response - let expectedEids = [{ - id: 'device_test_id', - atype: 1, - ext: { - HHID: expectedIds.HHID.join('|'), - DeviceID: expectedIds.DeviceID.join('|'), - SingleDeviceID: expectedIds.SingleDeviceID.join('|') - } - }]; - beforeEach(() => { init(config); setSubmoduleRegistry([ftrackIdSubmodule]); }); - afterEach(() => { - // Reset expectedIds to the default values because some tests overwrite them - expectedIds = { - HHID: ['household_test_id'], - DeviceID: ['device_test_id'], - SingleDeviceID: ['single_device_test_id'] - }; - }); - describe('pbjs.getUserIdsAsync()', () => { - it('should return the IDs in the correct schema', () => { - config.setConfig(userSyncConfigMock); + it('should return the IDs in the correct schema - flat schema', () => { + config.setConfig({ + userSync: { + auctionDelay: 10, + userIds: [{ + name: 'ftrack', + value: { + ftrackId: { + uid: 'device_test_id', + ext: { + HHID: 'household_test_id', + DeviceID: 'device_test_id', + SingleDeviceID: 'single_device_test_id' + } + } + } + }] + } + }); getGlobal().getUserIdsAsync().then(ids => { expect(ids).to.deep.equal({ - ftrackId: expectedIds + uid: 'device_test_id', + ftrackId: { + HHID: 'household_test_id', + DeviceID: 'device_test_id', + SingleDeviceID: 'single_device_test_id' + } }); }); }); @@ -366,73 +395,154 @@ describe('FTRACK ID System', () => { describe('pbjs.getUserIds()', () => { it('should return the IDs in the correct schema', () => { - config.setConfig(userSyncConfigMock); + config.setConfig({ + userSync: { + auctionDelay: 10, + userIds: [{ + name: 'ftrack', + value: { + ftrackId: { + uid: 'device_test_id', + ext: { + HHID: 'household_test_id', + DeviceID: 'device_test_id', + SingleDeviceID: 'single_device_test_id' + } + } + } + }] + } + }); expect(getGlobal().getUserIds()).to.deep.equal({ - 'ftrackId': expectedIds + ftrackId: { + uid: 'device_test_id', + ext: { + HHID: 'household_test_id', + DeviceID: 'device_test_id', + SingleDeviceID: 'single_device_test_id' + } + } }); }); }); describe('pbjs.getUserIdsAsEids()', () => { - it('should return the correct EIDs schema', () => { - let userSyncConfig = Object.assign({}, userSyncConfigMock); - - config.setConfig(userSyncConfig); + it('should return the correct EIDs schema ', () => { + // Pass all three IDs + config.setConfig({ + userSync: { + auctionDelay: 10, + userIds: [{ + name: 'ftrack', + value: { + ftrackId: { + uid: 'device_test_id', + ext: { + HHID: 'household_test_id', + DeviceID: 'device_test_id', + SingleDeviceID: 'single_device_test_id' + } + } + } + }] + } + }); - expect(getGlobal().getUserIdsAsEids()).to.deep.equal(expectedEids); + expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ + id: 'device_test_id', + atype: 1, + ext: { + HHID: 'household_test_id', + DeviceID: 'device_test_id', + SingleDeviceID: 'single_device_test_id' + } + }]); }); describe('by ID type:', () => { it('- DeviceID', () => { - let userSyncConfig = Object.assign({}, userSyncConfigMock); - - userSyncConfig.userSync.userIds[0].value.ftrackId = { - DeviceID: ['device_test_id'] - }; - - let expectedEidsClone = expectedEids.slice(); - expectedEidsClone[0].ext = { - DeviceID: expectedIds.DeviceID.join('|') - }; - - config.setConfig(userSyncConfig); + // Pass DeviceID only + config.setConfig({ + userSync: { + auctionDelay: 10, + userIds: [{ + name: 'ftrack', + value: { + ftrackId: { + uid: 'device_test_id', + ext: { + DeviceID: 'device_test_id', + } + } + } + }] + } + }); - expect(getGlobal().getUserIdsAsEids()).to.deep.equal(expectedEidsClone); + expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ + id: 'device_test_id', + atype: 1, + ext: { + DeviceID: 'device_test_id' + } + }]); }); it('- HHID', () => { - let userSyncConfig = Object.assign({}, userSyncConfigMock); - userSyncConfig.userSync.userIds[0].value.ftrackId = { - HHID: ['household_test_id'] - }; - - let expectedEidsClone = expectedEids.slice(); - expectedEidsClone[0].id = ''; - expectedEidsClone[0].ext = { - HHID: expectedIds.HHID.join('|') - }; - - config.setConfig(userSyncConfig); + // Pass HHID only + config.setConfig({ + userSync: { + auctionDelay: 10, + userIds: [{ + name: 'ftrack', + value: { + ftrackId: { + uid: '', + ext: { + HHID: 'household_test_id' + } + } + } + }] + } + }); - expect(getGlobal().getUserIdsAsEids()).to.deep.equal(expectedEidsClone); + expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ + id: '', + atype: 1, + ext: { + HHID: 'household_test_id' + } + }]); }); it('- SingleDeviceID', () => { - let userSyncConfig = Object.assign({}, userSyncConfigMock); - userSyncConfig.userSync.userIds[0].value.ftrackId = { - SingleDeviceID: ['single_device_test_id'] - }; - - let expectedEidsClone = expectedEids.slice(); - expectedEidsClone[0].id = ''; - expectedEidsClone[0].ext = { - SingleDeviceID: expectedIds.SingleDeviceID.join('|') - }; - - config.setConfig(userSyncConfig); + // Pass SingleDeviceID only + config.setConfig({ + userSync: { + auctionDelay: 10, + userIds: [{ + name: 'ftrack', + value: { + ftrackId: { + uid: '', + ext: { + SingleDeviceID: 'single_device_test_id' + } + } + } + }] + } + }); - expect(getGlobal().getUserIdsAsEids()).to.deep.equal(expectedEidsClone); + expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ + id: '', + atype: 1, + ext: { + SingleDeviceID: 'single_device_test_id' + } + }]); }); }); }); From 2bf778470b28f19b2a3c0a32b59214e5256ddad6 Mon Sep 17 00:00:00 2001 From: Tiago Peczenyj Date: Wed, 19 Oct 2022 18:11:49 +0200 Subject: [PATCH 035/367] Weborama RTD Module: add support to asset ids on contextual api (#9086) * format doc * refacto configuration * refactor module * refactor code by change 3 constants to use one * use single quote * refactor profile validator * refactor wrapping code * improve type return * update jsdoc, refactor some code * refactor Object.keys * update jsdoc * refactor specific bidder code * refactor jscode * refactor jscode * dont repeat yourself * add more info in components * convert to class * move all code to private methods * refactor into class with private methods * remove global list of components * update tests, refactor code * finish refactor * implement feature * update doc * fix doc * update integration example * add url parameter * Update weboramaRtdProvider.md Fix typo * improve asset id handling * adapt test to use webo_vctx when handle asset id * fix observations from julien * update fallback rules on contextual * fix doc --- .../gpt/weboramaRtdProvider_example.html | 61 +- modules/weboramaRtdProvider.js | 1443 +++++++++-------- modules/weboramaRtdProvider.md | 32 + test/spec/modules/weboramaRtdProvider_spec.js | 382 +++++ 4 files changed, 1224 insertions(+), 694 deletions(-) diff --git a/integrationExamples/gpt/weboramaRtdProvider_example.html b/integrationExamples/gpt/weboramaRtdProvider_example.html index 73843c49914..7e75721103f 100644 --- a/integrationExamples/gpt/weboramaRtdProvider_example.html +++ b/integrationExamples/gpt/weboramaRtdProvider_example.html @@ -1,12 +1,9 @@ - - - - - - weborama rtd submodule example - - + + + + + weborama rtd submodule example + @@ -33,16 +30,19 @@ weboCtxConf: { token: "to-be-defined", // mandatory targetURL: "https://prebid.org", // default is document.URL + assetID: "token:identifier", // new parameter, overrides url setPrebidTargeting: true, // override param.setPrebidTargeting or default true sendToBidders: true, // override param.sendToBidders or default true defaultProfile: { // optional webo_ctx: ["Rugby_Renault_c11495", "Sport_c11893"], webo_ds: ['bar'] }, + baseURLProfileAPI: 'ctx-preprod.weborama.com', // enabled: false, //, onData: function (data,...) { ...} }, weboUserDataConf: { + enabled: false, accountId: 12345, // recommended setPrebidTargeting: true, // override param.setPrebidTargeting or default true sendToBidders: ['smartadserver'], // specify the bidder to share data @@ -55,7 +55,7 @@ //, onData: function (data,...) { ...} }, sfbxLiteDataConf: { - enabled: true, + enabled: false, defaultProfile: { // optional lite_occupation: ['gérant', 'bénévole'], lite_hobbies: ['sport', 'cinéma'], @@ -118,46 +118,6 @@ networkId: 456456, }, }] - }, - { - code: '/1056029/webo-wam-prebid', - mediaTypes: { - banner: { - sizes: div_2_sizes - } - }, - bids: [{ - bidder: 'smartadserver', - params: { - siteId: 1234, - pageId: 1234, - formatId: 1234, - } - }, { - bidder: 'pubmatic', - params: { - publisherId: '32572', - } - }, { - bidder: 'appnexus', - params: { - placementId: 234234, - } - }, { - bidder: 'rubicon', - params: { - accountId: '14062', - siteId: '70608', - zoneId: '335918', - userId: '12346', - } - }, { - bidder: 'criteo', - params: { - zoneId: 234234, - networkId: 456456, - }, - }] } ]; @@ -197,7 +157,6 @@ googletag.cmd.push(function () { googletag.defineSlot('/1056029/webo-ctx-prebid', div_1_sizes, 'div-gpt-ad-1620653642627-0').addService(googletag.pubads()); - googletag.defineSlot('/1056029/webo-wam-prebid', div_2_sizes, 'div-gpt-ad-1645023761875-0').addService(googletag.pubads()); googletag.pubads().disableInitialLoad(); googletag.enableServices(); }); diff --git a/modules/weboramaRtdProvider.js b/modules/weboramaRtdProvider.js index 533e669fcaa..12e8d4b23c8 100644 --- a/modules/weboramaRtdProvider.js +++ b/modules/weboramaRtdProvider.js @@ -7,83 +7,98 @@ * @requires module:modules/realTimeData */ -/** +/** profile metadata * @typedef dataCallbackMetadata - * @property {Boolean} user if true it is user-centric data - * @property {String} source describe the source of data, if "contextual" or "wam" - * @property {Boolean} isDefault if true it the default profile defined in the configuration + * @property {boolean} user if true it is user-centric data + * @property {string} source describe the source of data, if 'contextual' or 'wam' + * @property {boolean} isDefault if true it the default profile defined in the configuration + */ + +/** profile from contextual, wam or sfbx + * @typedef {Object.} Profile */ /** onData callback type * @callback dataCallback - * @param {Object} data profile data + * @param {Profile} data profile data * @param {dataCallbackMetadata} meta metadata * @returns {void} */ /** setPrebidTargeting callback type * @callback setPrebidTargetingCallback - * @param {String} adUnitCode - * @param {Object} data + * @param {string} adUnitCode + * @param {Profile} data * @param {dataCallbackMetadata} metadata - * @returns {Boolean} + * @returns {boolean} */ /** sendToBidders callback type * @callback sendToBiddersCallback * @param {Object} bid - * @param {String} adUnitCode - * @param {Object} data + * @param {string} adUnitCode + * @param {Profile} data * @param {dataCallbackMetadata} metadata - * @returns {Boolean} + * @returns {boolean} */ /** * @typedef {Object} ModuleParams - * @property {?setPrebidTargetingCallback|?Boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined) - * @property {?sendToBiddersCallback|?Boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined) + * @property {?setPrebidTargetingCallback|?boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined) + * @property {?sendToBiddersCallback|?boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined) * @property {?dataCallback} onData callback * @property {?WeboCtxConf} weboCtxConf site-centric contextual configuration * @property {?WeboUserDataConf} weboUserDataConf user-centric wam configuration * @property {?SfbxLiteDataConf} sfbxLiteDataConf site-centric lite configuration */ +/** + * @callback assetIDcallback + * @returns {string} should return asset identifier using the form datasource:docId + */ /** * @typedef {Object} WeboCtxConf * @property {string} token required token to be used on bigsea contextual API requests * @property {?string} targetURL specify the target url instead use the referer - * @property {?setPrebidTargetingCallback|?Boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined) - * @property {?sendToBiddersCallback|?Boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined) + * @property {?assetIDcallback|?string} assetID specifies the assert identifier using the form datasource:docId or via callback + * @property {?setPrebidTargetingCallback|?boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined) + * @property {?sendToBiddersCallback|?boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined) * @property {?dataCallback} onData callback - * @property {?object} defaultProfile to be used if the profile is not found - * @property {?Boolean} enabled if false, will ignore this configuration + * @property {?Profile} defaultProfile to be used if the profile is not found + * @property {?boolean} enabled if false, will ignore this configuration * @property {?string} baseURLProfileAPI to be used to point to a different domain than ctx.weborama.com */ /** * @typedef {Object} WeboUserDataConf * @property {?number} accountId wam account id - * @property {?setPrebidTargetingCallback|?Boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined) - * @property {?sendToBiddersCallback|?Boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined) - * @property {?object} defaultProfile to be used if the profile is not found + * @property {?setPrebidTargetingCallback|?boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined) + * @property {?sendToBiddersCallback|?boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined) + * @property {?Profile} defaultProfile to be used if the profile is not found * @property {?dataCallback} onData callback * @property {?string} localStorageProfileKey can be used to customize the local storage key (default is 'webo_wam2gam_entry') - * @property {?Boolean} enabled if false, will ignore this configuration + * @property {?boolean} enabled if false, will ignore this configuration */ /** * @typedef {Object} SfbxLiteDataConf - * @property {?setPrebidTargetingCallback|?Boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined) - * @property {?sendToBiddersCallback|?Boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined) - * @property {?object} defaultProfile to be used if the profile is not found + * @property {?setPrebidTargetingCallback|?boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined) + * @property {?sendToBiddersCallback|?boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined) + * @property {?Profile} defaultProfile to be used if the profile is not found * @property {?dataCallback} onData callback * @property {?string} localStorageProfileKey can be used to customize the local storage key (default is '_lite') - * @property {?Boolean} enabled if false, will ignore this configuration + * @property {?boolean} enabled if false, will ignore this configuration */ + +/** common configuration between contextual, wam and sfbx + * @typedef {WeboCtxConf|WeboUserDataConf|SfbxLiteDataConf} CommonConf + */ + import { getGlobal } from '../src/prebidGlobal.js'; import { + deepClone, deepSetValue, isEmpty, isFn, @@ -93,8 +108,9 @@ import { isStr, isBoolean, isPlainObject, - deepClone, - tryAppendQueryString, mergeDeep, logWarn + logWarn, + mergeDeep, + tryAppendQueryString } from '../src/utils.js'; import { submodule @@ -127,431 +143,869 @@ const WEBO_CTX_CONF_SECTION = 'weboCtxConf'; const WEBO_USER_DATA_CONF_SECTION = 'weboUserDataConf'; /** @type {string} */ const SFBX_LITE_DATA_CONF_SECTION = 'sfbxLiteDataConf'; - +/** @type {string} */ +const WEBO_CTX_SOURCE_LABEL = 'contextual'; +/** @type {string} */ +const WEBO_USER_DATA_SOURCE_LABEL = 'wam'; +/** @type {string} */ +const SFBX_LITE_DATA_SOURCE_LABEL = 'lite'; /** @type {number} */ const GVLID = 284; -/** @type {?Object} */ + export const storage = getStorageManager({ gvlid: GVLID, moduleName: SUBMODULE_NAME }); -/** @type {null|Object} */ -let _weboContextualProfile = null; +/** + * @typedef {Object} Component + * @property {boolean} initialized + * @property {?Profile} data + * @property {boolean} user if true it is user-centric data + * @property {string} source describe the source of data, if 'contextual' or 'wam' + * @property {buildProfileHandlerCallbackBuilder} callbackBuilder + */ + +/** + * @typedef {Object} Components + * @property {Component} WeboCtx + * @property {Component} WeboUserData + * @property {Component} SfbxLiteData + */ -/** @type {Boolean} */ -let _weboCtxInitialized = false; +/** + * @classdesc Weborama Real Time Data Provider + * @class + */ +class WeboramaRtdProvider { + #components; + name = SUBMODULE_NAME; + /** + * @param {Components} components + */ + constructor(components) { + this.#components = components; + } + /** Initialize module + * @method + * @param {Object} moduleConfig + * @param {?ModuleParams} moduleConfig.params + * @return {boolean} true if module was initialized with success + */ + init(moduleConfig) { + /** @type {Object} */ + const globalDefaults = { + setPrebidTargeting: true, + sendToBidders: true, + onData: () => { + /* do nothing */ + } + }; + /** @type {ModuleParams} */ + const moduleParams = Object.assign({}, globalDefaults, moduleConfig?.params || {}); -/** @type {?Object} */ -let _weboUserDataUserProfile = null; + // reset profiles -/** @type {Boolean} */ -let _weboUserDataInitialized = false; + this.#components.WeboCtx.data = null; + this.#components.WeboUserData.data = null; + this.#components.SfbxLiteData.data = null; -/** @type {?Object} */ -let _sfbxLiteDataProfile = null; + this.#components.WeboCtx.initialized = this.#initSubSection(moduleParams, WEBO_CTX_CONF_SECTION, 'token'); + this.#components.WeboUserData.initialized = this.#initSubSection(moduleParams, WEBO_USER_DATA_CONF_SECTION); + this.#components.SfbxLiteData.initialized = this.#initSubSection(moduleParams, SFBX_LITE_DATA_CONF_SECTION); -/** @type {Boolean} */ -let _sfbxLiteDataInitialized = false; + return Object.values(this.#components).some((c) => c.initialized); + } -/** Initialize module - * @param {object} moduleConfig - * @return {Boolean} true if module was initialized with success - */ -function init(moduleConfig) { - const moduleParams = moduleConfig?.params || {}; + /** function that will allow RTD sub-modules to modify the AdUnit object for each auction + * @method + * @param {Object} reqBidsConfigObj + * @param {doneCallback} onDone + * @param {Object} moduleConfig + * @param {?ModuleParams} moduleConfig.params + * @returns {void} + */ + getBidRequestData(reqBidsConfigObj, onDone, moduleConfig) { + /** @type {ModuleParams} */ + const moduleParams = moduleConfig?.params || {}; + + if (!this.#components.WeboCtx.initialized) { + this.#handleBidRequestData(reqBidsConfigObj, moduleParams); - _weboContextualProfile = null; - _weboUserDataUserProfile = null; - _sfbxLiteDataProfile = null; + onDone(); - _weboCtxInitialized = initSubSection(moduleParams, WEBO_CTX_CONF_SECTION, 'token'); - _weboUserDataInitialized = initSubSection(moduleParams, WEBO_USER_DATA_CONF_SECTION); - _sfbxLiteDataInitialized = initSubSection(moduleParams, SFBX_LITE_DATA_CONF_SECTION); + return; + } - return _weboCtxInitialized || _weboUserDataInitialized || _sfbxLiteDataInitialized; -} + /** @type {WeboCtxConf} */ + const weboCtxConf = moduleParams.weboCtxConf || {}; -/** Initialize subsection module - * @param {Object} moduleParams - * @param {string} subSection subsection name to initialize - * @param {[]string} requiredFields - * @return {Boolean} true if module subsection was initialized with success - */ -function initSubSection(moduleParams, subSection, ...requiredFields) { - const weboSectionConf = moduleParams[subSection] || {enabled: false}; + this.#fetchContextualProfile(weboCtxConf, (data) => { + logMessage('fetchContextualProfile on getBidRequestData is done'); - if (weboSectionConf.enabled === false) { - delete moduleParams[subSection]; + this.#setWeboContextualProfile(data); + }, () => { + this.#handleBidRequestData(reqBidsConfigObj, moduleParams); - return false; + onDone(); + }); } - requiredFields ||= []; + /** function that provides ad server targeting data to RTD-core + * @method + * @param {string[]} adUnitsCodes + * @param {Object} moduleConfig + * @param {?ModuleParams} moduleConfig.params + * @returns {Object} target data + */ + getTargetingData(adUnitsCodes, moduleConfig) { + /** @type {ModuleParams} */ + const moduleParams = moduleConfig?.params || {}; + + const profileHandlers = this.#buildProfileHandlers(moduleParams); + + if (isEmpty(profileHandlers)) { + logMessage('no data to set targeting'); + return {}; + } - try { - normalizeConf(moduleParams, weboSectionConf); + try { + return adUnitsCodes.reduce((data, adUnitCode) => { + data[adUnitCode] = profileHandlers.reduce((targeting, ph) => { + // logMessage(`check if should set targeting for adunit '${adUnitCode}'`); + const [data, metadata] = this.#copyDataAndMetadata(ph); + if (ph.setTargeting(adUnitCode, data, metadata)) { + // logMessage(`set targeting for adunit '${adUnitCode}', source '${metadata.source}'`); + + mergeDeep(targeting, data); + } - requiredFields.forEach(field => { - if (!weboSectionConf[field]) { - throw `missing required field "{field}" on {section}`; - } - }); - } catch (e) { - logError(`unable to initialize: error on ${subSection} configuration: ${e}`); - return false; - } + return targeting; + }, {}); - logMessage(`weborama ${subSection} initialized with success`); + return data; + }, {}); + } catch (e) { + logError(`unable to format weborama rtd targeting data:`, e); - return true; -} + return {}; + } + } -/** @type {Object} */ -const globalDefaults = { - setPrebidTargeting: true, - sendToBidders: true, - onData: () => { - /* do nothing */ }, -}; + /** Initialize subsection module + * @method + * @private + * @param {ModuleParams} moduleParams + * @param {string} subSection subsection name to initialize + * @param {string[]} requiredFields + * @return {boolean} true if module subsection was initialized with success + */ + #initSubSection(moduleParams, subSection, ...requiredFields) { + /** @type {CommonConf} */ + const weboSectionConf = moduleParams[subSection] || { enabled: false }; + + if (weboSectionConf.enabled === false) { + delete moduleParams[subSection]; -/** normalize submodule configuration - * @param {ModuleParams} moduleParams - * @param {WeboCtxConf|WeboUserDataConf|SfbxLiteDataConf} submoduleParams - * @return {void} - */ -function normalizeConf(moduleParams, submoduleParams) { - // handle defaults - Object.entries(globalDefaults).forEach(([propertyName, globalDefaultValue]) => { - if (!submoduleParams.hasOwnProperty(propertyName)) { - const hasModuleParam = moduleParams.hasOwnProperty(propertyName); - submoduleParams[propertyName] = (hasModuleParam) ? moduleParams[propertyName] : globalDefaultValue; + return false; } - }) - // handle setPrebidTargeting - coerceSetPrebidTargeting(submoduleParams) + try { + this.#normalizeConf(moduleParams, weboSectionConf); - // handle sendToBidders - coerceSendToBidders(submoduleParams) + requiredFields.forEach(field => { + if (!(field in weboSectionConf)) { + throw `missing required field '${field}''`; + } + }); + } catch (e) { + logError(`unable to initialize: error on ${subSection} configuration:`, e); + return false; + } + + logMessage(`weborama ${subSection} initialized with success`); - if (!isFn(submoduleParams.onData)) { - throw 'onData parameter should be a callback'; + return true; } - submoduleParams.defaultProfile = submoduleParams.defaultProfile || {}; + /** normalize submodule configuration + * @method + * @private + * @param {ModuleParams} moduleParams + * @param {CommonConf} submoduleParams + * @return {void} + * @throws will throw an error in case of invalid configuration + */ + // eslint-disable-next-line no-dupe-class-members + #normalizeConf(moduleParams, submoduleParams) { + submoduleParams.defaultProfile = submoduleParams.defaultProfile || {}; - if (!isValidProfile(submoduleParams.defaultProfile)) { - throw 'defaultProfile is not valid'; - } -} + const { setPrebidTargeting, sendToBidders, onData } = moduleParams; -/** coerce set prebid targeting to function - * @param {WeboCtxConf|WeboUserDataConf|SfbxLiteDataConf} submoduleParams - * @return {void} - */ -function coerceSetPrebidTargeting(submoduleParams) { - const setPrebidTargeting = submoduleParams.setPrebidTargeting; + submoduleParams.setPrebidTargeting ??= setPrebidTargeting; + submoduleParams.sendToBidders ??= sendToBidders; + submoduleParams.onData ??= onData; - if (isFn(setPrebidTargeting)) { - return - } + // handle setPrebidTargeting + this.#coerceSetPrebidTargeting(submoduleParams); - if (isBoolean(setPrebidTargeting)) { - const shouldSetPrebidTargeting = setPrebidTargeting; + // handle sendToBidders + this.#coerceSendToBidders(submoduleParams); - submoduleParams.setPrebidTargeting = () => shouldSetPrebidTargeting; + if (!isFn(submoduleParams.onData)) { + throw 'onData parameter should be a callback'; + } - return + if (!isValidProfile(submoduleParams.defaultProfile)) { + throw 'defaultProfile is not valid'; + } } - if (isStr(setPrebidTargeting)) { - const allowedAdUnitCode = setPrebidTargeting; + /** coerce setPrebidTargeting to a callback + * @method + * @private + * @param {CommonConf} submoduleParams + * @return {void} + * @throws will throw an error in case of invalid configuration + */ + // eslint-disable-next-line no-dupe-class-members + #coerceSetPrebidTargeting(submoduleParams) { + try { + submoduleParams.setPrebidTargeting = this.#wrapValidatorCallback(submoduleParams.setPrebidTargeting); + } catch (e) { + throw `invalid setPrebidTargeting: ${e}`; + } + } - submoduleParams.setPrebidTargeting = (adUnitCode) => allowedAdUnitCode == adUnitCode; + /** coerce sendToBidders to a callback + * @method + * @private + * @param {CommonConf} submoduleParams + * @return {void} + * @throws will throw an error in case of invalid configuration + */ + // eslint-disable-next-line no-dupe-class-members + #coerceSendToBidders(submoduleParams) { + let sendToBidders = submoduleParams.sendToBidders; + + if (isPlainObject(sendToBidders)) { + const sendToBiddersMap = Object.entries(sendToBidders).reduce((map, [key, value]) => { + map[key] = this.#wrapValidatorCallback(value); + return map; + }, {}); - return - } + submoduleParams.sendToBidders = (bid, adUnitCode) => { + const bidder = bid.bidder; + if (!(bidder in sendToBiddersMap)) { + return false; + } - if (isArray(setPrebidTargeting)) { - const allowedAdUnitCodes = setPrebidTargeting; + const validatorCallback = sendToBiddersMap[bidder]; - submoduleParams.setPrebidTargeting = (adUnitCode) => allowedAdUnitCodes.includes(adUnitCode); + try { + return validatorCallback(adUnitCode); + } catch (e) { + throw `invalid sendToBidders[${bidder}]: ${e}`; + } + }; - return + return; + } + + try { + submoduleParams.sendToBidders = this.#wrapValidatorCallback(submoduleParams.sendToBidders, + (bid) => bid.bidder); + } catch (e) { + throw `invalid sendToBidders: ${e}`; + } } - throw `unexpected format for setPrebidTargeting: ${typeof setPrebidTargeting}`; -} + /** + * @typedef {Object} AdUnit + * @property {Object[]} bids + */ + /** function that handles bid request data + * @method + * @private + * @param {Object} reqBidsConfigObj + * @param {AdUnit[]} reqBidsConfigObj.adUnits + * @param {Object} reqBidsConfigObj.ortb2Fragments + * @param {Object} reqBidsConfigObj.ortb2Fragments.bidder + * @param {ModuleParams} moduleParams + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #handleBidRequestData(reqBidsConfigObj, moduleParams) { + const profileHandlers = this.#buildProfileHandlers(moduleParams); + + if (isEmpty(profileHandlers)) { + logMessage('no data to send to bidders'); + return; + } -/** coerce send to bidders to function - * @param {WeboCtxConf|WeboUserDataConf|SfbxLiteDataConf} submoduleParams - * @return {void} - */ -function coerceSendToBidders(submoduleParams) { - const sendToBidders = submoduleParams.sendToBidders; + const adUnits = reqBidsConfigObj.adUnits || getGlobal().adUnits; + + try { + adUnits.forEach( + adUnit => adUnit.bids?.forEach( + bid => profileHandlers.forEach(ph => { + // logMessage(`check if bidder '${bid.bidder}' and adunit '${adUnit.code} are share ${ph.metadata.source} data`); + + const [data, metadata] = this.#copyDataAndMetadata(ph); + if (ph.sendToBidders(bid, adUnit.code, data, metadata)) { + // logMessage(`handling bidder '${bid.bidder}' with ${ph.metadata.source} data`); + + this.#handleBid(reqBidsConfigObj, bid, data, ph.metadata); + } + }) + ) + ); + } catch (e) { + logError('unable to send data to bidders:', e); + } - if (isFn(sendToBidders)) { - return + profileHandlers.forEach(ph => { + try { + const [data, metadata] = this.#copyDataAndMetadata(ph); + ph.onData(data, metadata); + } catch (e) { + logError(`error while execute onData callback with ${ph.metadata.source}-based data:`, e); + } + }); } - if (isBoolean(sendToBidders)) { - const shouldSendToBidders = sendToBidders; + /** onSuccess callback type + * @callback successCallback + * @param {?Object} data + * @returns {void} + */ + + /** onDone callback type + * @callback doneCallback + * @returns {void} + */ + + /** Fetch Bigsea Contextual Profile + * @method + * @private + * @param {WeboCtxConf} weboCtxConf + * @param {successCallback} onSuccess callback + * @param {doneCallback} onDone callback + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #fetchContextualProfile(weboCtxConf, onSuccess, onDone) { + const token = weboCtxConf.token; + const baseURLProfileAPI = weboCtxConf.baseURLProfileAPI || BASE_URL_CONTEXTUAL_PROFILE_API; + + let path = '/profile'; + let queryString = ''; + queryString = tryAppendQueryString(queryString, 'token', token); + + if (weboCtxConf.assetID) { + path = '/document-profile'; + + let assetID = weboCtxConf.assetID; + if (isFn(assetID)) { + try { + assetID = weboCtxConf.assetID(); + } catch (e) { + logError('unexpected error while fetching asset id from callback', e); - submoduleParams.sendToBidders = () => shouldSendToBidders; + onDone(); - return - } + return; + } + } - if (isStr(sendToBidders)) { - const allowedBidder = sendToBidders; + if (!assetID) { + logError('missing asset id'); - submoduleParams.sendToBidders = (bid) => allowedBidder == bid.bidder; + onDone(); - return - } + return; + } - if (isArray(sendToBidders)) { - const allowedBidders = sendToBidders; + queryString = tryAppendQueryString(queryString, 'assetId', assetID); + } - submoduleParams.sendToBidders = (bid) => allowedBidders.includes(bid.bidder); + const targetURL = weboCtxConf.targetURL || document.URL; + queryString = tryAppendQueryString(queryString, 'url', targetURL); - return - } + const urlProfileAPI = `https://${baseURLProfileAPI}/api${path}?${queryString}`; - if (isPlainObject(sendToBidders)) { - const sendToBiddersMap = sendToBidders; - submoduleParams.sendToBidders = (bid, adUnitCode) => { - const bidder = bid.bidder; - if (!sendToBiddersMap.hasOwnProperty(bidder)) { - return false + const success = (response, req) => { + if (req.status === 200) { + const data = JSON.parse(response); + onSuccess(data); + } else { + throw `unexpected http status response ${req.status} with response ${response}`; } - const value = sendToBiddersMap[bidder]; + onDone(); + }; - if (isBoolean(value)) { - return value - } + const error = (e, req) => { + logError(`unable to get weborama data`, e, req); - if (isStr(value)) { - return value == adUnitCode - } + onDone(); + }; - if (isArray(value)) { - return value.includes(adUnitCode) - } + const callback = { + success, + error, + }; - throw `unexpected format for sendToBidders[${bidder}]: ${typeof value}`; + const options = { + method: 'GET', + withCredentials: false, }; - return + ajax(urlProfileAPI, callback, null, options); } - throw `unexpected format for sendToBidders: ${typeof sendToBidders}`; -} -/** - * check if profile is valid - * @param {*} profile - * @returns {Boolean} - */ -function isValidProfile(profile) { - if (!isPlainObject(profile)) { - return false; + /** set bigsea contextual profile on module state + * @method + * @private + * @param {?Object} data + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #setWeboContextualProfile(data) { + if (data && isPlainObject(data) && isValidProfile(data) && !isEmpty(data)) { + this.#components.WeboCtx.data = data; + } } - const keys = Object.keys(profile); + /** function that provides data handlers based on the configuration + * @method + * @private + * @param {ModuleParams} moduleParams + * @returns {ProfileHandler[]} + */ + // eslint-disable-next-line no-dupe-class-members + #buildProfileHandlers(moduleParams) { + const steps = [{ + component: this.#components.WeboCtx, + conf: moduleParams?.weboCtxConf, + }, { + component: this.#components.WeboUserData, + conf: moduleParams?.weboUserDataConf, + }, { + component: this.#components.SfbxLiteData, + conf: moduleParams?.sfbxLiteDataConf, + }]; + + return steps.filter(step => step.component.initialized).reduce((ph, { component, conf }) => { + const user = component.user; + const source = component.source; + const callback = component.callbackBuilder(component /* equivalent to this */); + const profileHandler = this.#buildProfileHandler(conf, callback, user, source); + if (profileHandler) { + ph.push(profileHandler); + } else { + logMessage(`skip ${source} profile: no data`); + } - for (var i in keys) { - const key = keys[i]; - const value = profile[key]; - if (!isArray(value)) { - return false; + return ph; + }, []); + } + + /** + * @typedef {Object} ProfileHandler + * @property {Profile} data + * @property {dataCallbackMetadata} metadata + * @property {setPrebidTargetingCallback} setTargeting + * @property {sendToBiddersCallback} sendToBidders + * @property {dataCallback} onData + */ + + /** + * @callback buildProfileHandlerCallbackBuilder + * @param {Component} component + * @returns {buildProfileHandlerCallback} + */ + + /** + * @callback buildProfileHandlerCallback + * @param {CommonConf} dataConf + * @returns {[Profile,boolean]} profile + is default flag + */ + + /** + * return specific profile handler + * @method + * @private + * @param {CommonConf} dataConf + * @param {buildProfileHandlerCallback} callback + * @param {boolean} user + * @param {string} source + * @returns {ProfileHandler} + */ + // eslint-disable-next-line no-dupe-class-members + #buildProfileHandler(dataConf, callback, user, source) { + if (!dataConf) { + return; } - for (var j in value) { - const elem = value[j] - if (!isStr(elem)) { - return false; - } + const [data, isDefault] = callback(dataConf); + if (isEmpty(data)) { + return; + } + + return { + data: data, + metadata: { + user: user, + source: source, + isDefault: !!isDefault, + }, + setTargeting: dataConf.setPrebidTargeting, + sendToBidders: dataConf.sendToBidders, + onData: dataConf.onData, + }; + } + /** handle individual bid + * @method + * @private + * @param {Object} reqBidsConfigObj + * @param {Object} reqBidsConfigObj.ortb2Fragments + * @param {Object} reqBidsConfigObj.ortb2Fragments.bidder + * @param {Object} bid + * @param {string} bid.bidder + * @param {Profile} profile + * @param {dataCallbackMetadata} metadata + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #handleBid(reqBidsConfigObj, bid, profile, metadata) { + this.#handleBidViaORTB2(reqBidsConfigObj, bid.bidder, profile, metadata); + + /** @type {Object.} */ + const bidderAliasRegistry = adapterManager.aliasRegistry || {}; + + /** @type {string} */ + const bidder = bidderAliasRegistry[bid.bidder] || bid.bidder; + + switch (bidder) { + case 'appnexus': + this.#handleAppnexusBid(bid, profile); + break; + case 'pubmatic': + this.#handlePubmaticBid(bid, profile); + break; + case 'smartadserver': + this.#handleSmartadserverBid(bid, profile); + break; + case 'rubicon': + this.#handleRubiconBid(bid, profile, metadata); + break; } } - return true; -} + /** function that handles bid request data + * @method + * @private + * @param {ProfileHandler} ph profile handler + * @returns {[Profile,dataCallbackMetadata]} deeply copy data + metadata + */ + // eslint-disable-next-line no-dupe-class-members + #copyDataAndMetadata(ph) { + return [deepClone(ph.data), deepClone(ph.metadata)]; + } -/** function that provides ad server targeting data to RTD-core - * @param {Array} adUnitsCodes - * @param {Object} moduleConfig - * @returns {Object} target data - */ -function getTargetingData(adUnitsCodes, moduleConfig) { - const moduleParams = moduleConfig?.params || {}; + /** handle appnexus/xandr bid + * @method + * @private + * @param {Object} bid + * @param {Object} bid.params + * @param {Object} bid.params.keyword + * @param {Profile} profile + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #handleAppnexusBid(bid, profile) { + const base = 'params.keywords'; + this.#assignProfileToObject(bid, base, profile); + } - const profileHandlers = buildProfileHandlers(moduleParams); + /** handle pubmatic bid + * @method + * @private + * @param {Object} bid + * @param {Object} bid.params + * @param {string} bid.params.dctr + * @param {Profile} profile + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #handlePubmaticBid(bid, profile) { + const sep = '|'; + const subsep = ','; + + bid.params ||= {}; + + const data = bid.params.dctr || ''; + const target = new Set(data.split(sep).filter((x) => x.length > 0)); + + Object.entries(profile).forEach(([key, values]) => { + const value = values.join(subsep); + const keyword = `${key}=${value}`; + target.add(keyword); + }); - if (isEmpty(profileHandlers)) { - logMessage('no data to set targeting'); - return {}; + bid.params.dctr = Array.from(target).join(sep); } - try { - const td = adUnitsCodes.reduce((data, adUnitCode) => { - data[adUnitCode] = profileHandlers.reduce((targeting, ph) => { - // logMessage(`check if should set targeting for adunit '${adUnitCode}'`); - const cph = copyProfileHandler(ph); - if (ph.setTargeting(adUnitCode, cph.data, cph.metadata)) { - // logMessage(`set targeting for adunit '${adUnitCode}', source '${ph.metadata.source}'`); - - mergeDeep(targeting, cph.data); - } - return targeting; - }, {}); - return data; - }, {}); + /** handle smartadserver bid + * @method + * @private + * @param {Object} bid + * @param {Object} bid.params + * @param {string} bid.params.target + * @param {Profile} profile + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #handleSmartadserverBid(bid, profile) { + const sep = ';'; + + bid.params ||= {}; + + const data = bid.params.target || ''; + const target = new Set(data.split(sep).filter((x) => x.length > 0)); + + Object.entries(profile).forEach(([key, values]) => { + values.forEach(value => { + const keyword = `${key}=${value}`; + target.add(keyword); + }) + }); - return td; - } catch (e) { - logError('unable to format weborama rtd targeting data', e); - return {}; + bid.params.target = Array.from(target).join(sep); } -} -/** function that provides data handlers based on the configuration - * @param {ModuleParams} moduleParams - * @returns {Array} handlers - */ -function buildProfileHandlers(moduleParams) { - const profileHandlers = []; - - if (_weboCtxInitialized && moduleParams?.weboCtxConf) { - const weboCtxConf = moduleParams.weboCtxConf; - const [data, isDefault] = getContextualProfile(weboCtxConf); - if (!isEmpty(data)) { - profileHandlers.push({ - data: data, - metadata: { - user: false, - source: 'contextual', - isDefault: !!isDefault, - }, - setTargeting: weboCtxConf.setPrebidTargeting, - sendToBidders: weboCtxConf.sendToBidders, - onData: weboCtxConf.onData, - }) + /** handle rubicon bid + * @method + * @private + * @param {Object} bid + * @param {string} bid.bidder + * @param {Profile} profile + * @param {dataCallbackMetadata} metadata + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #handleRubiconBid(bid, profile, metadata) { + if (isBoolean(metadata.user)) { + const section = metadata.user ? 'visitor' : 'inventory'; + const base = `params.${section}`; + this.#assignProfileToObject(bid, base, profile); } else { - logMessage('skip contextual profile: no data'); + logMessage(`SKIP bidder '${bid.bidder}', data from '${metadata.source}' is not defined as user or site-centric`); } } - if (_weboUserDataInitialized && moduleParams?.weboUserDataConf) { - const weboUserDataConf = moduleParams.weboUserDataConf; - const [data, isDefault] = getWeboUserDataProfile(weboUserDataConf); - if (!isEmpty(data)) { - profileHandlers.push({ - data: data, - metadata: { - user: true, - source: 'wam', - isDefault: !!isDefault, - }, - setTargeting: weboUserDataConf.setPrebidTargeting, - sendToBidders: weboUserDataConf.sendToBidders, - onData: weboUserDataConf.onData, - }) + /** handle generic bid via ortb2 arbitrary data + * @method + * @private + * @param {Object} reqBidsConfigObj + * @param {Object} reqBidsConfigObj.ortb2Fragments + * @param {Object} reqBidsConfigObj.ortb2Fragments.bidder + * @param {string} bidder + * @param {Profile} profile + * @param {dataCallbackMetadata} metadata + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #handleBidViaORTB2(reqBidsConfigObj, bidder, profile, metadata) { + if (isBoolean(metadata.user)) { + logMessage(`bidder '${bidder}' is not directly supported, trying set data via bidder ortb2 fpd`); + const section = metadata.user ? 'user' : 'site'; + const base = `${bidder}.${section}.ext.data`; + + this.#assignProfileToObject(reqBidsConfigObj.ortb2Fragments?.bidder, base, profile); } else { - logMessage('skip wam profile: no data'); + logMessage(`SKIP unsupported bidder '${bidder}', data from '${metadata.source}' is not defined as user or site-centric`); } } - if (_sfbxLiteDataInitialized && moduleParams?.sfbxLiteDataConf) { - const sfbxLiteDataConf = moduleParams.sfbxLiteDataConf; - const [data, isDefault] = getSfbxLiteDataProfile(sfbxLiteDataConf); - if (!isEmpty(data)) { - profileHandlers.push({ - data: data, - metadata: { - user: false, - source: 'lite', - isDefault: !!isDefault, - }, - setTargeting: sfbxLiteDataConf.setPrebidTargeting, - sendToBidders: sfbxLiteDataConf.sendToBidders, - onData: sfbxLiteDataConf.onData, - }) - } else { - logMessage('skip sfbx lite profile: no data'); - } + /** + * assign profile to object + * @method + * @private + * @param {Object} destination + * @param {string} base + * @param {Profile} profile + * @returns {void} + */ + // eslint-disable-next-line no-dupe-class-members + #assignProfileToObject(destination, base, profile) { + Object.entries(profile).forEach(([key, values]) => { + const path = `${base}.${key}`; + deepSetValue(destination, path, values); + }) } - return profileHandlers; + /** + * @callback validatorCallback + * @param {string} target + * @returns {boolean} + */ + + /** + * @callback coerceCallback + * @param {*} input + * @returns {*} + */ + + /** + * wrap value into validator + * @method + * @private + * @param {*} value + * @param {coerceCallback} coerce + * @returns {validatorCallback} + * @throws will throw an error in case of unsupported type + */ + // eslint-disable-next-line no-dupe-class-members + #wrapValidatorCallback(value, coerce = (x) => x) { + if (isFn(value)) { + return value; + } + + if (isBoolean(value)) { + return (_) => value; + } + + if (isStr(value)) { + return (target) => { + return value == coerce(target); + }; + } + + if (isArray(value)) { + return (target) => { + return value.includes(coerce(target)); + }; + } + + throw `unexpected format: ${typeof value} (expects function, boolean, string or array)`; + } } -/** return contextual profile - * @param {WeboCtxConf} weboCtxConf - * @returns {Array} contextual profile + isDefault boolean flag +/** + * check if profile is valid + * @param {*} profile + * @returns {boolean} */ -function getContextualProfile(weboCtxConf) { - if (_weboContextualProfile) { - return [_weboContextualProfile, false]; +export function isValidProfile(profile) { + if (!isPlainObject(profile)) { + return false; } - const defaultContextualProfile = weboCtxConf.defaultProfile || {}; + return Object.values(profile).every((field) => isArray(field) && field.every(isStr)); +} + +/** + * bind callback with component + * @param {Component} component + * @returns {buildProfileHandlerCallback} + */ +function getContextualProfile(component /* equivalent to this */) { + /** return contextual profile + * @param {WeboCtxConf} weboCtxConf + * @returns {[Profile,boolean]} contextual profile + isDefault boolean flag + */ + return function (weboCtxConf) { + if (component.data) { + return [component.data, false]; + } - return [defaultContextualProfile, true]; + const defaultContextualProfile = weboCtxConf.defaultProfile || {}; + + return [defaultContextualProfile, true]; + } } -/** return weboUserData profile - * @param {WeboUserDataConf} weboUserDataConf - * @returns {Array} weboUserData profile + isDefault boolean flag +/** + * bind callback with component + * @param {Component} component + * @returns {buildProfileHandlerCallback} */ -function getWeboUserDataProfile(weboUserDataConf) { - return getDataFromLocalStorage(weboUserDataConf, - () => _weboUserDataUserProfile, - (data) => _weboUserDataUserProfile = data, - DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY, - LOCAL_STORAGE_USER_TARGETING_SECTION, - 'wam'); +function getWeboUserDataProfile(component /* equivalent to this */) { + /** return weboUserData profile + * @param {WeboUserDataConf} weboUserDataConf + * @returns {[Profile,boolean]} weboUserData profile + isDefault boolean flag + */ + return function (weboUserDataConf) { + return getDataFromLocalStorage(weboUserDataConf, + () => component.data, + (data) => component.data = data, + DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY, + LOCAL_STORAGE_USER_TARGETING_SECTION, + WEBO_USER_DATA_SOURCE_LABEL); + } } -/** return weboUserData profile - * @param {SfbxLiteDataConf} sfbxLiteDataConf - * @returns {Array} sfbxLiteData profile + isDefault boolean flag +/** + * bind callback with component + * @param {Component} component + * @returns {buildProfileHandlerCallback} */ -function getSfbxLiteDataProfile(sfbxLiteDataConf) { - return getDataFromLocalStorage(sfbxLiteDataConf, - () => _sfbxLiteDataProfile, - (data) => _sfbxLiteDataProfile = data, - DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY, - LOCAL_STORAGE_LITE_TARGETING_SECTION, - 'lite'); +function getSfbxLiteDataProfile(component /* equivalent to this */) { + /** return weboUserData profile + * @param {SfbxLiteDataConf} sfbxLiteDataConf + * @returns {[Profile,boolean]} sfbxLiteData profile + isDefault boolean flag + */ + return function getSfbxLiteDataProfile(sfbxLiteDataConf) { + return getDataFromLocalStorage(sfbxLiteDataConf, + () => component.data, + (data) => component.data = data, + DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY, + LOCAL_STORAGE_LITE_TARGETING_SECTION, + SFBX_LITE_DATA_SOURCE_LABEL); + } } +/** + * @callback cacheGetCallback + * @returns {Profile} + */ +/** + * @callback cacheSetCallback + * @param {Profile} profile + * @returns {void} + */ + /** return generic webo data profile * @param {WeboUserDataConf|SfbxLiteDataConf} weboDataConf * @param {cacheGetCallback} cacheGet * @param {cacheSetCallback} cacheSet - * @param {String} defaultLocalStorageProfileKey - * @param {String} targetingSection - * @param {String} source - * @returns {Array} webo (user|lite) data profile + isDefault boolean flag + * @param {string} defaultLocalStorageProfileKey + * @param {string} targetingSection + * @param {string} source + * @returns {[Profile,boolean]} webo (user|lite) data profile + isDefault boolean flag */ function getDataFromLocalStorage(weboDataConf, cacheGet, cacheSet, defaultLocalStorageProfileKey, targetingSection, source) { const defaultProfile = weboDataConf.defaultProfile || {}; - if (storage.localStorageIsEnabled() && !cacheGet()) { + if (storage.hasLocalStorage() && storage.localStorageIsEnabled() && !cacheGet()) { const localStorageProfileKey = weboDataConf.localStorageProfileKey || defaultLocalStorageProfileKey; const entry = storage.getDataFromLocalStorage(localStorageProfileKey); if (entry) { const data = JSON.parse(entry); - if (data && isPlainObject(data) && data.hasOwnProperty(targetingSection)) { + if (data && isPlainObject(data) && targetingSection in data) { + /** @type {profile} */ const profile = data[targetingSection]; const valid = isValidProfile(profile); if (!valid) { logWarn(`found invalid ${source} profile on local storage key ${localStorageProfileKey}, section ${targetingSection}`); + + return; } - if (valid && !isEmpty(data)) { + if (!isEmpty(data)) { cacheSet(profile); } } @@ -566,328 +1020,31 @@ function getDataFromLocalStorage(weboDataConf, cacheGet, cacheSet, defaultLocalS return [defaultProfile, true]; } - -/** function that will allow RTD sub-modules to modify the AdUnit object for each auction - * @param {Object} reqBidsConfigObj - * @param {doneCallback} onDone - * @param {Object} moduleConfig - * @returns {void} - */ -export function getBidRequestData(reqBidsConfigObj, onDone, moduleConfig) { - const moduleParams = moduleConfig?.params || {}; - - if (!_weboCtxInitialized) { - handleBidRequestData(reqBidsConfigObj, moduleParams); - - onDone(); - - return; - } - - const weboCtxConf = moduleParams.weboCtxConf || {}; - - fetchContextualProfile(weboCtxConf, (data) => { - logMessage('fetchContextualProfile on getBidRequestData is done'); - - setWeboContextualProfile(data); - }, () => { - handleBidRequestData(reqBidsConfigObj, moduleParams); - - onDone(); - }); -} - -/** function that handles bid request data - * @param {Object} reqBids - * @param {ModuleParams} moduleParams - * @returns {void} - */ -function handleBidRequestData(reqBids, moduleParams) { - const profileHandlers = buildProfileHandlers(moduleParams); - - if (isEmpty(profileHandlers)) { - logMessage('no data to send to bidders'); - return; - } - - const adUnits = reqBids.adUnits || getGlobal().adUnits; - - try { - adUnits.filter( - adUnit => adUnit.hasOwnProperty('bids') - ).forEach( - adUnit => adUnit.bids.forEach( - bid => profileHandlers.forEach(ph => { - // logMessage(`check if bidder '${bid.bidder}' and adunit '${adUnit.code} are share ${ph.metadata.source} data`); - - const cph = copyProfileHandler(ph); - if (ph.sendToBidders(bid, adUnit.code, cph.data, cph.metadata)) { - // logMessage(`handling bidder '${bid.bidder}' with ${ph.metadata.source} data`); - - handleBid(reqBids, bid, cph.data, ph.metadata); - } - }) - ) - ); - } catch (e) { - logError('unable to send data to bidders:', e); - } - - profileHandlers.forEach(ph => { - try { - const cph = copyProfileHandler(ph); - ph.onData(cph.data, cph.metadata); - } catch (e) { - logError(`error while executure onData callback with ${ph.metadata.source}-based data:`, e); - } - }); -} -/** function that handles bid request data - * @param {Object} ph profile handler - *@returns {Object} of deeply copy data and metadata - */ -function copyProfileHandler(ph) { - return { - data: deepClone(ph.data), - metadata: deepClone(ph.metadata), - }; -} - -/** @type {string} */ -const APPNEXUS = 'appnexus'; - -/** @type {string} */ -const PUBMATIC = 'pubmatic'; - -/** @type {string} */ -const RUBICON = 'rubicon'; - -/** @type {string} */ -const SMARTADSERVER = 'smartadserver'; - -/** @type {Object} */ -const bidderAliasRegistry = adapterManager.aliasRegistry || {}; - -/** handle individual bid - * @param reqBids - * @param {Object} bid - * @param {Object} profile - * @param {Object} metadata - * @returns {void} - */ -function handleBid(reqBids, bid, profile, metadata) { - const bidder = bidderAliasRegistry[bid.bidder] || bid.bidder; - - switch (bidder) { - // TODO: these special cases should not be necessary - all adapters should look into FPD, not just their params - case APPNEXUS: - handleAppnexusBid(bid, profile); - - break; - - case PUBMATIC: - handlePubmaticBid(bid, profile); - - break; - - case SMARTADSERVER: - handleSmartadserverBid(bid, profile); - - break; - case RUBICON: - handleRubiconBid(bid, profile, metadata); - - break; - default: - handleBidViaORTB2(reqBids, bid, profile, metadata); - } -} - -/** handle appnexus/xandr bid - * @param {Object} bid - * @param {Object} profile - * @returns {void} - */ -function handleAppnexusBid(bid, profile) { - const base = 'params.keywords'; - assignProfileToObject(bid, base, profile); -} - -/** handle pubmatic bid - * @param {Object} bid - * @param {Object} profile - * @returns {void} - */ -function handlePubmaticBid(bid, profile) { - const sep = '|'; - const subsep = ','; - const target = []; - - bid.params ||= {}; - - const data = bid.params.dctr; - if (data) { - data.split(sep).forEach(t => target.push(t)); - } - - Object.keys(profile).forEach(key => { - const value = profile[key].join(subsep); - const keyword = `${key}=${value}`; - if (target.indexOf(keyword) === -1) { - target.push(keyword); - } - }); - - bid.params.dctr = target.join(sep); -} - -/** handle smartadserver bid - * @param {Object} bid - * @param {Object} profile - * @returns {void} - */ -function handleSmartadserverBid(bid, profile) { - const sep = ';'; - const target = []; - - bid.params ||= {}; - - const data = bid.params.target; - if (data) { - data.split(sep).forEach(t => target.push(t)); - } - - Object.keys(profile).forEach(key => { - profile[key].forEach(value => { - const keyword = `${key}=${value}`; - if (target.indexOf(keyword) === -1) { - target.push(keyword); - } - }); - }); - - bid.params.target = target.join(sep); -} - -/** handle rubicon bid - * @param {Object} bid - * @param {Object} profile - * @param {Object} metadata - * @returns {void} - */ -function handleRubiconBid(bid, profile, metadata) { - if (isBoolean(metadata.user)) { - const section = (metadata.user) ? 'visitor' : 'inventory'; - const base = `params.${section}`; - assignProfileToObject(bid, base, profile); - } else { - logMessage(`SKIP bidder '${bid.bidder}', data from '${metadata.source}' is not defined as user or site-centric`); - } -} - -/** handle generic bid via ortb2 arbitrary data - * @param reqBids - * @param {Object} bid - * @param {Object} profile - * @param {Object} metadata - * @returns {void} - */ -function handleBidViaORTB2(reqBids, bid, profile, metadata) { - if (isBoolean(metadata.user)) { - logMessage(`bidder '${bid.bidder}' is not directly supported, trying set data via bidder ortb2 fpd`); - const section = ((metadata.user) ? 'user' : 'site'); - const base = `${bid.bidder}.${section}.ext.data`; - - assignProfileToObject(reqBids.ortb2Fragments?.bidder, base, profile); - } else { - logMessage(`SKIP unsupported bidder '${bid.bidder}', data from '${metadata.source}' is not defined as user or site-centric`); - } -} - -/** - * assign profile to object - * @param {Object} destination - * @param {string} base - * @param {Object} profile - * @returns {void} - */ -function assignProfileToObject(destination, base, profile) { - Object.keys(profile).forEach(key => { - const path = `${base}.${key}`; - deepSetValue(destination, path, profile[key]) - }) -} - -/** set bigsea contextual profile on module state - * @param {null|Object} data - * @returns {void} - */ -export function setWeboContextualProfile(data) { - if (data && isPlainObject(data) && isValidProfile(data) && !isEmpty(data)) { - _weboContextualProfile = data; - } -} - -/** onSuccess callback type - * @callback successCallback - * @param {null|Object} data - * @returns {void} - */ - -/** onDone callback type - * @callback doneCallback - * @returns {void} - */ - -/** Fetch Bigsea Contextual Profile - * @param {WeboCtxConf} weboCtxConf - * @param {successCallback} onSuccess callback - * @param {doneCallback} onDone callback - * @returns {void} - */ -function fetchContextualProfile(weboCtxConf, onSuccess, onDone) { - const targetURL = weboCtxConf.targetURL || document.URL; - const token = weboCtxConf.token; - const baseURLProfileAPI = weboCtxConf.baseURLProfileAPI || BASE_URL_CONTEXTUAL_PROFILE_API; - - let queryString = ''; - queryString = tryAppendQueryString(queryString, 'token', token); - queryString = tryAppendQueryString(queryString, 'url', targetURL); - - const urlProfileAPI = `https://${baseURLProfileAPI}/api/profile?${queryString}`; - - ajax(urlProfileAPI, { - success: (response, req) => { - if (req.status === 200) { - try { - const data = JSON.parse(response); - onSuccess(data); - onDone(); - } catch (e) { - onDone(); - logError('unable to parse weborama data', e); - throw e; - } - } else if (req.status === 204) { - onDone(); - } - }, - error: () => { - onDone(); - logError('unable to get weborama data'); - } +/** @type {Components} */ +const components = { + WeboCtx: { + initialized: false, + data: null, + user: false, + source: WEBO_CTX_SOURCE_LABEL, + callbackBuilder: getContextualProfile, + }, + WeboUserData: { + initialized: false, + data: null, + user: true, + source: WEBO_USER_DATA_SOURCE_LABEL, + callbackBuilder: getWeboUserDataProfile, + }, + SfbxLiteData: { + initialized: false, + data: null, + user: false, + source: SFBX_LITE_DATA_SOURCE_LABEL, + callbackBuilder: getSfbxLiteDataProfile, }, - null, { - method: 'GET', - withCredentials: false, - }); -} - -export const weboramaSubmodule = { - name: SUBMODULE_NAME, - init: init, - getTargetingData: getTargetingData, - getBidRequestData: getBidRequestData, }; +export const weboramaSubmodule = new WeboramaRtdProvider(components); + submodule(MODULE_NAME, weboramaSubmodule); diff --git a/modules/weboramaRtdProvider.md b/modules/weboramaRtdProvider.md index 88ec907c9a1..f86351fe214 100644 --- a/modules/weboramaRtdProvider.md +++ b/modules/weboramaRtdProvider.md @@ -109,6 +109,7 @@ On this section we will explain the `params.weboCtxConf` subconfiguration: | :------------ | :------------ | :------------ |:------------ | | token | String | Security Token provided by Weborama, unique per client | Mandatory | | targetURL | String | Url to be profiled in the contextual api | Optional. Defaults to `document.URL` | +| assetID | Function or String | if provided, we will call the document-profile api using this asset id. |Optional| | setPrebidTargeting|Various|If true, will use the contextual profile to set the prebid (GPT/GAM or AST) targeting of all adunits managed by prebid.js| Optional. Default is `params.setPrebidTargeting` (if any) or `true`.| | sendToBidders|Various|If true, will send the contextual profile to all bidders. If an array, will specify the bidders to send data| Optional. Default is `params.sendToBidders` (if any) or `true`.| | defaultProfile | Object | default value of the profile to be used when there are no response from contextual api (such as timeout)| Optional. Default is `{}` | @@ -383,6 +384,37 @@ pbjs.que.push(function () { }); ``` +An alternative version, using asset id instead of target url on contextual, can be found here: + +```javascript +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +pbjs.que.push(function () { + pbjs.setConfig({ + debug: true, + realTimeData: { + auctionDelay: 1000, + dataProviders: [{ + name: "weborama", + waitForIt: true, + params: { + weboCtxConf: { + token: "<>", // mandatory + assetID: "datasource:docId", // can be a callback to be executed in runtime and returns the identifier + setPrebidTargeting: true, // override param.setPrebidTargeting. default is true + sendToBidders: true, // override param.sendToBidders. default is true + defaultProfile: { // optional, used if nothing is found + webo_ctx: [ ... ], // contextual segments + webo_ds: [ ...], // data science segments + }, + enabled: true, + }, + ... + }); +}); +``` + Imagine we need to configure the following options using the previous example, we can write the configuration like the one below. ||contextual|wam|lite| diff --git a/test/spec/modules/weboramaRtdProvider_spec.js b/test/spec/modules/weboramaRtdProvider_spec.js index 523406dc492..bbc1c6d6f02 100644 --- a/test/spec/modules/weboramaRtdProvider_spec.js +++ b/test/spec/modules/weboramaRtdProvider_spec.js @@ -153,6 +153,289 @@ describe('weboramaRtdProvider', function() { }); }); + it('should use asset id when available and set gam targeting and send to bidders by default', function() { + let onDataResponse = {}; + const moduleConfig = { + params: { + weboCtxConf: { + token: 'foo', + assetID: 'datasource:docId', + targetURL: 'https://prebid.org', + onData: (data, meta) => { + onDataResponse = { + data: data, + meta: meta, + }; + }, + } + } + }; + const data = { + webo_vctx: ['foo', 'bar'], + }; + const adUnitCode = 'adunit1'; + const reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + bidder: {} + }, + adUnits: [{ + code: adUnitCode, + bids: [{ + bidder: 'smartadserver' + }, { + bidder: 'pubmatic' + }, { + bidder: 'appnexus' + }, { + bidder: 'rubicon' + }, { + bidder: 'other' + }] + }] + }; + + const onDoneSpy = sinon.spy(); + + expect(weboramaSubmodule.init(moduleConfig)).to.be.true; + weboramaSubmodule.getBidRequestData(reqBidsConfigObj, onDoneSpy, moduleConfig); + + let request = server.requests[0]; + + expect(request.method).to.equal('GET'); + expect(request.url).to.equal('https://ctx.weborama.com/api/document-profile?token=foo&assetId=datasource%3AdocId&url=https%3A%2F%2Fprebid.org&'); + expect(request.withCredentials).to.be.false; + + request.respond(200, responseHeader, JSON.stringify(data)); + + expect(onDoneSpy.calledOnce).to.be.true; + + const targeting = weboramaSubmodule.getTargetingData([adUnitCode], moduleConfig); + + expect(targeting).to.deep.equal({ + 'adunit1': data, + }); + + expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); + expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('webo_vctx=foo;webo_vctx=bar'); + expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('webo_vctx=foo,bar'); + expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(data); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ + inventory: data + }); + expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + expect(onDataResponse).to.deep.equal({ + data: data, + meta: { + user: false, + source: 'contextual', + isDefault: false, + }, + }); + }); + + it('should use asset id as callback when available and set gam targeting and send to bidders by default', function() { + let onDataResponse = {}; + const moduleConfig = { + params: { + weboCtxConf: { + token: 'foo', + assetID: () => 'datasource:docId', + targetURL: 'https://prebid.org', + onData: (data, meta) => { + onDataResponse = { + data: data, + meta: meta, + }; + }, + } + } + }; + const data = { + webo_vctx: ['foo', 'bar'], + }; + const adUnitCode = 'adunit1'; + const reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + bidder: {} + }, + adUnits: [{ + code: adUnitCode, + bids: [{ + bidder: 'smartadserver' + }, { + bidder: 'pubmatic' + }, { + bidder: 'appnexus' + }, { + bidder: 'rubicon' + }, { + bidder: 'other' + }] + }] + }; + + const onDoneSpy = sinon.spy(); + + expect(weboramaSubmodule.init(moduleConfig)).to.be.true; + weboramaSubmodule.getBidRequestData(reqBidsConfigObj, onDoneSpy, moduleConfig); + + let request = server.requests[0]; + + expect(request.method).to.equal('GET'); + expect(request.url).to.equal('https://ctx.weborama.com/api/document-profile?token=foo&assetId=datasource%3AdocId&url=https%3A%2F%2Fprebid.org&'); + expect(request.withCredentials).to.be.false; + + request.respond(200, responseHeader, JSON.stringify(data)); + + expect(onDoneSpy.calledOnce).to.be.true; + + const targeting = weboramaSubmodule.getTargetingData([adUnitCode], moduleConfig); + + expect(targeting).to.deep.equal({ + 'adunit1': data, + }); + + expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); + expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('webo_vctx=foo;webo_vctx=bar'); + expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('webo_vctx=foo,bar'); + expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(data); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ + inventory: data + }); + expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ + site: { + ext: { + data: data + }, + } + }); + expect(onDataResponse).to.deep.equal({ + data: data, + meta: { + user: false, + source: 'contextual', + isDefault: false, + }, + }); + }); + + it('should handle exception from asset id callback', function() { + let onDataResponse = {}; + const moduleConfig = { + params: { + weboCtxConf: { + token: 'foo', + assetID: () => { + throw new Error('ops'); + }, + targetURL: 'https://prebid.org', + onData: (data, meta) => { + onDataResponse = { + data: data, + meta: meta, + }; + }, + } + } + }; + const adUnitCode = 'adunit1'; + const reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + bidder: {} + }, + adUnits: [{ + code: adUnitCode, + bids: [{ + bidder: 'smartadserver' + }, { + bidder: 'pubmatic' + }, { + bidder: 'appnexus' + }, { + bidder: 'rubicon' + }, { + bidder: 'other' + }] + }] + }; + + const onDoneSpy = sinon.spy(); + + expect(weboramaSubmodule.init(moduleConfig)).to.be.true; + weboramaSubmodule.getBidRequestData(reqBidsConfigObj, onDoneSpy, moduleConfig); + + expect(server.requests.length).to.equal(0); + + expect(onDoneSpy.calledOnce).to.be.true; + + const targeting = weboramaSubmodule.getTargetingData([adUnitCode], moduleConfig); + + expect(targeting).to.deep.equal({}); + }); + + it('should handle case when callback return falsy value', function() { + let onDataResponse = {}; + const moduleConfig = { + params: { + weboCtxConf: { + token: 'foo', + assetID: () => '', + targetURL: 'https://prebid.org', + onData: (data, meta) => { + onDataResponse = { + data: data, + meta: meta, + }; + }, + } + } + }; + + const adUnitCode = 'adunit1'; + const reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + bidder: {} + }, + adUnits: [{ + code: adUnitCode, + bids: [{ + bidder: 'smartadserver' + }, { + bidder: 'pubmatic' + }, { + bidder: 'appnexus' + }, { + bidder: 'rubicon' + }, { + bidder: 'other' + }] + }] + }; + + const onDoneSpy = sinon.spy(); + + expect(weboramaSubmodule.init(moduleConfig)).to.be.true; + weboramaSubmodule.getBidRequestData(reqBidsConfigObj, onDoneSpy, moduleConfig); + + expect(server.requests.length).to.equal(0); + + expect(onDoneSpy.calledOnce).to.be.true; + + const targeting = weboramaSubmodule.getTargetingData([adUnitCode], moduleConfig); + + expect(targeting).to.deep.equal({}); + }); + describe('should set gam targeting and send to one specific bidder and multiple adunits', function() { const testcases = { 'single string': 'appnexus', @@ -1090,6 +1373,7 @@ describe('weboramaRtdProvider', function() { targeting: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY) @@ -1199,6 +1483,7 @@ describe('weboramaRtdProvider', function() { targeting: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY) @@ -1311,6 +1596,7 @@ describe('weboramaRtdProvider', function() { targeting: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY) @@ -1418,6 +1704,7 @@ describe('weboramaRtdProvider', function() { targeting: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY) @@ -1560,6 +1847,7 @@ describe('weboramaRtdProvider', function() { targeting: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY) @@ -1700,6 +1988,7 @@ describe('weboramaRtdProvider', function() { targeting: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY) @@ -1760,6 +2049,7 @@ describe('weboramaRtdProvider', function() { targeting: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY) @@ -1859,6 +2149,7 @@ describe('weboramaRtdProvider', function() { } }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); const adUnitCode = 'adunit1'; @@ -1932,6 +2223,7 @@ describe('weboramaRtdProvider', function() { } }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(false); const adUnitCode = 'adunit1'; @@ -2029,6 +2321,7 @@ describe('weboramaRtdProvider', function() { targeting: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY) @@ -2146,6 +2439,7 @@ describe('weboramaRtdProvider', function() { webo: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY) @@ -2254,6 +2548,7 @@ describe('weboramaRtdProvider', function() { webo: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY) @@ -2365,6 +2660,7 @@ describe('weboramaRtdProvider', function() { webo: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY) @@ -2471,6 +2767,7 @@ describe('weboramaRtdProvider', function() { webo: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY) @@ -2612,6 +2909,7 @@ describe('weboramaRtdProvider', function() { webo: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY) @@ -2751,6 +3049,7 @@ describe('weboramaRtdProvider', function() { webo: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY) @@ -2814,6 +3113,7 @@ describe('weboramaRtdProvider', function() { webo: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY) @@ -2912,6 +3212,7 @@ describe('weboramaRtdProvider', function() { } }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); const adUnitCode = 'adunit1'; @@ -2984,6 +3285,7 @@ describe('weboramaRtdProvider', function() { } }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(false); const adUnitCode = 'adunit1'; @@ -3044,6 +3346,85 @@ describe('weboramaRtdProvider', function() { }); }); + it('should use default profile if has no local storage', function() { + const defaultProfile = { + lite_hobbies: ['sport', 'cinéma'], + }; + let onDataResponse = {}; + const moduleConfig = { + params: { + sfbxLiteDataConf: { + setPrebidTargeting: true, + defaultProfile: defaultProfile, + onData: (data, meta) => { + onDataResponse = { + data: data, + meta: meta, + }; + }, + } + } + }; + + sandbox.stub(storage, 'hasLocalStorage').returns(false); + + const adUnitCode = 'adunit1'; + const reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + bidder: {}, + }, + adUnits: [{ + code: adUnitCode, + bids: [{ + bidder: 'smartadserver' + }, { + bidder: 'pubmatic' + }, { + bidder: 'appnexus' + }, { + bidder: 'rubicon' + }, { + bidder: 'other' + }] + }] + }; + const onDoneSpy = sinon.spy(); + + expect(weboramaSubmodule.init(moduleConfig)).to.be.true; + weboramaSubmodule.getBidRequestData(reqBidsConfigObj, onDoneSpy, moduleConfig); + + expect(onDoneSpy.calledOnce).to.be.true; + + const targeting = weboramaSubmodule.getTargetingData([adUnitCode], moduleConfig); + + expect(targeting).to.deep.equal({ + 'adunit1': defaultProfile, + }); + + expect(reqBidsConfigObj.adUnits[0].bids.length).to.equal(5); + expect(reqBidsConfigObj.adUnits[0].bids[0].params.target).to.equal('lite_hobbies=sport;lite_hobbies=cinéma'); + expect(reqBidsConfigObj.adUnits[0].bids[1].params.dctr).to.equal('lite_hobbies=sport,cinéma'); + expect(reqBidsConfigObj.adUnits[0].bids[2].params.keywords).to.deep.equal(defaultProfile); + expect(reqBidsConfigObj.adUnits[0].bids[3].params).to.deep.equal({ + inventory: defaultProfile, + }); + expect(reqBidsConfigObj.ortb2Fragments.bidder.other).to.deep.equal({ + site: { + ext: { + data: defaultProfile, + }, + }, + }); + expect(onDataResponse).to.deep.equal({ + data: defaultProfile, + meta: { + user: false, + source: 'lite', + isDefault: true, + }, + }); + }); it('should be possible update profile from callbacks for a given bidder/adUnitCode', function() { let onDataResponse = {}; const moduleConfig = { @@ -3080,6 +3461,7 @@ describe('weboramaRtdProvider', function() { webo: data, }; + sandbox.stub(storage, 'hasLocalStorage').returns(true); sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'getDataFromLocalStorage') .withArgs(DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY) From 0377e56a2b0d77fa3784f557d54c40747b7fac9e Mon Sep 17 00:00:00 2001 From: shahinrahbariasl <56240400+shahinrahbariasl@users.noreply.github.com> Date: Wed, 19 Oct 2022 12:13:11 -0400 Subject: [PATCH 036/367] IX Bid Adapter: send bid floor per size in format ext (#9084) * feat: send bid floor per size in format ext [PB-1311] * fix: remove typo [PB-1311] Co-authored-by: shahin.rahbariasl --- modules/ixBidAdapter.js | 13 +++++++++---- test/spec/modules/ixBidAdapter_spec.js | 12 ++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 6913c98013c..fc387fac76a 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -809,10 +809,15 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { }, }; - // We add sid in imp.ext.sid therefore, remove from banner.format[].ext - for (let bannerFormat of _bannerImpression.banner.format) { - if (bannerFormat.ext != null && bannerFormat.ext.sid != null) { - delete bannerFormat.ext.sid; + for (let i = 0; i < _bannerImpression.banner.format.length; i++) { + // We add sid in imp.ext.sid therefore, remove from banner.format[].ext + if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) { + delete _bannerImpression.banner.format[i].ext.sid; + } + + // add floor per size + if ('bidfloor' in impressionObjects[i]) { + _bannerImpression.banner.format[i].ext.bidfloor = impressionObjects[i].bidfloor } } diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index b110c9a4872..a1b79358e8c 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -1870,6 +1870,18 @@ describe('IndexexchangeAdapter', function () { expect(impression.banner.format[0].ext.fl).to.equal('x'); }); + it('banner multi size impression should have bidFloor both in imp and format ext obejcts', function () { + const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); + bid.params.bidFloor = 50; + bid.params.bidFloorCur = 'USD'; + const requestBidFloor = spec.buildRequests([bid], {})[0]; + const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + + expect(impression.bidfloor).to.equal(bid.params.bidFloor); + expect(impression.bidfloorcur).to.equal(bid.params.bidFloorCur); + expect(impression.banner.format[0].ext.bidfloor).to.equal(50); + }); + it('missing sizes impressions should contain floors from priceFloors module ', function () { const bid = utils.deepClone(ONE_BANNER[0]); bid.mediaTypes.banner.sizes.push([500, 400]) From 0f513e76ce26efb77092b4373b0280258429dd6e Mon Sep 17 00:00:00 2001 From: xwang202 <57196235+xwang202@users.noreply.github.com> Date: Thu, 20 Oct 2022 00:13:48 +0800 Subject: [PATCH 037/367] Freewheel-SSP Bid Adapter: add alias, update local param, and other additions (#9093) * freewheel add schain in the request * FreewheelSSP-Update update the bidder name and advertiserDomain * FreewheelSSP-Update code update * Freewheel-SSP Bid Adapter: code update --- modules/freewheel-sspBidAdapter.js | 55 ++++++++++++++++--- modules/freewheel-sspBidAdapter.md | 2 +- .../modules/freewheel-sspBidAdapter_spec.js | 29 ++++++++-- 3 files changed, 74 insertions(+), 12 deletions(-) diff --git a/modules/freewheel-sspBidAdapter.js b/modules/freewheel-sspBidAdapter.js index 38973f915b6..764e3d6e6c0 100644 --- a/modules/freewheel-sspBidAdapter.js +++ b/modules/freewheel-sspBidAdapter.js @@ -78,6 +78,39 @@ function getPricing(xmlNode) { return princingData; } +/* +* Read the StickyBrand extension with this format: +* +* +* +* +* +* +* @return {object} pricing data in format: {currency: "EUR", price:"1.000"} +*/ +function getAdvertiserDomain(xmlNode) { + var domain = []; + var brandExtNode; + 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') === 'StickyBrand') { + brandExtNode = node; + } + }); + + // Currently we only return one Domain + if (brandExtNode) { + var domainNode = brandExtNode.querySelector('Domain'); + domain.push(domainNode.textContent || domainNode.innerText); + } else { + logWarn('PREBID - ' + BIDDER_CODE + ': No bid received or missing StickyBrand extension.'); + } + + return domain; +} + function hashcode(inputString) { var hash = 0; var char; @@ -260,7 +293,7 @@ var getOutstreamScript = function(bid) { export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO], - aliases: ['stickyadstv'], // former name for freewheel-ssp + aliases: ['stickyadstv', 'freewheelssp'], // aliases for freewheel-ssp /** * Determines whether or not the given bid request is valid. * @@ -326,7 +359,7 @@ export const spec = { } } } - // TODO: is 'page' the right value here? + var location = bidderRequest?.refererInfo?.page; if (isValidUrl(location)) { requestParams.loc = location; @@ -409,6 +442,8 @@ export const spec = { const campaignId = getCampaignId(xmlDoc); const bannerId = getBannerId(xmlDoc); const topWin = getTopMostWindow(); + const advertiserDomains = getAdvertiserDomain(xmlDoc); + if (!topWin.freewheelssp_cache) { topWin.freewheelssp_cache = {}; } @@ -426,7 +461,7 @@ export const spec = { currency: princingData.currency, netRevenue: true, ttl: 360, - meta: { advertiserDomains: princingData.adomain && isArray(princingData.adomain) ? princingData.adomain : [] }, + meta: { advertiserDomains: advertiserDomains }, dealId: dealId, campaignId: campaignId, bannerId: bannerId @@ -454,14 +489,20 @@ export const spec = { } } + const syncs = []; if (syncOptions && syncOptions.pixelEnabled) { - return [{ + syncs.push({ type: 'image', url: USER_SYNC_URL + gdprParams - }]; - } else { - return []; + }); + } else if (syncOptions.iframeEnabled) { + syncs.push({ + type: 'iframe', + url: USER_SYNC_URL + gdprParams + }); } + + return syncs; }, }; diff --git a/modules/freewheel-sspBidAdapter.md b/modules/freewheel-sspBidAdapter.md index 0086aac6567..a445280f2b0 100644 --- a/modules/freewheel-sspBidAdapter.md +++ b/modules/freewheel-sspBidAdapter.md @@ -22,7 +22,7 @@ Module that connects to Freewheel ssp's demand sources bids: [ { - bidder: "freewheel-ssp", + bidder: "freewheelssp", // or use alias "freewheel-ssp" params: { zoneId : '277225' } diff --git a/test/spec/modules/freewheel-sspBidAdapter_spec.js b/test/spec/modules/freewheel-sspBidAdapter_spec.js index 81f4ecec074..7ef576fc7ec 100644 --- a/test/spec/modules/freewheel-sspBidAdapter_spec.js +++ b/test/spec/modules/freewheel-sspBidAdapter_spec.js @@ -483,6 +483,23 @@ describe('freewheelSSP BidAdapter Test', () => { 'bidId': '2', 'bidderRequestId': '3', 'auctionId': '4', + }, + { + 'bidder': 'freewheelssp', + 'params': { + 'zoneId': '277225', + 'format': 'test' + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'video': { + 'playerSize': [300, 600], + } + }, + 'sizes': [[300, 400]], + 'bidId': '2', + 'bidderRequestId': '3', + 'auctionId': '4', } ]; @@ -510,7 +527,8 @@ describe('freewheelSSP BidAdapter Test', () => { ' ' + ' ' + ' 0.2000' + - ' ' + + ' ' + + ' ' + ' ' + ' ' + ''; @@ -536,12 +554,15 @@ describe('freewheelSSP BidAdapter Test', () => { bannerId: '12345', vastXml: response, mediaType: 'video', - ad: ad + ad: ad, + meta: { + advertiserDomains: 'minotaur.com' + } } ]; let result = spec.interpretResponse(response, request[0]); - expect(result[0].meta.advertiserDomains).to.deep.equal([]); + expect(result[0].meta.advertiserDomains).to.deep.equal(['minotaur.com']); expect(result[0].dealId).to.equal('NRJ-PRO-00008'); expect(result[0].campaignId).to.equal('SMF-WOW-55555'); expect(result[0].bannerId).to.equal('12345'); @@ -570,7 +591,7 @@ describe('freewheelSSP BidAdapter Test', () => { ]; let result = spec.interpretResponse(response, request[0]); - expect(result[0].meta.advertiserDomains).to.deep.equal([]); + expect(result[0].meta.advertiserDomains).to.deep.equal(['minotaur.com']); expect(result[0].dealId).to.equal('NRJ-PRO-00008'); expect(result[0].campaignId).to.equal('SMF-WOW-55555'); expect(result[0].bannerId).to.equal('12345'); From c709f86d3f1ec3237ba6d37e9f95f99f3a7d2285 Mon Sep 17 00:00:00 2001 From: "Adserver.Online" <61009237+adserver-online@users.noreply.github.com> Date: Wed, 19 Oct 2022 19:18:19 +0300 Subject: [PATCH 038/367] Aso Bid Adapter: support schain (#9108) * SChain support * manually kick off tests * Inappropriate remove * Typo fixed * Example updated to avoid confusion Co-authored-by: dev Co-authored-by: Chris Huie --- modules/asoBidAdapter.js | 17 +++++++++++------ modules/asoBidAdapter.md | 11 +++++------ test/spec/modules/asoBidAdapter_spec.js | 4 ++-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/modules/asoBidAdapter.js b/modules/asoBidAdapter.js index 9469bc6b00c..83b182e4ca5 100644 --- a/modules/asoBidAdapter.js +++ b/modules/asoBidAdapter.js @@ -4,6 +4,7 @@ import { deepSetValue, getDNT, inIframe, + isArray, isFn, logWarn, parseSizesInput, @@ -19,6 +20,7 @@ const BIDDER_CODE = 'aso'; const DEFAULT_SERVER_URL = 'https://srv.aso1.net'; const DEFAULT_SERVER_PATH = '/prebid/bidder'; const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; +const VERSION = '$prebid.version$_1.1'; const TTL = 300; export const spec = { @@ -59,7 +61,7 @@ export const spec = { serverRequests.push({ method: 'POST', - url: getEnpoint(bidRequest), + url: getEndpoint(bidRequest), data: payload, options: { withCredentials: true, @@ -272,11 +274,9 @@ function createVideoImp(bidRequest, videoParams) { return imp; } -function getEnpoint(bidRequest) { - const serverUrl = bidRequest.params.serverUrl || DEFAULT_SERVER_URL; - const serverPath = bidRequest.params.serverPath || DEFAULT_SERVER_PATH; - - return serverUrl + serverPath + '?zid=' + bidRequest.params.zone + '&pbjs=$prebid.version$'; +function getEndpoint(bidRequest) { + const serverUrl = bidRequest.params.server || DEFAULT_SERVER_URL; + return serverUrl + DEFAULT_SERVER_PATH + '?zid=' + bidRequest.params.zone + '&pbjs=' + VERSION; } function getConsentsIds(gdprConsent) { @@ -341,6 +341,11 @@ function createBasePayload(bidRequest, bidderRequest) { deepSetValue(payload, 'user.ext.eids', eids); } + const schainData = deepAccess(bidRequest, 'schain.nodes'); + if (isArray(schainData) && schainData.length > 0) { + deepSetValue(payload, 'source.ext.schain', bidRequest.schain); + } + return payload; } diff --git a/modules/asoBidAdapter.md b/modules/asoBidAdapter.md index 32f4ebf5cef..f187389c5b5 100644 --- a/modules/asoBidAdapter.md +++ b/modules/asoBidAdapter.md @@ -14,12 +14,11 @@ For more information, please visit [Adserver.Online](https://adserver.online). # Parameters -| Name | Scope | Description | Example | Type | -|---------------|----------|-------------------------|-----------|-----------| -| `zone` | required | Zone ID | `73815` | `Integer` | -| `attr` | optional | Custom targeting params | `{keywords: ["a", "b"]}` | `Object` | - - +| Name | Scope | Description | Example | Type | +|-----------|----------|-------------------------|------------------------|------------| +| `zone` | required | Zone ID | `73815` | `Integer` | +| `attr` | optional | Custom targeting params | `{foo: ["a", "b"]}` | `Object` | +| `server` | optional | Custom bidder endpoint | `https://endpoint.url` | `String` | # Test parameters for banner ```js diff --git a/test/spec/modules/asoBidAdapter_spec.js b/test/spec/modules/asoBidAdapter_spec.js index 5ac44cb1db4..88016d1902c 100644 --- a/test/spec/modules/asoBidAdapter_spec.js +++ b/test/spec/modules/asoBidAdapter_spec.js @@ -125,7 +125,7 @@ describe('Adserver.Online bidding adapter', function () { expect(parsedRequestUrl.pathname).to.equal('/prebid/bidder'); const query = parsedRequestUrl.search; - expect(query.pbjs).to.equal('$prebid.version$'); + expect(query.pbjs).to.contain('$prebid.version$'); expect(query.zid).to.equal('1'); expect(request.data).to.exist; @@ -162,7 +162,7 @@ describe('Adserver.Online bidding adapter', function () { expect(parsedRequestUrl.pathname).to.equal('/prebid/bidder'); const query = parsedRequestUrl.search; - expect(query.pbjs).to.equal('$prebid.version$'); + expect(query.pbjs).to.contain('$prebid.version$'); expect(query.zid).to.equal('2'); expect(request.data).to.not.be.empty; From e459b91cc2deb83fe26f8f515dfb59157687fdc6 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Wed, 19 Oct 2022 09:19:13 -0700 Subject: [PATCH 039/367] Prebid core: restore bid-level `renderer` (#9128) --- src/auction.js | 6 ++-- test/spec/auctionmanager_spec.js | 49 +++++++++++++++++++------------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/auction.js b/src/auction.js index 26561d87d71..89b8f21d571 100644 --- a/src/auction.js +++ b/src/auction.js @@ -690,7 +690,7 @@ function getPreparedBidForAuction(bid, {index = auctionManager.index} = {}) { events.emit(CONSTANTS.EVENTS.BID_ADJUSTMENT, bid); // a publisher-defined renderer can be used to render bids - const adUnitRenderer = index.getAdUnit(bid).renderer; + const bidRenderer = index.getBidRequest(bid)?.renderer || index.getAdUnit(bid).renderer; // a publisher can also define a renderer for a mediaType const bidObjectMediaType = bid.mediaType; @@ -704,8 +704,8 @@ function getPreparedBidForAuction(bid, {index = auctionManager.index} = {}) { // the renderer for the mediaType takes precendence if (mediaTypeRenderer && mediaTypeRenderer.url && mediaTypeRenderer.render && !(mediaTypeRenderer.backupOnly === true && bid.renderer)) { renderer = mediaTypeRenderer; - } else if (adUnitRenderer && adUnitRenderer.url && adUnitRenderer.render && !(adUnitRenderer.backupOnly === true && bid.renderer)) { - renderer = adUnitRenderer; + } else if (bidRenderer && bidRenderer.url && bidRenderer.render && !(bidRenderer.backupOnly === true && bid.renderer)) { + renderer = bidRenderer; } if (renderer) { diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index 105401a62a4..e36b2ccbb07 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -736,6 +736,7 @@ describe('auctionmanager.js', function () { let auction; let ajaxStub; let bids; + let bidderRequests; let makeRequestsStub; before(function () { @@ -759,7 +760,8 @@ describe('auctionmanager.js', function () { adUnitCodes = [ADUNIT_CODE]; auction = auctionModule.newAuction({adUnits, adUnitCodes, callback: function() {}, cbTimeout: 3000}); bids = TEST_BIDS.slice(); - makeRequestsStub.returns(bids.map(b => mockBidRequest(b, {auctionId: auction.getAuctionId()}))); + bidderRequests = bids.map(b => mockBidRequest(b, {auctionId: auction.getAuctionId()})); + makeRequestsStub.returns(bidderRequests); indexAuctions = [auction]; createAuctionStub = sinon.stub(auctionModule, 'newAuction'); createAuctionStub.returns(auction); @@ -813,25 +815,32 @@ describe('auctionmanager.js', function () { assert.equal(registeredBid.adserverTargeting.extra, 'stuff'); }); - it('installs publisher-defined renderers on bids', function () { - let renderer = { - url: 'renderer.js', - render: (bid) => bid - }; - Object.assign(adUnits[0], {renderer}); - - let bids1 = Object.assign({}, - bids[0], - { - bidderCode: BIDDER_CODE, - mediaType: 'video-outstream', - } - ); - spec.interpretResponse.returns(bids1); - auction.callBids(); - const addedBid = auction.getBidsReceived().pop(); - assert.equal(addedBid.renderer.url, 'renderer.js'); - }); + describe('install publisher-defined renderers', () => { + Object.entries({ + 'on adUnit': () => adUnits[0], + 'on bid': () => bidderRequests[0].bids[0], + }).forEach(([t, getObj]) => { + it(t, () => { + let renderer = { + url: 'renderer.js', + render: (bid) => bid + }; + + let bids1 = Object.assign({}, + bids[0], + { + bidderCode: BIDDER_CODE, + mediaType: 'video-outstream', + } + ); + Object.assign(getObj(), {renderer}); + spec.interpretResponse.returns(bids1); + auction.callBids(); + const addedBid = auction.getBidsReceived().pop(); + assert.equal(addedBid.renderer.url, 'renderer.js'); + }) + }) + }) it('installs publisher-defined backup renderers on bids', function () { let renderer = { From 588568232bad7282be43729a6c8c2a8352c74204 Mon Sep 17 00:00:00 2001 From: el-chuck Date: Wed, 19 Oct 2022 18:27:38 +0200 Subject: [PATCH 040/367] Smaato Bid Adapter: Native support (#9089) * PREB-36 [Prebid.js] Native support * PREB-36 [Prebid.js] Native support - update to ortb native Co-authored-by: Ruslan Sibgatullin Co-authored-by: Bernhard Pickenbrock --- modules/smaatoBidAdapter.js | 59 +++- modules/smaatoBidAdapter.md | 78 +++++ test/spec/modules/smaatoBidAdapter_spec.js | 343 ++++++++++++++++++--- 3 files changed, 439 insertions(+), 41 deletions(-) diff --git a/modules/smaatoBidAdapter.js b/modules/smaatoBidAdapter.js index c783f35d915..18ce56c7a80 100644 --- a/modules/smaatoBidAdapter.js +++ b/modules/smaatoBidAdapter.js @@ -1,11 +1,14 @@ -import { deepAccess, getDNT, deepSetValue, logInfo, logError, isEmpty, getAdUnitSizes, fill, chunk, getMaxValueFromArray, getMinValueFromArray } from '../src/utils.js'; +import { deepAccess, isNumber, getDNT, deepSetValue, logInfo, logError, isEmpty, getAdUnitSizes, fill, chunk, getMaxValueFromArray, getMinValueFromArray } from '../src/utils.js'; +import {find} from '../src/polyfill.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; -import {ADPOD, BANNER, VIDEO} from '../src/mediaTypes.js'; +import {ADPOD, BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js'; +import CONSTANTS from '../src/constants.json'; +const { NATIVE_IMAGE_TYPES } = CONSTANTS; const BIDDER_CODE = 'smaato'; const SMAATO_ENDPOINT = 'https://prebid.ad.smaato.net/oapi/prebid'; -const SMAATO_CLIENT = 'prebid_js_$prebid.version$_1.6' +const SMAATO_CLIENT = 'prebid_js_$prebid.version$_1.7' const CURRENCY = 'USD'; const buildOpenRtbBidRequest = (bidRequest, bidderRequest) => { @@ -91,6 +94,12 @@ const buildOpenRtbBidRequest = (bidRequest, bidderRequest) => { } } + const nativeOrtbRequest = bidRequest.nativeOrtbRequest; + if (nativeOrtbRequest) { + const nativeRequest = Object.assign({}, requestTemplate, createNativeImp(bidRequest, nativeOrtbRequest)); + requests.push(nativeRequest); + } + return requests; } @@ -109,11 +118,11 @@ const buildServerRequest = (validBidRequest, data) => { export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER, VIDEO], + supportedMediaTypes: [BANNER, VIDEO, NATIVE], gvlid: 82, /** - * Determines whether or not the given bid request is valid. + * Determines whether 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. @@ -171,6 +180,7 @@ export const spec = { * Unpack the response from the server into a list of bids. * * @param {ServerResponse} serverResponse A successful response from the server. + * @param {BidRequest} bidRequest * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: (serverResponse, bidRequest) => { @@ -239,6 +249,11 @@ export const spec = { resultingBid.mediaType = VIDEO; bids.push(resultingBid); break; + case 'Native': + resultingBid.native = createNativeAd(bid.adm); + resultingBid.mediaType = NATIVE; + bids.push(resultingBid); + break; default: logInfo('[SMAATO] Invalid ad type:', smtAdType); } @@ -297,6 +312,13 @@ const createRichmediaAd = (adm) => { return markup + ''; }; +const createNativeAd = (adm) => { + const nativeResponse = JSON.parse(adm).native; + return { + ortb: nativeResponse + } +}; + function createBannerImp(bidRequest) { const adUnitSizes = getAdUnitSizes(bidRequest); const sizes = adUnitSizes.map((size) => ({w: size[0], h: size[1]})); @@ -342,6 +364,33 @@ function createVideoImp(bidRequest, videoMediaType) { }; } +function createNativeImp(bidRequest, nativeRequest) { + return { + imp: [{ + id: bidRequest.bidId, + tagid: deepAccess(bidRequest, 'params.adspaceId'), + bidfloor: getBidFloor(bidRequest, NATIVE, getNativeMainImageSize(nativeRequest)), + native: { + request: JSON.stringify(nativeRequest), + ver: '1.2' + } + }] + }; +} + +function getNativeMainImageSize(nativeRequest) { + const mainImage = find(nativeRequest.assets, asset => asset.hasOwnProperty('img') && asset.img.type === NATIVE_IMAGE_TYPES.MAIN) + if (mainImage) { + if (isNumber(mainImage.img.w) && isNumber(mainImage.img.h)) { + return [[mainImage.img.w, mainImage.img.h]] + } + if (isNumber(mainImage.img.wmin) && isNumber(mainImage.img.hmin)) { + return [[mainImage.img.wmin, mainImage.img.hmin]] + } + } + return [] +} + function createAdPodImp(bidRequest, videoMediaType) { const tagid = deepAccess(bidRequest, 'params.adbreakId') const bce = config.getConfig('adpod.brandCategoryExclusion') diff --git a/modules/smaatoBidAdapter.md b/modules/smaatoBidAdapter.md index 41e1c952f2a..170880c3fc0 100644 --- a/modules/smaatoBidAdapter.md +++ b/modules/smaatoBidAdapter.md @@ -63,6 +63,84 @@ var adUnits = [{ }]; ``` +For native adunits: + +``` +var adUnits = [{ + "code": "native unit", + "mediaTypes": { + native: { + ortb: { + ver: "1.2", + assets: [ + { + id: 1, + required: 1, + img: { + type: 3, + w: 150, + h: 50, + } + }, + { + id: 2, + required: 1, + img: { + type: 2, + w: 50, + h: 50 + } + }, + { + id: 3, + required: 1, + title: { + len: 80 + } + }, + { + id: 4, + required: 1, + data: { + type: 1 + } + }, + { + id: 5, + required: 1, + data: { + type: 2 + } + }, + { + id: 6, + required: 0, + data: { + type: 3 + } + }, + { + id: 7, + required: 0, + data: { + type: 12 + } + } + ] + }, + sendTargetingKeys: false, + } + }, + "bids": [{ + "bidder": "smaato", + "params": { + "publisherId": "1100042525", + "adspaceId": "130563103" + } + }] +}]; +``` + For adpod adunits: ``` diff --git a/test/spec/modules/smaatoBidAdapter_spec.js b/test/spec/modules/smaatoBidAdapter_spec.js index 99592765845..c7dbf1363e7 100644 --- a/test/spec/modules/smaatoBidAdapter_spec.js +++ b/test/spec/modules/smaatoBidAdapter_spec.js @@ -6,6 +6,7 @@ import {createEidsArray} from 'modules/userId/eids.js'; const ADTYPE_IMG = 'Img'; const ADTYPE_RICHMEDIA = 'Richmedia'; const ADTYPE_VIDEO = 'Video'; +const ADTYPE_NATIVE = 'Native'; const REFERRER = 'http://example.com/page.html' const CONSENT_STRING = 'HFIDUYFIUYIUYWIPOI87392DSU' @@ -421,7 +422,6 @@ describe('smaatoBidAdapterTest', () => { }, adUnitCode: '/19968336/header-bid-tag-0', transactionId: 'transactionId', - sizes: [[300, 50]], bidId: 'bidId', bidderRequestId: 'bidderRequestId', src: 'client', @@ -793,6 +793,168 @@ describe('smaatoBidAdapterTest', () => { }); }); + describe('buildRequests for native imps', () => { + const NATIVE_OPENRTB_REQUEST = { + ver: '1.2', + assets: [ + { + id: 4, + required: 1, + img: { + type: 3, + w: 150, + h: 50, + } + }, + { + id: 2, + required: 1, + img: { + type: 2, + w: 50, + h: 50 + } + }, + { + id: 0, + required: 1, + title: { + len: 80 + } + }, + { + id: 1, + required: 1, + data: { + type: 1 + } + }, + { + id: 3, + required: 1, + data: { + type: 2 + } + }, + { + id: 5, + required: 1, + data: { + type: 3 + } + }, + { + id: 6, + required: 1, + data: { + type: 4 + } + }, + { + id: 7, + required: 1, + data: { + type: 5 + } + }, + { + id: 8, + required: 1, + data: { + type: 6 + } + }, + { + id: 9, + required: 1, + data: { + type: 7 + } + }, + { + id: 10, + required: 0, + data: { + type: 8 + } + }, + { + id: 11, + required: 1, + data: { + type: 9 + } + }, + { + id: 12, + require: 0, + data: { + type: 10 + } + }, + { + id: 13, + required: 0, + data: { + type: 11 + } + }, + { + id: 14, + required: 1, + data: { + type: 12 + } + } + ] + }; + + const singleNativeBidRequest = { + bidder: 'smaato', + params: { + publisherId: 'publisherId', + adspaceId: 'adspaceId' + }, + nativeOrtbRequest: NATIVE_OPENRTB_REQUEST, + adUnitCode: '/19968336/header-bid-tag-0', + transactionId: 'transactionId', + bidId: 'bidId', + bidderRequestId: 'bidderRequestId', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0 + }; + + it('sends correct native imps', () => { + const reqs = spec.buildRequests([singleNativeBidRequest], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].id).to.be.equal('bidId'); + expect(req.imp[0].tagid).to.be.equal('adspaceId'); + expect(req.imp[0].bidfloor).to.be.undefined; + expect(req.imp[0].native.request).to.deep.equal(JSON.stringify(NATIVE_OPENRTB_REQUEST)); + }); + + it('sends bidfloor when configured', () => { + const singleNativeBidRequestWithFloor = Object.assign({}, singleNativeBidRequest); + singleNativeBidRequestWithFloor.getFloor = function(arg) { + if (arg.currency === 'USD' && + arg.mediaType === 'native' && + JSON.stringify(arg.size) === JSON.stringify([150, 50])) { + return { + currency: 'USD', + floor: 0.123 + } + } + } + const reqs = spec.buildRequests([singleNativeBidRequestWithFloor], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].bidfloor).to.be.equal(0.123); + }); + }); + describe('in-app requests', () => { const LOCATION = { lat: 33.3, @@ -932,50 +1094,131 @@ describe('smaatoBidAdapterTest', () => { } } + const NATIVE_RESPONSE = { + ver: '1.2', + link: { + url: 'https://link.url', + clicktrackers: [ + 'http://click.url/v1/click?e=prebid' + ] + }, + assets: [ + { + id: 0, + required: 1, + title: { + text: 'Title' + } + }, + { + id: 2, + required: 1, + img: { + type: 1, + url: 'https://logo.png', + w: 40, + h: 40 + } + }, + { + id: 4, + required: 1, + img: { + type: 3, + url: 'https://main.png', + w: 480, + h: 320 + } + }, + { + id: 3, + required: 1, + data: { + type: 2, + value: 'Desc' + } + }, + { + id: 14, + required: 1, + data: { + type: 12, + value: 'CTAText' + } + }, + { + id: 5, + required: 0, + data: { + type: 3, + value: '2 stars' + } + } + ], + eventtrackers: [ + { + event: 2, + method: 1, + url: 'https://js.url' + }, + { + event: 1, + method: 1, + url: 'http://view.url/v1/view?e=prebid' + } + ], + privacy: 'https://privacy.com/' + } + const buildOpenRtbBidResponse = (adType) => { let adm = ''; switch (adType) { case ADTYPE_IMG: - adm = JSON.stringify({ - image: { - img: { - url: 'https://prebid/static/ad.jpg', - w: 320, - h: 50, - ctaurl: 'https://prebid/track/ctaurl' - }, - impressiontrackers: [ - 'https://prebid/track/imp/1', - 'https://prebid/track/imp/2' - ], - clicktrackers: [ - 'https://prebid/track/click/1' - ] - } - }); + adm = JSON.stringify( + { + image: { + img: { + url: 'https://prebid/static/ad.jpg', + w: 320, + h: 50, + ctaurl: 'https://prebid/track/ctaurl' + }, + impressiontrackers: [ + 'https://prebid/track/imp/1', + 'https://prebid/track/imp/2' + ], + clicktrackers: [ + 'https://prebid/track/click/1' + ] + } + }); break; case ADTYPE_RICHMEDIA: - adm = JSON.stringify({ - richmedia: { - mediadata: { - content: '

RICHMEDIA CONTENT

', - w: 800, - h: 600 - }, - impressiontrackers: [ - 'https://prebid/track/imp/1', - 'https://prebid/track/imp/2' - ], - clicktrackers: [ - 'https://prebid/track/click/1' - ] - } - }); + adm = JSON.stringify( + { + richmedia: { + mediadata: { + content: '

RICHMEDIA CONTENT

', + w: 800, + h: 600 + }, + impressiontrackers: [ + 'https://prebid/track/imp/1', + 'https://prebid/track/imp/2' + ], + clicktrackers: [ + 'https://prebid/track/click/1' + ] + } + }); break; case ADTYPE_VIDEO: adm = ''; break; + case ADTYPE_NATIVE: + adm = JSON.stringify({ native: NATIVE_RESPONSE }) + break; default: throw Error('Invalid AdType'); } @@ -1030,7 +1273,7 @@ describe('smaatoBidAdapterTest', () => { }); describe('non ad pod', () => { - it('single image reponse', () => { + it('single image response', () => { const bids = spec.interpretResponse(buildOpenRtbBidResponse(ADTYPE_IMG), buildBidRequest()); expect(bids).to.deep.equal([ @@ -1056,7 +1299,7 @@ describe('smaatoBidAdapterTest', () => { ]); }); - it('single richmedia reponse', () => { + it('single richmedia response', () => { const bids = spec.interpretResponse(buildOpenRtbBidResponse(ADTYPE_RICHMEDIA), buildBidRequest()); expect(bids).to.deep.equal([ @@ -1108,6 +1351,34 @@ describe('smaatoBidAdapterTest', () => { ]); }); + it('single native response', () => { + const bids = spec.interpretResponse(buildOpenRtbBidResponse(ADTYPE_NATIVE), buildBidRequest()); + + expect(bids).to.deep.equal([ + { + requestId: '226416e6e6bf41', + cpm: 0.01, + width: 350, + height: 50, + native: { + ortb: NATIVE_RESPONSE + }, + ttl: 300, + creativeId: 'CR69381', + dealId: '12345', + netRevenue: true, + currency: 'USD', + mediaType: 'native', + meta: { + advertiserDomains: ['smaato.com'], + agencyId: 'CM6523', + networkName: 'smaato', + mediaType: 'native' + } + } + ]); + }); + it('ignores bid response with invalid ad type', () => { const serverResponse = buildOpenRtbBidResponse(ADTYPE_IMG); serverResponse.headers.get = (header) => { From 6bce8fe5158c426fe38fa1da68fba5aa5f86860a Mon Sep 17 00:00:00 2001 From: Joel Meyer Date: Wed, 19 Oct 2022 09:44:12 -0700 Subject: [PATCH 041/367] Betters docs for the fledgeForGpt module (#9127) Enhance the documentation with directions for publishers and bidder adapter maintainers. --- modules/fledgeForGpt.md | 124 ++++++++++++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 23 deletions(-) diff --git a/modules/fledgeForGpt.md b/modules/fledgeForGpt.md index 5672ac04618..3bb86cd5946 100644 --- a/modules/fledgeForGpt.md +++ b/modules/fledgeForGpt.md @@ -1,34 +1,33 @@ -## Overview +# Overview +This module allows Prebid.js to support FLEDGE by integrating it with GPT's [experimental FLEDGE +support](https://github.com/google/ads-privacy/tree/master/proposals/fledge-multiple-seller-testing). -This module enables the handling of fledge auction by GPT. -Bid adapters can now return component auction configs in addition to bids. +To learn more about FLEDGE in general, go [here](https://github.com/WICG/turtledove/blob/main/FLEDGE.md). -Those component auction configs will be registered to the GPT ad slot, -and GPT will be responsible to run fledge auction and render the winning fledge ad. +This document covers the steps necessary for publishers to enable FLEDGE on their inventory. It also describes +the changes Bid Adapters need to implement in order to support FLEDGE. -Find out more [here](https://github.com/WICG/turtledove/blob/main/FLEDGE.md). - -## Integration - -Build the fledge module into the Prebid.js package with: +## Publisher Integration +Publishers wishing to enable FLEDGE support must do two things. First, they must compile Prebid.js with support for this module. +This is accomplished by adding the `fledgeForGpt` module to the list of modules they are already using: ``` gulp build --modules=fledgeForGpt,... ``` -## Module Configuration Parameters +Second, they must enable FLEDGE in their Prebid.js configuration. To provide a high degree of flexiblity for testing, FLEDGE +settings exist at the module level, the bidder level, and the slot level. + +### Module Configuration +This module exposes the following settings: |Name |Type |Description |Notes | | :------------ | :------------ | :------------ |:------------ | |enabled | Boolean |Enable/disable the module |Defaults to `false` | -## Configuration +As noted above, FLEDGE support is disabled by default. To enable it, set the `enabled` value to `true` for this module +using the `setConfig` method of Prebid.js: -Fledge support need to be enabled at 3 levels: -- `fledgeForGpt` module -- bidder -- adunit -### enabling the fledgeForGpt module ```js pbjs.que.push(function() { pbjs.setConfig({ @@ -39,7 +38,17 @@ pbjs.que.push(function() { }); ``` -### enablingthe bidder +### Bidder Configuration +This module adds the following setting for bidders: + +|Name |Type |Description |Notes | +| :------------ | :------------ | :------------ |:------------ | +| fledgeEnabled | Boolean | Enable/disable a bidder to participate in FLEDGE | Defaults to `false` | + +In addition to enabling FLEDGE at the module level, individual bidders must also be enabled. This allows publishers to +selectively test with one or more bidders as they desire. To enable one or more bidders, use the `setBidderConfig` method +of Prebid.js: + ```js pbjs.setBidderConfig({ bidders: ["openx"], @@ -49,12 +58,81 @@ pbjs.setBidderConfig({ }); ``` -### enabling the adunit -ortb2Imp.ext.ae on the adunit must be set 1 +### AdUnit Configuration +Enabling an adunit for FLEDGE eligibility is accomplished by setting an attribute of the `ortb2Imp` object for that +adunit. + +|Name |Type |Description |Notes | +| :------------ | :------------ | :------------ |:------------ | +| ortb2Imp.ext.ae | Integer | Auction Environment: 1 indicates FLEDGE eligible, 0 indicates it is not | Absence indicates this is not FLEDGE eligible | + +The `ae` field stands for Auction Environment and was chosen to be consistent with the field that GAM passes to bidders +in their Open Bidding and Exchange Bidding APIs. More details on that can be found +[here](https://github.com/google/ads-privacy/tree/master/proposals/fledge-rtb#bid-request-changes-indicating-interest-group-auction-support) +In practice, this looks as follows: + ```js -ortb2Imp: { - ext: { - ae: 1 +pbjs.addAdUnits({ + code: "my-adunit-div", + // other config here + ortb2Imp: { + ext: { + ae: 1 + } + } +}); +``` + +## Bid Adapter Integration +Chrome has enabled a two-tier auction in FLEDGE. This allows multiple sellers (frequently SSPs) to act on behalf of the publisher with +a single entity serving as the final decision maker. In their [current approach](https://github.com/google/ads-privacy/tree/master/proposals/fledge-multiple-seller-testing), +GPT has opted to run the final auction layer while allowing other SSPs/sellers to participate as +[Component Auctions](https://github.com/WICG/turtledove/blob/main/FLEDGE.md#21-initiating-an-on-device-auction) which feed their +bids to the final layer. To learn more about Component Auctions, go [here](https://github.com/WICG/turtledove/blob/main/FLEDGE.md#24-scoring-bids-in-component-auctions). + +The FLEDGE auction, including Component Auctions, are configured via an `AuctionConfig` object that defines the parameters of the auction for a given +seller. This module enables FLEDGE support by allowing bid adaptors to return `AuctionConfig` objects in addition to bids. If a bid adaptor returns an +`AuctionConfig` object, Prebid.js will register it with the appropriate GPT ad slot so the bidder can participate as a Component Auction in the overall +FLEDGE auction for that slot. More details on the GPT API can be found [here](https://developers.google.com/publisher-tag/reference#googletag.config.componentauctionconfig). + +Modifying a bid adapter to support FLEDGE is a straightforward process and consists of the following steps: +1. Detecting when a bid request is FLEDGE eligible +2. Responding with AuctionConfig + +FLEDGE eligibility is made available to bid adapters through the `bidderRequest.fledgeEnabled` field. +The [`bidderRequest`](https://docs.prebid.org/dev-docs/bidder-adaptor.html#bidderrequest-parameters) object is passed to +the [`buildRequests`](https://docs.prebid.org/dev-docs/bidder-adaptor.html#building-the-request) method of an adapter. Bid adapters +who wish to participate should read this flag and pass it to their server. FLEDGE eligibility depends on a number of parameters: + +1. Chrome enablement +2. Publisher participatipon in the [Origin Trial](https://developer.chrome.com/docs/privacy-sandbox/unified-origin-trial/#configure) +3. Publisher Prebid.js configuration (detailed above) + +When a bid request is FLEDGE enabled, a bid adapter can return a tuple consisting of bids and AuctionConfig objects rather than just a list of bids: + +```js +function interpretResponse(resp, req) { + // Load the bids from the response - this is adapter specific + const bids = parseBids(resp); + + // Load the auctionConfigs from the response - also adapter specific + const auctionConfigs = parseAuctionConfigs(resp); + + if (auctionConfigs) { + // Return a tuple of bids and auctionConfigs. It is possible that bids could be null. + return {bids, auctionConfigs}; + } else { + return bids; } } ``` + +An AuctionConfig must be associated with an adunit and auction, and this is accomplished using the value in the `bidId` field from the objects in the +`validBidRequests` array passed to the `buildRequests` function - see [here](https://docs.prebid.org/dev-docs/bidder-adaptor.html#ad-unit-params-in-the-validbidrequests-array) +for more details. This means that the AuctionConfig objects returned from `interpretResponse` must contain a `bidId` field whose value corresponds to +the request it should be associated with. This may raise the question: why isn't the AuctionConfig object returned as part of the bid? The +answer is that it's possible to participate in the FLEDGE auction without returning a contextual bid. + +An example of this can be seen in the OpenX OpenRTB bid adapter [here](https://github.com/prebid/Prebid.js/blob/master/modules/openxOrtbBidAdapter.js#L327). + +Other than the addition of the `bidId` field, the AuctionConfig object should adhere to the requirements set forth in FLEDGE. The details of creating an AuctionConfig object are beyond the scope of this document. From 5f389fcce98e63a557bc81c5938520f3b59ecbf6 Mon Sep 17 00:00:00 2001 From: Adish Rao <30475159+adish1997@users.noreply.github.com> Date: Thu, 20 Oct 2022 00:28:43 +0530 Subject: [PATCH 042/367] logging fix multi ra and request url (#9090) Co-authored-by: adish --- modules/medianetAnalyticsAdapter.js | 48 ++++++++------- .../modules/medianetAnalyticsAdapter_spec.js | 58 ++++++++++++++++--- 2 files changed, 76 insertions(+), 30 deletions(-) diff --git a/modules/medianetAnalyticsAdapter.js b/modules/medianetAnalyticsAdapter.js index b7abe5f56cf..d2d3d2bf888 100644 --- a/modules/medianetAnalyticsAdapter.js +++ b/modules/medianetAnalyticsAdapter.js @@ -40,6 +40,7 @@ const MEDIANET_BIDDER_CODE = 'medianet'; const PREBID_VERSION = $$PREBID_GLOBAL$$.version; const ERROR_CONFIG_JSON_PARSE = 'analytics_config_parse_fail'; const ERROR_CONFIG_FETCH = 'analytics_config_ajax_fail'; +const ERROR_WINNING_BID_ABSENT = 'winning_bid_absent'; const BID_SUCCESS = 1; const BID_NOBID = 2; const BID_TIMEOUT = 3; @@ -51,7 +52,7 @@ const CONFIG_PASS = 1; const CONFIG_ERROR = 3; const VALID_URL_KEY = ['canonical_url', 'og_url', 'twitter_url']; -const DEFAULT_URL_KEY = 'page'; +const DEFAULT_URL_KEY = 'topmostLocation'; const LOG_TYPE = { APPR: 'APPR', @@ -62,6 +63,7 @@ let auctions = {}; let config; let pageDetails; let logsQueue = []; +let errorQueue = []; class ErrorLogger { constructor(event, additionalData) { @@ -78,6 +80,7 @@ class ErrorLogger { send() { let url = EVENT_PIXEL_URL + '?' + formatQS(this); + errorQueue.push(url); triggerPixel(url); } } @@ -160,7 +163,7 @@ class Configure { init() { // Forces Logging % to 100% - let urlObj = URL.parseUrl(pageDetails.page); + let urlObj = URL.parseUrl(pageDetails.topmostLocation); if (deepAccess(urlObj, 'search.medianet_test') || urlObj.hostname === 'localhost') { this.loggingPercent = 100; this.ajaxState = CONFIG_PASS; @@ -194,17 +197,10 @@ class PageDetail { this.canonical_url = refererInfo.canonicalUrl; this.og_url = ogUrl; this.twitter_url = twitterUrl; + this.topmostLocation = refererInfo.topmostLocation; this.screen = this._getWindowSize(); } - _getTopWindowReferrer() { - try { - return window.top.document.referrer; - } catch (e) { - return document.referrer; - } - } - _getWindowSize() { let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || -1; let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || -1; @@ -235,7 +231,7 @@ class PageDetail { getLoggingData() { return { - requrl: this[config.urlToConsume] || this.page, + requrl: this[config.urlToConsume] || this.topmostLocation, dn: this.domain, ref: this.referrer, screen: this.screen @@ -402,10 +398,6 @@ class Auction { .map((bid) => bid.getLoggingData()); } - getWinnerAdslotBid(adslot) { - return this.getAdslotBids(adslot).filter((bid) => bid.winner); - } - _mergeFieldsToLog(objParams) { let logParams = []; let value; @@ -641,17 +633,22 @@ function setTargetingHandler(params) { } function bidWonHandler(bid) { - const { requestId, auctionId, adUnitCode } = bid; + const { auctionId, adUnitCode, adId } = bid; if (!(auctions[auctionId] instanceof Auction)) { return; } - let bidObj = auctions[auctionId].findBid('bidId', requestId); + let bidObj = auctions[auctionId].findBid('adId', adId); if (!(bidObj instanceof Bid)) { + new ErrorLogger(ERROR_WINNING_BID_ABSENT, { + adId: adId, + acid: auctionId, + adUnitCode, + }).send(); return; } auctions[auctionId].bidWonTime = Date.now(); bidObj.winner = 1; - sendEvent(auctionId, adUnitCode, LOG_TYPE.RA); + sendEvent(auctionId, adUnitCode, LOG_TYPE.RA, bidObj.adId); } function isSampled() { @@ -662,12 +659,12 @@ function isValidAuctionAdSlot(acid, adtag) { return (auctions[acid] instanceof Auction) && (auctions[acid].adSlots[adtag] instanceof AdSlot); } -function sendEvent(id, adunit, logType) { +function sendEvent(id, adunit, logType, adId) { if (!isValidAuctionAdSlot(id, adunit)) { return; } if (logType === LOG_TYPE.RA) { - fireAuctionLog(id, adunit, logType); + fireAuctionLog(id, adunit, logType, adId); } else { fireApPrLog(id, adunit, logType) } @@ -688,7 +685,7 @@ function getCommonLoggingData(acid, adtag) { return Object.assign(commonParams, adunitParams, auctionParams); } -function fireAuctionLog(acid, adtag, logType) { +function fireAuctionLog(acid, adtag, logType, adId) { let commonParams = getCommonLoggingData(acid, adtag); commonParams.lgtp = logType; let targeting = deepAccess(commonParams, 'targ'); @@ -699,7 +696,10 @@ function fireAuctionLog(acid, adtag, logType) { let bidParams; if (logType === LOG_TYPE.RA) { - bidParams = auctions[acid].getWinnerAdslotBid(adtag); + const winningBidObj = auctions[acid].findBid('adId', adId); + if (!winningBidObj) return; + const winLogData = winningBidObj.getLoggingData(); + bidParams = [winLogData]; commonParams.lper = 1; } else { bidParams = auctions[acid].getAdslotBids(adtag).map(({winner, ...restParams}) => restParams); @@ -767,8 +767,12 @@ let medianetAnalytics = Object.assign(adapter({URL, analyticsType}), { getlogsQueue() { return logsQueue; }, + getErrorQueue() { + return errorQueue; + }, clearlogsQueue() { logsQueue = []; + errorQueue = []; auctions = {}; }, track({ eventType, args }) { diff --git a/test/spec/modules/medianetAnalyticsAdapter_spec.js b/test/spec/modules/medianetAnalyticsAdapter_spec.js index 0ce26ab4863..b75437f2ccd 100644 --- a/test/spec/modules/medianetAnalyticsAdapter_spec.js +++ b/test/spec/modules/medianetAnalyticsAdapter_spec.js @@ -8,6 +8,8 @@ const { EVENTS: { AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, NO_BID, BID_TIMEOUT, AUCTION_END, SET_TARGETING, BID_WON } } = CONSTANTS; +const ERROR_WINNING_BID_ABSENT = 'winning_bid_absent'; + const MOCK = { Ad_Units: [{'code': 'div-gpt-ad-1460505748561-0', 'mediaTypes': {'banner': {'sizes': [[300, 250]]}}, 'bids': [], 'ext': {'prop1': 'value1'}}], MULTI_FORMAT_TWIN_AD_UNITS: [{'code': 'div-gpt-ad-1460505748561-0', 'mediaTypes': {'banner': {'sizes': [[300, 250]]}, 'native': {'image': {'required': true, 'sizes': [150, 50]}}}, 'bids': [], 'ext': {'prop1': 'value1'}}, {'code': 'div-gpt-ad-1460505748561-0', 'mediaTypes': {'video': {'playerSize': [640, 480], 'context': 'instream'}}, 'bids': [], 'ext': {'prop1': 'value1'}}], @@ -22,11 +24,15 @@ const MOCK = { SET_TARGETING: {'div-gpt-ad-1460505748561-0': {'prebid_test': '1', 'hb_format': 'banner', 'hb_source': 'client', 'hb_size': '300x250', 'hb_pb': '2.00', 'hb_adid': '3e6e4bce5c8fb3', 'hb_bidder': 'medianet', 'hb_format_medianet': 'banner', 'hb_source_medianet': 'client', 'hb_size_medianet': '300x250', 'hb_pb_medianet': '2.00', 'hb_adid_medianet': '3e6e4bce5c8fb3', 'hb_bidder_medianet': 'medianet'}}, NO_BID_SET_TARGETING: {'div-gpt-ad-1460505748561-0': {}}, BID_WON: {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'statusMessage': 'Bid available', 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}, + BID_WON_2: {'bidderCode': 'appnexus', 'width': 300, 'height': 250, 'statusMessage': 'Bid available', 'adId': '3e6e4bce5c8fb4', 'requestId': '28248b0e6aecd5', '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': 'appnexus', 'hb_adid': '3e6e4bce5c8fb4', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'publisherId': 'test123', 'placementId': '451466393'}]}, + BID_WON_UNKNOWN: {'bidderCode': 'appnexus', 'width': 300, 'height': 250, 'statusMessage': 'Bid available', 'adId': '3e6e4bce5c8fkk', 'requestId': '28248b0e6aecd5', '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': 'appnexus', 'hb_adid': '3e6e4bce5c8fb4', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'publisherId': 'test123', 'placementId': '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}], - BIDS_SAME_REQ_DIFF_CPM: [{'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fgg', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.10, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}, {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb4', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 1.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.10, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 278, 'pbLg': '1.00', 'pbMg': '1.20', 'pbHg': '1.29', 'pbAg': '1.25', 'pbDg': '1.29', 'pbCg': '1.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '1.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}], - BIDS_SAME_REQ_EQUAL_CPM: [{'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fgg', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.1, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}, {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb4', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.1, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 286, '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'}]}] -} + BIDS_SAME_REQ_DIFF_CPM: [{'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.10, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}, {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb4', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 1.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.10, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 278, 'pbLg': '1.00', 'pbMg': '1.20', 'pbHg': '1.29', 'pbAg': '1.25', 'pbDg': '1.29', 'pbCg': '1.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '1.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}], + BIDS_SAME_REQ_EQUAL_CPM: [{'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.1, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}, {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb4', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.1, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 286, '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'}]}], + BID_RESPONSES: [{'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.1, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'params': [{'cid': 'test123', 'crid': '451466393'}]}, {'bidderCode': 'appnexus', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb4', 'requestId': '28248b0e6aecd5', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 1.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.1, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 278, 'pbLg': '1.00', 'pbMg': '1.20', 'pbHg': '1.29', 'pbAg': '1.25', 'pbDg': '1.29', 'pbCg': '1.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'appnexus', 'hb_adid': '3e6e4bce5c8fb4', 'hb_pb': '1.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'params': [{'publisherId': 'test123', 'placementId': '451466393'}]}], + BID_REQUESTS: [{'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}, {'bidderCode': 'appnexus', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'bids': [{'bidder': 'appnexus', 'params': {'publisherId': 'TEST_CID', 'placementId': '451466393'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]], 'ext': ['asdads']}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'sizes': [[300, 250]], 'bidId': '28248b0e6aecd5', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'}], 'auctionStart': 1584563605739, 'timeout': 6000, 'uspConsent': '1YY', 'start': 1584563605743}] +}; function performAuctionWithFloorConfig() { events.emit(AUCTION_INIT, Object.assign({}, MOCK.AUCTION_INIT_WITH_FLOOR, {adUnits: MOCK.Ad_Units})); @@ -87,6 +93,14 @@ function performStandardAuctionMultiBidWithSameRequestId(bidRespArray) { events.emit(BID_WON, MOCK.BID_WON); } +function performStandardAuctionMultiBidResponseNoWin() { + events.emit(AUCTION_INIT, Object.assign({}, MOCK.AUCTION_INIT, {adUnits: MOCK.Ad_Units})); + MOCK.BID_REQUESTS.forEach(bidReq => events.emit(BID_REQUESTED, bidReq)); + MOCK.BID_RESPONSES.forEach(bidResp => events.emit(BID_RESPONSE, bidResp)); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(SET_TARGETING, MOCK.SET_TARGETING); +} + function getQueryData(url, decode = false) { const queryArgs = url.split('?')[1].split('&'); return queryArgs.reduce((data, arg) => { @@ -113,7 +127,7 @@ describe('Media.net Analytics Adapter', function() { options: { cid: CUSTOMER_ID } - } + }; beforeEach(function () { sandbox = sinon.sandbox.create(); }); @@ -280,25 +294,53 @@ describe('Media.net Analytics Adapter', function() { it('should pick winning bid if multibids with same request id', function() { performStandardAuctionMultiBidWithSameRequestId(MOCK.BIDS_SAME_REQ_DIFF_CPM); let winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner)[0]; - expect(winningBid.adid).equals('3e6e4bce5c8fgg'); + expect(winningBid.adid).equals('3e6e4bce5c8fb3'); medianetAnalytics.clearlogsQueue(); const reversedResponseArray = [].concat(MOCK.BIDS_SAME_REQ_DIFF_CPM).reverse(); performStandardAuctionMultiBidWithSameRequestId(reversedResponseArray); winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner)[0]; - expect(winningBid.adid).equals('3e6e4bce5c8fgg'); + expect(winningBid.adid).equals('3e6e4bce5c8fb3'); }); it('should pick winning bid if multibids with same request id and equal cpm', function() { performStandardAuctionMultiBidWithSameRequestId(MOCK.BIDS_SAME_REQ_EQUAL_CPM); let winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner)[0]; - expect(winningBid.adid).equals('3e6e4bce5c8fgg'); + expect(winningBid.adid).equals('3e6e4bce5c8fb3'); medianetAnalytics.clearlogsQueue(); const reversedResponseArray = [].concat(MOCK.BIDS_SAME_REQ_EQUAL_CPM).reverse(); performStandardAuctionMultiBidWithSameRequestId(reversedResponseArray); winningBid = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter(log => log.winner)[0]; - expect(winningBid.adid).equals('3e6e4bce5c8fgg'); + expect(winningBid.adid).equals('3e6e4bce5c8fb3'); + }); + + it('should pick single winning bid per bid won', function() { + performStandardAuctionMultiBidResponseNoWin(); + const queue = medianetAnalytics.getlogsQueue(); + queue.length = 0; + + events.emit(BID_WON, MOCK.BID_WON); + let winningBids = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)); + expect(winningBids[0].adid).equals(MOCK.BID_WON.adId); + expect(winningBids.length).equals(1); + events.emit(BID_WON, MOCK.BID_WON_2); + winningBids = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)); + expect(winningBids[1].adid).equals(MOCK.BID_WON_2.adId); + expect(winningBids.length).equals(2); + }); + + it('should ignore unknown winning bid and log error', function() { + performStandardAuctionMultiBidResponseNoWin(); + const queue = medianetAnalytics.getlogsQueue(); + queue.length = 0; + + events.emit(BID_WON, MOCK.BID_WON_UNKNOWN); + let winningBids = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)); + let errors = medianetAnalytics.getErrorQueue().map((log) => getQueryData(log)); + expect(winningBids.length).equals(0); + expect(errors.length).equals(1); + expect(errors[0].event).equals(ERROR_WINNING_BID_ABSENT); }); }); }); From 459a2eed38b7fe9b6f7a4d631d55d94f1e41e1ba Mon Sep 17 00:00:00 2001 From: github-tom-kuhnen <101572885+github-tom-kuhnen@users.noreply.github.com> Date: Thu, 20 Oct 2022 07:29:13 +0200 Subject: [PATCH 043/367] Teads adapter: use user id module and send user-agent client hints (#9130) --- modules/teadsBidAdapter.js | 34 ++++-- test/spec/modules/teadsBidAdapter_spec.js | 125 ++++++++++++++++++++-- 2 files changed, 145 insertions(+), 14 deletions(-) diff --git a/modules/teadsBidAdapter.js b/modules/teadsBidAdapter.js index 9ce00d2d3eb..56b21d0d4cf 100644 --- a/modules/teadsBidAdapter.js +++ b/modules/teadsBidAdapter.js @@ -55,11 +55,13 @@ export const spec = { deviceWidth: screen.width, hb_version: '$prebid.version$', ...getSharedViewerIdParameters(validBidRequests), - ...getFirstPartyTeadsIdParameter() + ...getFirstPartyTeadsIdParameter(validBidRequests) }; - if (validBidRequests[0].schain) { - payload.schain = validBidRequests[0].schain; + const firstBidRequest = validBidRequests[0]; + + if (firstBidRequest.schain) { + payload.schain = firstBidRequest.schain; } let gdpr = bidderRequest.gdprConsent; @@ -80,6 +82,11 @@ export const spec = { payload.us_privacy = bidderRequest.uspConsent; } + const userAgentClientHints = deepAccess(firstBidRequest, 'ortb2.device.sua'); + if (userAgentClientHints) { + payload.userAgentClientHints = userAgentClientHints; + } + const payloadString = JSON.stringify(payload); return { method: 'POST', @@ -261,14 +268,25 @@ function _validateId(id) { /** * Get the first-party cookie Teads ID parameter to be sent in bid request. + * @param validBidRequests an array of bids * @returns `{} | {firstPartyCookieTeadsId: string}` */ -function getFirstPartyTeadsIdParameter() { - if (!storage.cookiesAreEnabled()) { - return {}; +function getFirstPartyTeadsIdParameter(validBidRequests) { + const firstPartyTeadsIdFromUserIdModule = deepAccess(validBidRequests, '0.userId.teadsId'); + + if (firstPartyTeadsIdFromUserIdModule) { + return {firstPartyCookieTeadsId: firstPartyTeadsIdFromUserIdModule}; } - const firstPartyTeadsId = storage.getCookie(FP_TEADS_ID_COOKIE_NAME); - return firstPartyTeadsId ? { firstPartyCookieTeadsId: firstPartyTeadsId } : {}; + + if (storage.cookiesAreEnabled(null)) { + const firstPartyTeadsIdFromCookie = storage.getCookie(FP_TEADS_ID_COOKIE_NAME, null); + + if (firstPartyTeadsIdFromCookie) { + return {firstPartyCookieTeadsId: firstPartyTeadsIdFromCookie}; + } + } + + return {}; } registerBidder(spec); diff --git a/test/spec/modules/teadsBidAdapter_spec.js b/test/spec/modules/teadsBidAdapter_spec.js index 254f23d011e..e981d80c8ae 100644 --- a/test/spec/modules/teadsBidAdapter_spec.js +++ b/test/spec/modules/teadsBidAdapter_spec.js @@ -418,6 +418,74 @@ describe('teadsBidAdapter', () => { }); }); + it('should add userAgentClientHints info to payload if available', function () { + const bidRequest = Object.assign({}, bidRequests[0], { + ortb2: { + device: { + sua: { + source: 2, + platform: { + brand: 'macOS', + version: [ '12', '4', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + } + ], + mobile: 0, + model: '', + bitness: '64', + architecture: 'x86' + } + } + } + }); + + const requestWithUserAgentClientHints = spec.buildRequests([bidRequest], bidderResquestDefault); + const payload = JSON.parse(requestWithUserAgentClientHints.data); + + expect(payload.userAgentClientHints).to.exist; + expect(payload.userAgentClientHints).to.deep.equal({ + source: 2, + platform: { + brand: 'macOS', + version: [ '12', '4', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + } + ], + mobile: 0, + model: '', + bitness: '64', + architecture: 'x86' + } + ); + + const defaultRequest = spec.buildRequests(bidRequests, bidderResquestDefault); + expect(JSON.parse(defaultRequest.data).userAgentClientHints).to.not.exist; + }); + it('should use good mediaTypes video sizes', function() { const mediaTypesVideoSizes = { 'mediaTypes': { @@ -555,34 +623,79 @@ describe('teadsBidAdapter', () => { }) describe('First-party cookie Teads ID', function () { - it('should not add firstPartyCookieTeadsId param to payload if cookies are not enabled', function () { + it('should not add firstPartyCookieTeadsId param to payload if cookies are not enabled' + + ' and teads user id not available', function () { cookiesAreEnabledStub.returns(false); - const request = spec.buildRequests([baseBidRequest], bidderResquestDefault); + const bidRequest = { + ...baseBidRequest, + userId: { + pubcid: 'publisherFirstPartyViewerId-id' + } + }; + + const request = spec.buildRequests([bidRequest], bidderResquestDefault); const payload = JSON.parse(request.data); expect(payload).not.to.have.property('firstPartyCookieTeadsId'); }); - it('should not add firstPartyCookieTeadsId param to payload if first-party cookie is not available', function () { + it('should not add firstPartyCookieTeadsId param to payload if cookies are enabled ' + + 'but first-party cookie and teads user id are not available', function () { cookiesAreEnabledStub.returns(true); getCookieStub.withArgs('_tfpvi').returns(undefined); - const request = spec.buildRequests([baseBidRequest], bidderResquestDefault); + const bidRequest = { + ...baseBidRequest, + userId: { + pubcid: 'publisherFirstPartyViewerId-id' + } + }; + + const request = spec.buildRequests([bidRequest], bidderResquestDefault); const payload = JSON.parse(request.data); expect(payload).not.to.have.property('firstPartyCookieTeadsId'); }); - it('should add firstPartyCookieTeadsId param to payload if first-party cookie is available', function () { + it('should add firstPartyCookieTeadsId from cookie if it\'s available ' + + 'and teads user id is not', function () { cookiesAreEnabledStub.returns(true); getCookieStub.withArgs('_tfpvi').returns('my-teads-id'); - const request = spec.buildRequests([baseBidRequest], bidderResquestDefault); + const bidRequest = { + ...baseBidRequest, + userId: { + pubcid: 'publisherFirstPartyViewerId-id' + } + }; + + const request = spec.buildRequests([bidRequest], bidderResquestDefault); + const payload = JSON.parse(request.data); expect(payload.firstPartyCookieTeadsId).to.equal('my-teads-id'); }); + + it('should add firstPartyCookieTeadsId from user id module if it\'s available ' + + 'even if cookie is available too', function () { + cookiesAreEnabledStub.returns(true); + getCookieStub.withArgs('_tfpvi').returns('my-teads-id'); + + const bidRequest = { + ...baseBidRequest, + userId: { + pubcid: 'publisherFirstPartyViewerId-id', + teadsId: 'teadsId-fake-id' + } + }; + + const request = spec.buildRequests([bidRequest], bidderResquestDefault); + + const payload = JSON.parse(request.data); + + expect(payload.firstPartyCookieTeadsId).to.equal('teadsId-fake-id'); + }); }); }); From 9288657e6e48e518682332a0b386caa57a467b77 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 20 Oct 2022 22:36:39 +0000 Subject: [PATCH 044/367] Prebid 7.21.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2ae7f9f3931..feb8cbc85b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.21.0-pre", + "version": "7.21.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index ed80a9c94a7..fc38cd99ea5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.21.0-pre", + "version": "7.21.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From c0260f2cf45f4eeb95dd72872b07d171b3ba99ba Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 20 Oct 2022 22:36:40 +0000 Subject: [PATCH 045/367] Increment version to 7.22.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index feb8cbc85b7..82675d5cc00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.21.0", + "version": "7.22.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index fc38cd99ea5..94f6b75b272 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.21.0", + "version": "7.22.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From df2418d740d6a70aedb3ba25ba1a5595703a33af Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 20 Oct 2022 19:03:01 -0700 Subject: [PATCH 046/367] Prebid core: do not enforce valid size in bid responses (#9138) --- src/adapters/bidderFactory.js | 20 +++++++++++--------- test/spec/unit/core/bidderFactory_spec.js | 4 ---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index d0b716d656d..7e66b849783 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -545,22 +545,24 @@ export function getIabSubCategory(bidderCode, category) { // check that the bid has a width and height set function validBidSize(adUnitCode, bid, {index = auctionManager.index} = {}) { - const bidRequest = index.getBidRequest(bid); - const mediaTypes = index.getMediaTypes(bid); - - const sizes = (bidRequest && bidRequest.sizes) || (mediaTypes && mediaTypes.banner && mediaTypes.banner.sizes); - const parsedSizes = parseSizesInput(sizes).map(sz => sz.split('x').map(n => parseInt(n, 10))); - if ((bid.width || parseInt(bid.width, 10) === 0) && (bid.height || parseInt(bid.height, 10) === 0)) { bid.width = parseInt(bid.width, 10); bid.height = parseInt(bid.height, 10); - return parsedSizes.length === 0 || parsedSizes.some(([w, h]) => bid.width === w && bid.height === h); + return true; } + const bidRequest = index.getBidRequest(bid); + const mediaTypes = index.getMediaTypes(bid); + + const sizes = (bidRequest && bidRequest.sizes) || (mediaTypes && mediaTypes.banner && mediaTypes.banner.sizes); + const parsedSizes = parseSizesInput(sizes); + // if a banner impression has one valid size, we assign that size to any bid // response that does not explicitly set width or height if (parsedSizes.length === 1) { - ([bid.width, bid.height] = parsedSizes[0]); + const [ width, height ] = parsedSizes[0].split('x'); + bid.width = parseInt(width, 10); + bid.height = parseInt(height, 10); return true; } @@ -602,7 +604,7 @@ export function isValid(adUnitCode, bid, {index = auctionManager.index} = {}) { return false; } if (bid.mediaType === 'banner' && !validBidSize(adUnitCode, bid, {index})) { - logError(errorMessage(`Banner bids require a width and height that match one of the requested sizes`)); + logError(errorMessage(`Banner bids require a width and height`)); return false; } diff --git a/test/spec/unit/core/bidderFactory_spec.js b/test/spec/unit/core/bidderFactory_spec.js index fa6cf7e6bb5..1eecfac47a7 100644 --- a/test/spec/unit/core/bidderFactory_spec.js +++ b/test/spec/unit/core/bidderFactory_spec.js @@ -1434,9 +1434,5 @@ describe('bid response isValid', () => { it('should succeed when response has a size that was in request', () => { expect(checkValid(mkResponse(3, 4))).to.be.true; }); - - it('should fail when response has a size that was not in request', () => { - expect(checkValid(mkResponse(10, 11))).to.be.false; - }); }) }); From f4ca86ddb49f1a54a2ef8133bd6d7db902f3e72c Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 21 Oct 2022 02:21:33 +0000 Subject: [PATCH 047/367] Prebid 7.22.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 82675d5cc00..b6863634a1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.22.0-pre", + "version": "7.22.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 94f6b75b272..48dd88a0d92 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.22.0-pre", + "version": "7.22.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 6183d235a137c7b8cd9a1fcca2de7c06ea5b24b6 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 21 Oct 2022 02:21:33 +0000 Subject: [PATCH 048/367] Increment version to 7.23.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b6863634a1f..ffc179f2914 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.22.0", + "version": "7.23.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 48dd88a0d92..a463546efa1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.22.0", + "version": "7.23.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 87e5b89987704dd47e4f15d87e0814ef9064af69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9onard=20Labat?= Date: Fri, 21 Oct 2022 17:06:53 +0200 Subject: [PATCH 049/367] Criteo Bid Adapter: add support of static floors (#9140) We want publishers that are not interested in using Prebid floor module to be able to send us floor/floorCur through bid params. --- modules/criteoBidAdapter.js | 28 ++++++++++++++++++---- test/spec/modules/criteoBidAdapter_spec.js | 28 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index f3988a2fa4e..622c42c9cb7 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -644,26 +644,46 @@ for (var i = 0; i < 10; ++i) { `; } +function pickAvailableGetFloorFunc(bidRequest) { + if (bidRequest.getFloor) { + return bidRequest.getFloor; + } + if (bidRequest.params.bidFloor && bidRequest.params.bidFloorCur) { + try { + const floor = parseFloat(bidRequest.params.bidFloor); + return () => { + return { + currency: bidRequest.params.bidFloorCur, + floor: floor + }; + }; + } catch { } + } + return undefined; +} + function enrichSlotWithFloors(slot, bidRequest) { try { const slotFloors = {}; - if (bidRequest.getFloor) { + const getFloor = pickAvailableGetFloorFunc(bidRequest); + + if (getFloor) { if (bidRequest.mediaTypes?.banner) { slotFloors.banner = {}; const bannerSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes')) - bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = bidRequest.getFloor({ size: bannerSize, mediaType: BANNER })); + bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = getFloor({ size: bannerSize, mediaType: BANNER })); } if (bidRequest.mediaTypes?.video) { slotFloors.video = {}; const videoSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize')) - videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = bidRequest.getFloor({ size: videoSize, mediaType: VIDEO })); + videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = getFloor({ size: videoSize, mediaType: VIDEO })); } if (bidRequest.mediaTypes?.native) { slotFloors.native = {}; - slotFloors.native['*'] = bidRequest.getFloor({ size: '*', mediaType: NATIVE }); + slotFloors.native['*'] = getFloor({ size: '*', mediaType: NATIVE }); } if (Object.keys(slotFloors).length > 0) { diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index 7af5f5d77a2..c54453bd7fc 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -1279,6 +1279,34 @@ describe('The Criteo bidding adapter', function () { }); }); + it('should properly build a request with static floors', function () { + const bidRequests = [ + { + bidder: 'criteo', + adUnitCode: 'bid-123', + transactionId: 'transaction-123', + mediaTypes: { + banner: { + sizes: [[300, 250], [728, 90]] + } + }, + params: { + networkId: 456, + bidFloor: 1, + bidFloorCur: 'EUR' + }, + }, + ]; + const bidderRequest = {}; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.slots[0].ext.floors).to.deep.equal({ + 'banner': { + '300x250': { 'currency': 'EUR', 'floor': 1 }, + '728x90': { 'currency': 'EUR', 'floor': 1 } + } + }); + }); + it('should properly build a video request with several player sizes with floors', function () { const bidRequests = [ { From 6c63c6f00267f396176e5b96629b6fc570e40805 Mon Sep 17 00:00:00 2001 From: chtdsp <109642171+chtdsp@users.noreply.github.com> Date: Sat, 22 Oct 2022 01:15:32 +0800 Subject: [PATCH 050/367] CHTNW Adapter: initial release (#8987) * add chtnw bid adapter * fix chtnw bid adapter issues * add meta advertiserDomain support --- modules/chtnwBidAdapter.js | 110 ++++++++++++++++++++++ modules/chtnwBidAdapter.md | 31 ++++++ test/spec/modules/chtnwBidAdapter_spec.js | 105 +++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 modules/chtnwBidAdapter.js create mode 100644 modules/chtnwBidAdapter.md create mode 100644 test/spec/modules/chtnwBidAdapter_spec.js diff --git a/modules/chtnwBidAdapter.js b/modules/chtnwBidAdapter.js new file mode 100644 index 00000000000..5f77cec018a --- /dev/null +++ b/modules/chtnwBidAdapter.js @@ -0,0 +1,110 @@ +import { + generateUUID, + getDNT, + _each, +} from '../src/utils.js'; +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { ajax } from '../src/ajax.js'; +import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js'; +const ENDPOINT_URL = 'https://prebid.cht.hinet.net/api/v1'; +const BIDDER_CODE = 'chtnw'; +const COOKIE_NAME = '__htid'; +const storage = getStorageManager({bidderCode: BIDDER_CODE}); + +const { getConfig } = config; + +function _isMobile() { + return (/(ios|ipod|ipad|iphone|android)/i).test(navigator.userAgent); +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + isBidRequestValid: function(bid = {}) { + return !!(bid && bid.params); + }, + buildRequests: function(validBidRequests = [], bidderRequest = {}) { + validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); + const chtnwId = (storage.getCookie(COOKIE_NAME) != undefined) ? storage.getCookie(COOKIE_NAME) : generateUUID(); + if (storage.cookiesAreEnabled()) { + storage.setCookie(COOKIE_NAME, chtnwId); + } + const device = getConfig('device') || {}; + device.w = device.w || window.innerWidth; + device.h = device.h || window.innerHeight; + device.ua = device.ua || navigator.userAgent; + device.dnt = getDNT() ? 1 : 0; + device.language = (navigator && navigator.language) ? navigator.language.split('-')[0] : ''; + const bidParams = []; + _each(validBidRequests, function(bid) { + bidParams.push({ + bidId: bid.bidId, + placement: bid.params.placementId, + sizes: bid.sizes, + adSlot: bid.adUnitCode + }); + }); + return { + method: 'POST', + url: ENDPOINT_URL + '/request/prebid.json', + data: { + bids: bidParams, + uuid: chtnwId, + device: device, + version: { + prebid: '$prebid.version$', + adapter: '1.0.0', + }, + site: { + numIframes: bidderRequest.refererInfo?.numIframes || 0, + isAmp: bidderRequest.refererInfo?.isAmp || false, + pageUrl: bidderRequest.refererInfo?.page || '', + ref: bidderRequest.refererInfo?.ref || '', + }, + }, + bids: validBidRequests + }; + }, + interpretResponse: function(serverResponse) { + const bidResponses = [] + _each(serverResponse.body, function(response, i) { + bidResponses.push({ + ...response + }); + }); + return bidResponses; + }, + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { + const syncs = []; + if (syncOptions.pixelEnabled) { + const chtnwId = generateUUID() + const uuid = chtnwId + const type = (_isMobile()) ? 'dot' : 'pixel'; + syncs.push({ + type: 'image', + url: `https://t.ssp.hinet.net/${type}?bd=${uuid}&t=chtnw` + }) + } + return syncs + }, + onTimeout: function(timeoutData) { + if (timeoutData === null) { + return; + } + ajax(ENDPOINT_URL + '/trace/timeout/bid', null, JSON.stringify(timeoutData), { + method: 'POST', + withCredentials: false + }); + }, + onBidWon: function(bid) { + if (bid.nurl) { + ajax(bid.nurl, null); + } + }, + onSetTargeting: function(bid) { + }, +} +registerBidder(spec); diff --git a/modules/chtnwBidAdapter.md b/modules/chtnwBidAdapter.md new file mode 100644 index 00000000000..08e634d577d --- /dev/null +++ b/modules/chtnwBidAdapter.md @@ -0,0 +1,31 @@ +# Overview + +``` +Module Name: CHT Bidder Adapter +Module Type: Bidder Adapter +Maintainer: chtdsp@cht.com.tw +``` + +# Description + +Module that connects to CHT's demand sources + +# Test Parameters +``` +var adUnits = [ + { + code: 'adunit-code', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [{ + bidder: 'chtnw', + params: { + placementId: '38EL412LO82XR9O6' + } + }] + } +]; +``` diff --git a/test/spec/modules/chtnwBidAdapter_spec.js b/test/spec/modules/chtnwBidAdapter_spec.js new file mode 100644 index 00000000000..3875de6c4fa --- /dev/null +++ b/test/spec/modules/chtnwBidAdapter_spec.js @@ -0,0 +1,105 @@ +import { expect } from 'chai'; +import { spec } from '../../../modules/chtnwBidAdapter.js'; +import * as utils from '../../../src/utils.js'; + +describe('ChtnwAdapter', function () { + describe('isBidRequestValid', function () { + const bid = { + code: 'adunit-code', + bidder: 'chtnw', + params: { + placementId: '38EL412LO82XR9O6' + }, + sizes: [ + [300, 250] + ], + }; + + it('should return true when required params found', function () { + const bidRequest = utils.deepClone(bid); + expect(spec.isBidRequestValid(bidRequest)).to.equal(true); + }); + + it('should return false when required params are missing', function () { + const bidRequest = utils.deepClone(bid); + delete bidRequest.params; + expect(spec.isBidRequestValid(bidRequest)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + let bidRequests = [{ + code: 'adunit-code', + bidder: 'chtnw', + params: { + placementId: '38EL412LO82XR9O6' + }, + sizes: [ + [300, 250] + ], + }]; + + const request = spec.buildRequests(bidRequests); + + it('Returns POST method', function () { + expect(request.method).to.equal('POST'); + }); + + it('Returns general data valid', function () { + let data = request.data; + expect(data).to.be.an('object'); + expect(data).to.have.property('bids'); + expect(data).to.have.property('uuid'); + expect(data).to.have.property('device'); + expect(data).to.have.property('site'); + }); + }); + + describe('interpretResponse', function () { + let responseBody = [{ + 'requestId': 'test', + 'cpm': 0.5, + 'currency': 'USD', + 'width': 300, + 'height': 250, + 'netRevenue': true, + 'ttl': 60, + 'creativeId': 'AD', + 'ad': '

AD

', + 'mediaType': 'banner', + 'meta': { + 'advertiserDomains': [ + 'www.example.com' + ] + } + }]; + + it('handles empty bid response', function () { + let response = { + body: responseBody + }; + let result = spec.interpretResponse(response); + expect(result.length).to.not.equal(0); + expect(result[0].meta.advertiserDomains).to.be.an('array'); + }); + + 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 register type is image', function () { + const syncOptions = { + 'pixelEnabled': 'true' + } + let userSync = spec.getUserSyncs(syncOptions); + expect(userSync[0].type).to.equal('image'); + expect(userSync[0].url).to.have.string('ssp'); + }); + }); +}); From 0c69238d05017b372e4d527d02ad71bbeb0aca71 Mon Sep 17 00:00:00 2001 From: Karim Mourra Date: Fri, 21 Oct 2022 14:46:45 -0400 Subject: [PATCH 051/367] Video Module: Initial Release (#8858) * registers as module * adds vendor consts * registers jwplayer submodule * renames render ad * checks config autostart * moves private functions to a util obj * introduces ad optimization * tests state.js * introduces submodule tests * populates utils tests * tests callback storage * tests ad and time states * introduces provider tests: * tests init * tests get ortb * tests event listeners * supports removing all event handlers when explicit * splits clear all event listeners from early return * removes hook * shares directory * prevents registering a same provider twice * adds pb video * adds video module to submodules list * adds integration example * implements ad unit enrichment * moves submodule to parent dir * removes comment * implements event listener * adds unit tests * tests updating video config * tests events surfacing * nests the event trigger tests * restores factory * adds adServer * shares base parent module logic * register gam submodule * tests submodule builder * instantiates ad server * tests parent module * updates core video tests * adds ad server tests * obtains vast ad to render * passes options * tests ad tag obtention * tests settings tags without ad server * adds vast xml builder * tests node makers * implments vast xml build fn * renames wrapper builder * adds vast xml editor * modifies vast xml * moves logic to helper * appends doc element * copies node when required multiple times * improves copy check * adds tests for error node * adds tests cases for different config * pulls vast wrapper builders from xml editor * adds tracking tests * tests arguments * removes obsolete path * polls for duration when absent * sets up video module * prevents ad load if bidding is used * triggers event before loading ad * adds inline docs to shared modules * adds inline docs * documents providers * adds inline docs for ortb * adds missing ortb params * obtains language code * makes placement more precise * adds notes * updates todo * early exit if not video media type * loads ad server config * filters for highest bids before rendering * emits event even on loss * registers video auction events * updates events * includes ad unit code in loss * uses config fallback * tracks bids sent for rendering * adds video impression verification * shares code * triggers bid video events * matches ad event to bid * adds inline documentation * allows URL import * updates vast xml editor tests * tests ad event processsing * includes ad wrapper ids * updates ad tag injection tests * tests impression tracking * updates for new find * removes unused var * uses find polyfill * updates event import * exposes addEvents * checks for bid identifiers bfore accessing properties * checks for bid identifiers bfore accessing properties * exposes video bid events * converts ortb params to insternal fields * reads from video * removes typo * sets ortb video to media type video * sets ortb2 obj * gets impression url from fn * tmg uses mediatype video * configures provider to properly render ads * sets up player in demo * triggers load abort * uses appnexys * uses getGlobal * protects against missing params * breaks out shared and adserver from videoModule * updates import * resolves lgtm errors * uses submodule pattern * uses uuid generator util * removes adServer module * moves shared to video folder * prefix events with video_ * adds auction end listener when no bids back handler * fixes tests * refactors render * exposes rendering * uses mergeDeep * shares constants * populates ortb content.data * register events as prefixed * adds test bidders * moves videoModule to library * Added draft for videojs integration example * Moved jwplayer integration example, added draft for videojs example * Created integration example for a mocked videojs adapter * Fixed call order for integration examples, moved imports up * Finished init for videojs provider * Setup videojs init unit tests * Formatting to pass linter * Removed comments/redundant tests, clarified some sections of code * Added semicolon * Videojs ortb params, added ortb constants * Fixed integration examples, ortb adjustments * Cleaned up code added comments * Renamed test file * Removed videojs mock in favor of videojs * Changed video source, finished tests for ortb * Cleaned up spacing added some comments * Added ad position to ortb * Cleaned up playback methods code * Omitted skip variable per ortb spec * Added unit tests for ima integration * Added util function, and corresponding tests * Added code for placement * Linter pass through * Added videojs-ima to integration example * Removed duplicate tests * Removed non bidding module tests * Added clarifying comments * Updated name mapping for videojs events * Added callback factory, and presetup listeners * Filled in initialization events * Importing event constants * Fixing setup failed event handler * Fixed init behavior to work with setupCompleteCallback * Added pre setup callback tests * Setup presetupListeners/moved away from callbackStorage * Added missing case for setup failure * Basic event handling * adds ortb constants * removes trailing file * uses hook.js * marks winning bid as used * gets adWrapper regardless of property name * rename vars * fixes init and loadAdTag * renames videojs var * supports media events * addresses size events * registers ad events * implements get ad info * generates ad pauload * includes wrapper ids * supports ad config * populates ad config * adds event listener at every manager change * handles setupfailure * renames video js example * updates time * supports loadstart * supports multiple setup callbacks * removes global ima for test * removes obsolete IMA checks * requests ad unit * uses vendor config to setup * listens for playlist events * restors src tag * resolves build fail * splits library from module * allows obtaining ortb obj * uses safe getConfig * adds metadata demo * improves metadata util * triggers playlist event at first load * adds bid request scheduling demo * obtains bid adId * sets proper context * combines all possible adServer configs * configures ad tag * adds demos * adServerConfig getter is nullable * adds demos * triggers setup fail when ima is missing * checks for player existence * updates tests * adds tests * tests media parsers * returns empty object when no config gound * adds integrity * removes library map * prioritizes bidder params * uses camel casing for event names * support multiple setup successful callbacks * supports multiple setup fail ballbacks * moves early return to core * registers one event at a time * uses event handler builder * uses name conversion util * refactors event handling * refactors ima listeners * simplifies event logic * checks for existence * offevent singular * adds fn desc * splits ortb video from content * checks for player existence * enrichment rules * only sets main content div when enabled * sets ortb2 in the bidRequest * tests re ortb * refactor tests * resolves instability * removes auction end event listener * rebuilds dependencies * sets ortb site.content * renames auctionRequest * renames optimizeAds * adds module docs * adds event doc Co-authored-by: karimJWP Co-authored-by: AnirudhRahul --- .../videoModule/jwplayer/bidMarkedAsUsed.html | 98 + .../jwplayer/bidRequestScheduling.html | 89 + .../videoModule/jwplayer/eventListeners.html | 244 + .../jwplayer/gamAdServerMediation.html | 122 + .../videoModule/jwplayer/mediaMetadata.html | 80 + .../videoModule/jwplayer/playlist.html | 122 + .../videoModule/videojs/bidMarkedAsUsed.html | 126 + .../videojs/bidRequestScheduling.html | 132 + .../videoModule/videojs/eventListeners.html | 238 + .../videojs/gamAdServerMediation.html | 138 + .../videoModule/videojs/mediaMetadata.html | 103 + .../videoModule/videojs/playlist.html | 151 + libraries/video/constants/enums.js | 5 + libraries/video/constants/events.js | 97 + libraries/video/constants/ortb.js | 169 + libraries/video/constants/vendorCodes.js | 6 + libraries/video/shared/eventHandler.js | 18 + libraries/video/shared/parentModule.js | 82 + libraries/video/shared/state.js | 47 + libraries/video/shared/vastXmlBuilder.js | 77 + libraries/video/shared/vastXmlEditor.js | 115 + modules/.submodules.json | 6 +- modules/appnexusBidAdapter.js | 39 +- modules/gridNMBidAdapter.js | 24 +- modules/jwplayerVideoProvider.js | 929 ++ modules/jwplayerVideoProvider.md | 25 + modules/spotxBidAdapter.js | 31 +- modules/synacormediaBidAdapter.js | 2 +- modules/videoModule/addingSubmodule.md | 521 + modules/videoModule/coreVideo.js | 234 + modules/videoModule/gamAdServerSubmodule.js | 27 + modules/videoModule/index.js | 244 + .../videoModule/videoImpressionVerifier.js | 206 + modules/videojsVideoProvider.js | 854 ++ modules/videojsVideoProvider.md | 17 + package-lock.json | 11927 +++++++++++++++- package.json | 4 + src/events.js | 6 +- src/prebid.js | 169 +- .../modules/videoModule/coreVideo_spec.js | 98 + test/spec/modules/videoModule/pbVideo_spec.js | 362 + .../videoModule/shared/parentModule_spec.js | 73 + .../modules/videoModule/shared/state_spec.js | 26 + .../videoModule/shared/vastXmlBuilder_spec.js | 103 + .../videoModule/shared/vastXmlEditor_spec.js | 209 + .../submodules/jwplayerVideoProvider_spec.js | 846 ++ .../submodules/videojsVideoProvider_spec.js | 391 + .../videoImpressionVerifier_spec.js | 112 + test/spec/unit/pbjs_api_spec.js | 2 +- 49 files changed, 18938 insertions(+), 808 deletions(-) create mode 100644 integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html create mode 100644 integrationExamples/videoModule/jwplayer/bidRequestScheduling.html create mode 100644 integrationExamples/videoModule/jwplayer/eventListeners.html create mode 100644 integrationExamples/videoModule/jwplayer/gamAdServerMediation.html create mode 100644 integrationExamples/videoModule/jwplayer/mediaMetadata.html create mode 100644 integrationExamples/videoModule/jwplayer/playlist.html create mode 100644 integrationExamples/videoModule/videojs/bidMarkedAsUsed.html create mode 100644 integrationExamples/videoModule/videojs/bidRequestScheduling.html create mode 100644 integrationExamples/videoModule/videojs/eventListeners.html create mode 100644 integrationExamples/videoModule/videojs/gamAdServerMediation.html create mode 100644 integrationExamples/videoModule/videojs/mediaMetadata.html create mode 100644 integrationExamples/videoModule/videojs/playlist.html create mode 100644 libraries/video/constants/enums.js create mode 100644 libraries/video/constants/events.js create mode 100644 libraries/video/constants/ortb.js create mode 100644 libraries/video/constants/vendorCodes.js create mode 100644 libraries/video/shared/eventHandler.js create mode 100644 libraries/video/shared/parentModule.js create mode 100644 libraries/video/shared/state.js create mode 100644 libraries/video/shared/vastXmlBuilder.js create mode 100644 libraries/video/shared/vastXmlEditor.js create mode 100644 modules/jwplayerVideoProvider.js create mode 100644 modules/jwplayerVideoProvider.md create mode 100644 modules/videoModule/addingSubmodule.md create mode 100644 modules/videoModule/coreVideo.js create mode 100644 modules/videoModule/gamAdServerSubmodule.js create mode 100644 modules/videoModule/index.js create mode 100644 modules/videoModule/videoImpressionVerifier.js create mode 100644 modules/videojsVideoProvider.js create mode 100644 modules/videojsVideoProvider.md create mode 100644 test/spec/modules/videoModule/coreVideo_spec.js create mode 100644 test/spec/modules/videoModule/pbVideo_spec.js create mode 100644 test/spec/modules/videoModule/shared/parentModule_spec.js create mode 100644 test/spec/modules/videoModule/shared/state_spec.js create mode 100644 test/spec/modules/videoModule/shared/vastXmlBuilder_spec.js create mode 100644 test/spec/modules/videoModule/shared/vastXmlEditor_spec.js create mode 100644 test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js create mode 100644 test/spec/modules/videoModule/submodules/videojsVideoProvider_spec.js create mode 100644 test/spec/modules/videoModule/videoImpressionVerifier_spec.js diff --git a/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html b/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html new file mode 100644 index 00000000000..542cab4202e --- /dev/null +++ b/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html @@ -0,0 +1,98 @@ + + + + + + + JW Player with Bid Marked As Used + + + + + + + +
+ + + diff --git a/integrationExamples/videoModule/jwplayer/bidRequestScheduling.html b/integrationExamples/videoModule/jwplayer/bidRequestScheduling.html new file mode 100644 index 00000000000..620f891fa50 --- /dev/null +++ b/integrationExamples/videoModule/jwplayer/bidRequestScheduling.html @@ -0,0 +1,89 @@ + + + + + + + JW Player with Bid Request Scheduling + + + + + + + +

JW Player with Bid Request Scheduling

+
Div-1: Player placeholder div
+
+ + + diff --git a/integrationExamples/videoModule/jwplayer/eventListeners.html b/integrationExamples/videoModule/jwplayer/eventListeners.html new file mode 100644 index 00000000000..b4f5aaa5443 --- /dev/null +++ b/integrationExamples/videoModule/jwplayer/eventListeners.html @@ -0,0 +1,244 @@ +- + + + + + + + + + + + +
+ + + diff --git a/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html b/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html new file mode 100644 index 00000000000..4612d03f336 --- /dev/null +++ b/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html @@ -0,0 +1,122 @@ + + + + + + + JW Player with GAM Ad Server Mediation + + + + + + + +

JW Player with GAM Ad Server Mediation

+
Player placeholder div
+
+ + + diff --git a/integrationExamples/videoModule/jwplayer/mediaMetadata.html b/integrationExamples/videoModule/jwplayer/mediaMetadata.html new file mode 100644 index 00000000000..97e35c4de0d --- /dev/null +++ b/integrationExamples/videoModule/jwplayer/mediaMetadata.html @@ -0,0 +1,80 @@ + + + + + + + JW Player with Media Metadata + + + + + + + + +

JW Player with Media Metadata

+ +
+ + + diff --git a/integrationExamples/videoModule/jwplayer/playlist.html b/integrationExamples/videoModule/jwplayer/playlist.html new file mode 100644 index 00000000000..eb9a9b12700 --- /dev/null +++ b/integrationExamples/videoModule/jwplayer/playlist.html @@ -0,0 +1,122 @@ + + + + + + + JW Player with Playlist + + + + + + + + +

JW Player with Playlist

+ +
Div-1: Player placeholder div
+
+ + + diff --git a/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html b/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html new file mode 100644 index 00000000000..3c21130e8f5 --- /dev/null +++ b/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + VideoJS with Bid Marked As Used + + + + + + + +

VideoJS with Bid Marked As Used

+
Div-1: Player placeholder div
+ + + + diff --git a/integrationExamples/videoModule/videojs/bidRequestScheduling.html b/integrationExamples/videoModule/videojs/bidRequestScheduling.html new file mode 100644 index 00000000000..48f8b8685e1 --- /dev/null +++ b/integrationExamples/videoModule/videojs/bidRequestScheduling.html @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + VideoJS with Bid Request Scheduling + + + + + + + +

VideoJS with Bid Request Scheduling

+
Div-1: Player placeholder div
+ + + + diff --git a/integrationExamples/videoModule/videojs/eventListeners.html b/integrationExamples/videoModule/videojs/eventListeners.html new file mode 100644 index 00000000000..63de878715f --- /dev/null +++ b/integrationExamples/videoModule/videojs/eventListeners.html @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + VideoJS Event Listeners + + + + + + + + +

VideoJS Event Listeners

+ +
Div-1: Player placeholder div
+ + + + + diff --git a/integrationExamples/videoModule/videojs/gamAdServerMediation.html b/integrationExamples/videoModule/videojs/gamAdServerMediation.html new file mode 100644 index 00000000000..72deba861bf --- /dev/null +++ b/integrationExamples/videoModule/videojs/gamAdServerMediation.html @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + VideoJS with GAM Ad Server Mediation + + + + + + + +

VideoJS with GAM Ad Server Mediation

+
Div-1: Player placeholder div
+ + + + diff --git a/integrationExamples/videoModule/videojs/mediaMetadata.html b/integrationExamples/videoModule/videojs/mediaMetadata.html new file mode 100644 index 00000000000..eef12b0e19d --- /dev/null +++ b/integrationExamples/videoModule/videojs/mediaMetadata.html @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + VideoJS with Media Metadata + + + + + + + + +

VideoJS with Media Metadata

+ +
Div-1: Player placeholder div
+ + + + diff --git a/integrationExamples/videoModule/videojs/playlist.html b/integrationExamples/videoModule/videojs/playlist.html new file mode 100644 index 00000000000..a9354e06c83 --- /dev/null +++ b/integrationExamples/videoModule/videojs/playlist.html @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + VideoJS with Playlist + + + + + + + + +

VideoJS with Playlist

+ +
Div-1: Player placeholder div
+ + + + + diff --git a/libraries/video/constants/enums.js b/libraries/video/constants/enums.js new file mode 100644 index 00000000000..b0755020580 --- /dev/null +++ b/libraries/video/constants/enums.js @@ -0,0 +1,5 @@ +export const PLAYBACK_MODE = { + VOD: 0, + LIVE: 1, + DVR: 2 +}; diff --git a/libraries/video/constants/events.js b/libraries/video/constants/events.js new file mode 100644 index 00000000000..5be594b1b48 --- /dev/null +++ b/libraries/video/constants/events.js @@ -0,0 +1,97 @@ +// Life Cycle +export const SETUP_COMPLETE = 'setupComplete'; +export const SETUP_FAILED = 'setupFailed'; +export const DESTROYED = 'destroyed'; + +// Ads +export const AD_REQUEST = 'adRequest'; +export const AD_BREAK_START = 'adBreakStart'; +export const AD_LOADED = 'adLoaded'; +export const AD_STARTED = 'adStarted'; +export const AD_IMPRESSION = 'adImpression'; +export const AD_PLAY = 'adPlay'; +export const AD_TIME = 'adTime'; +export const AD_PAUSE = 'adPause'; +export const AD_CLICK = 'adClick'; +export const AD_SKIPPED = 'adSkipped'; +export const AD_ERROR = 'adError'; +export const AD_COMPLETE = 'adComplete'; +export const AD_BREAK_END = 'adBreakEnd'; + +// Media +export const PLAYLIST = 'playlist'; +export const PLAYBACK_REQUEST = 'playbackRequest'; +export const AUTOSTART_BLOCKED = 'autostartBlocked'; +export const PLAY_ATTEMPT_FAILED = 'playAttemptFailed'; +export const CONTENT_LOADED = 'contentLoaded'; +export const PLAY = 'play'; +export const PAUSE = 'pause'; +export const BUFFER = 'buffer'; +export const TIME = 'time'; +export const SEEK_START = 'seekStart'; +export const SEEK_END = 'seekEnd'; +export const MUTE = 'mute'; +export const VOLUME = 'volume'; +export const RENDITION_UPDATE = 'renditionUpdate'; +export const ERROR = 'error'; +export const COMPLETE = 'complete'; +export const PLAYLIST_COMPLETE = 'playlistComplete'; + +// Layout +export const FULLSCREEN = 'fullscreen'; +export const PLAYER_RESIZE = 'playerResize'; +export const VIEWABLE = 'viewable'; +export const CAST = 'cast'; + +export const allVideoEvents = [ + SETUP_COMPLETE, SETUP_FAILED, DESTROYED, AD_REQUEST, AD_BREAK_START, AD_LOADED, AD_STARTED, + AD_IMPRESSION, AD_PLAY, AD_TIME, AD_PAUSE, AD_CLICK, AD_SKIPPED, AD_ERROR, AD_COMPLETE, AD_BREAK_END, PLAYLIST, + PLAYBACK_REQUEST, AUTOSTART_BLOCKED, PLAY_ATTEMPT_FAILED, CONTENT_LOADED, PLAY, PAUSE, BUFFER, TIME, SEEK_START, + SEEK_END, MUTE, VOLUME, RENDITION_UPDATE, ERROR, COMPLETE, PLAYLIST_COMPLETE, FULLSCREEN, PLAYER_RESIZE, VIEWABLE, + CAST +]; + +export const AUCTION_AD_LOAD_ATTEMPT = 'auctionAdLoadAttempt'; +export const AUCTION_AD_LOAD_ABORT = 'auctionAdLoadAbort'; +export const BID_IMPRESSION = 'bidImpression'; +export const BID_ERROR = 'bidError'; + +export const videoEvents = { + SETUP_COMPLETE, + SETUP_FAILED, + DESTROYED, + AD_REQUEST, + AD_BREAK_START, + AD_LOADED, + AD_STARTED, + AD_IMPRESSION, + AD_PLAY, + AD_TIME, + AD_PAUSE, + AD_CLICK, + AD_SKIPPED, + AD_ERROR, + AD_COMPLETE, + AD_BREAK_END, + PLAYLIST, + PLAYBACK_REQUEST, + AUTOSTART_BLOCKED, + PLAY_ATTEMPT_FAILED, + CONTENT_LOADED, + PLAY, + PAUSE, + BUFFER, + TIME, + SEEK_START, + SEEK_END, + MUTE, + VOLUME, + RENDITION_UPDATE, + ERROR, + COMPLETE, + PLAYLIST_COMPLETE, + FULLSCREEN, + PLAYER_RESIZE, + VIEWABLE, + CAST, +}; diff --git a/libraries/video/constants/ortb.js b/libraries/video/constants/ortb.js new file mode 100644 index 00000000000..d67c8a5f393 --- /dev/null +++ b/libraries/video/constants/ortb.js @@ -0,0 +1,169 @@ +/** + * @typedef {Object} OrtbParams + * @property {OrtbVideoParamst} video + * @property {OrtbContentParams} content + */ + +/** + * @typedef OrtbVideoParams + * @property {[string]} mimes - Content MIME types supported (e.g., “video/x-ms-wmv”, “video/mp4”). + * @property {number|undefined} minduration - Minimum video ad duration in seconds. + * @property {number|undefined} maxduration - Maximum video ad duration in seconds. + * @property {[number]} protocols - Supported video protocols. At least one supported protocol must be specified. + * @property {number} w - Width of the video player in device independent pixels (DIPS). + * @property {number} h - Height of the video player in device independent pixels (DIPS). + * @property {number|undefined} startdelay - Indicates the offset of the ad placement. + * @property {number|undefined} placement - Placement type for the impression. + * @property {number|undefined} linearity - Indicates if the impression must be linear, nonlinear, etc. If omitted, assume all are allowed. + * @property {number} skip - Indicates if the player can allow the video to be skipped, where 0 is no, 1 is yes. + * @property {number|undefined} skipmin - Only ad creatives with a duration greater than this value can be skippable; only applicable if the ad is skippable. + * @property {number|undefined} skipafter - Number of seconds a video must play before skipping is enabled; only applicable if the ad is skippable. + * @property {number|undefined} sequence - If multiple ad impressions are offered in the same bid request, the sequence number will allow for the coordinated delivery of multiple creatives. + * @property {[number]|undefined} battr - Blocked creative attributes. Use this to indicate which creatives the player does not support. + * @property {number|undefined} maxextended - Maximum extended ad duration if extension is allowed. + * @property {number|undefined} minbitrate - Minimum bit rate in Kbps supported by the player. + * @property {number|undefined} maxbitrate - Maximum bit rate in Kbps supported by the player. + * @property {number|undefined} boxingallowed - Indicates if letter-boxing of 4:3 content into a 16:9 window is allowed. 0 is no, 1 is yes. + * @property {[number]|undefined} playbackmethod - Playback methods that may be in use. + * @property {number|undefined} playbackend - The scenario that causes playback to end. + * @property {[number]|undefined} delivery - Supported delivery methods (e.g., streaming, progressive). + * @property {number|undefined} pos - Ad position on screen. + * @property {[Object]|undefined} companionad - list of companion ads. Refer to Section 3.2.6 of the oRTB v2.5 spec for the interface of the companion ad object. + * @property {[number]|undefined} api - List of supported API frameworks for this impression. + * @property {[number]|undefined} companiontype - Supported VAST companion ad types. Refer to List 5.14 of the oRTB v2.5 spec for the interface. + * @property {Object|undefined} ext - Placeholder for exchange-specific extensions to OpenRTB. + */ + +/** + * @typedef OrtbContentParams + * @property {string} id - ID uniquely identifying the content. + * @property {string} url - URL of the content, for buy-side contextualization or review. + * @property {number|undefined} episode - Episode number. + * @property {string|undefined} title - Content title. + * @property {string|undefined} series - Content series i.e. “The Office” (television), “Star Wars” (movie). + * @property {string|undefined} season - Content season (e.g., “Season 3”). + * @property {string|undefined} artist - Artist credited with the content. + * @property {string|undefined} genre - Genre that best describes the content (e.g., rock, pop, etc). + * @property {string|undefined} album - Album to which the content belongs. Typically for audio. + * @property {string|undefined} isrc - International Standard Recording Code conforming to ISO3901. + * @property {Object|undefined} producer - Details about the content Producer. For Producer interface visit Section 3.2.17 of the oRTB v2.5 spec. + * @property {[string]|undefined} cat - List of IAB content categories that describe the content. Refer to List 5.1. of the oRTB v2.5 spec for the complete list. + * @property {number|undefined} prodq - Production quality. Refer to List 5.13 of the oRTB v2.5 spec. + * @property {number|undefined} context - Type of content (game, video, text, etc.). Refer to List 5.18 of the oRTB v2.5 spec. + * @property {string|undefined} contentrating - Content rating (e.g., MPAA). + * @property {string|undefined} userrating - User rating of the content (e.g., number of stars, likes, etc.). + * @property {number|undefined} qagmediarating - Media rating per IQG guidelines. Refer to List 5.19 of the oRTB v2.5 spec. + * @property {string|undefined} keywords - Comma separated list of keywords describing the content. + * @property {number|undefined} livestream - Whether the stream is live or not. 0 means not live (VOD), 1 means content is live streaming. + * @property {number|undefined} sourcerelationship - 0 means indirect, 1 means direct. + * @property {number} len - Duration of content in seconds. + * @property {string|undefined} language - Content language using ISO-639-1-alpha-2. + * @property {number|undefined} embeddable - Indicator of whether or not the content is embeddable (e.g., an embeddable video player). 0 means no, 1 means yes. + * @property {[Object]|undefined} data - Additional content data. Each Data object represents a different data source. See Section 3.2.21 of the oRTB v2.5 spec. + * @property {Object|undefined} ext - Placeholder for exchange-specific extensions to OpenRTB. + */ + +const VIDEO_PREFIX = 'video/'; +const APPLICATION_PREFIX = 'application/'; + +/** + * ORTB 2.5 section 3.2.7 - Video.mimes + * @enum OrtbVideoParams.mimes + */ +export const VIDEO_MIME_TYPE = { + MP4: VIDEO_PREFIX + 'mp4', + MPEG: VIDEO_PREFIX + 'mpeg', + OGG: VIDEO_PREFIX + 'ogg', + WEBM: VIDEO_PREFIX + 'webm', + AAC: VIDEO_PREFIX + 'aac', + HLS: APPLICATION_PREFIX + 'vnd.apple.mpegurl' +}; + +export const JS_APP_MIME_TYPE = APPLICATION_PREFIX + 'javascript'; +export const VPAID_MIME_TYPE = JS_APP_MIME_TYPE; + +/** + * ORTB 2.5 section 5.9 - Video Placement Types + * @enum OrtbVideoParams.placement + */ +export const PLACEMENT = { + INSTREAM: 1, + BANNER: 2, + ARTICLE: 3, + FEED: 4, + INTERSTITIAL: 5, + SLIDER: 5, + FLOATING: 5, + INTERSTITIAL_SLIDER_FLOATING: 5 +}; + +/** + * ORTB 2.5 section 5.4 - Ad Position + * @enum OrtbVideoParams.pos + */ +export const AD_POSITION = { + UNKNOWN: 0, + ABOVE_THE_FOLD: 1, + BELOW_THE_FOLD: 3, + HEADER: 4, + FOOTER: 5, + SIDEBAR: 6, + FULL_SCREEN: 7 +} + +/** + * ORTB 2.5 section 5.11 - Playback Cessation Modes + * @enum OrtbVideoParams.playbackend + */ +export const PLAYBACK_END = { + VIDEO_COMPLETION: 1, + VIEWPORT_LEAVE: 2, + FLOATING: 3 +} + +/** + * ORTB 2.5 section 5.10 - Playback Methods + * @enum OrtbVideoParams.playbackmethod + */ +export const PLAYBACK_METHODS = { + AUTOPLAY: 1, + AUTOPLAY_MUTED: 2, + CLICK_TO_PLAY: 3, + CLICK_TO_PLAY_MUTED: 4, + VIEWABLE: 5, + VIEWABLE_MUTED: 6 +}; + +/** + * ORTB 2.5 section 5.8 - Protocols + * @enum OrtbVideoParams.protocols + */ +export const PROTOCOLS = { + // VAST_1_0: 1, + VAST_2_0: 2, + VAST_3_0: 3, + // VAST_1_O_WRAPPER: 4, + VAST_2_0_WRAPPER: 5, + VAST_3_0_WRAPPER: 6, + VAST_4_0: 7, + VAST_4_0_WRAPPER: 8 +}; + +/** + * ORTB 2.5 section 5.6 - API Frameworks + * @enum OrtbVideoParams.api + */ +export const API_FRAMEWORKS = { + VPAID_1_0: 1, + VPAID_2_0: 2, + OMID_1_0: 7 +}; + +/** + * ORTB 2.5 section 5.18 - Content Context + * @enum OrtbContentParams.context + */ +export const CONTEXT = { + VIDEO: 1, + AUDIO: 3 +}; diff --git a/libraries/video/constants/vendorCodes.js b/libraries/video/constants/vendorCodes.js new file mode 100644 index 00000000000..370c151b997 --- /dev/null +++ b/libraries/video/constants/vendorCodes.js @@ -0,0 +1,6 @@ +// Video Vendors +export const JWPLAYER_VENDOR = 1; +export const VIDEO_JS_VENDOR = 2; + +// Ad Server Vendors +export const GAM_VENDOR = 'gam'; diff --git a/libraries/video/shared/eventHandler.js b/libraries/video/shared/eventHandler.js new file mode 100644 index 00000000000..ee0d6b2cbfb --- /dev/null +++ b/libraries/video/shared/eventHandler.js @@ -0,0 +1,18 @@ +/** + * Builds a standard event handler + * @param {String} type Event name + * @param {(function(String, Object): Object)} callback Callback defined by publisher to be executed when the event occurs + * @param {Object} payload Base payload defined when the event is registered + * @param {(function(*): Object)|null|undefined} getExtraPayload Parses the player's event payload to return a normalized payload + * @returns {(function(*): void)|*} event handler + */ +export function getEventHandler(type, callback, payload, getExtraPayload) { + return event => { + if (getExtraPayload) { + const extraPayload = getExtraPayload(event); + Object.assign(payload, extraPayload); + } + + callback(type, payload); + }; +} diff --git a/libraries/video/shared/parentModule.js b/libraries/video/shared/parentModule.js new file mode 100644 index 00000000000..e96113fd894 --- /dev/null +++ b/libraries/video/shared/parentModule.js @@ -0,0 +1,82 @@ +/** + * @typedef {Object} ParentModule + * @summary abstraction for any module to store and reference its submodules + * @param {SubmoduleBuilder} submoduleBuilder_ + * @returns {ParentModule} + * @constructor + */ +export function ParentModule(submoduleBuilder_) { + const submoduleBuilder = submoduleBuilder_; + const submodules = {}; + + /** + * @function ParentModule#registerSubmodule + * @summary Stores a submodule + * @param {String} id - unique identifier of the submodule instance + * @param {String} vendorCode - identifier to the submodule type that must be built + * @param {Object} config - additional information necessary to instantiate the submodule + */ + function registerSubmodule(id, vendorCode, config) { + if (submodules[id]) { + return; + } + + let submodule; + try { + submodule = submoduleBuilder.build(vendorCode, config); + } catch (e) { + throw e; + } + submodules[id] = submodule; + } + + /** + * @function ParentModule#getSubmodule + * @summary Stores a submodule + * @param {String} id - unique identifier of the submodule instance + * @returns {Object} - a submodule instance + */ + function getSubmodule(id) { + return submodules[id]; + } + + return { + registerSubmodule, + getSubmodule + } +} + +/** + * @typedef {Object} SubmoduleBuilder + * @summary Instantiates submodules + * @param {vendorSubmoduleDirectory} submoduleDirectory_ + * @param {Object|null|undefined} sharedUtils_ + * @returns {SubmoduleBuilder} + * @constructor + */ +export function SubmoduleBuilder(submoduleDirectory_, sharedUtils_) { + const submoduleDirectory = submoduleDirectory_; + const sharedUtils = sharedUtils_; + + /** + * @function SubmoduleBuilder#build + * @param vendorCode - identifier to the submodule type that must be instantiated + * @param config - additional information necessary to instantiate the submodule + * @throws + * @returns {{init}|*} - a submodule instance + */ + function build(vendorCode, config) { + const submoduleFactory = submoduleDirectory[vendorCode]; + if (!submoduleFactory) { + throw new Error('Unrecognized submodule vendor code: ' + vendorCode); + } + + const submodule = submoduleFactory(config, sharedUtils); + submodule && submodule.init && submodule.init(); + return submodule; + } + + return { + build + }; +} diff --git a/libraries/video/shared/state.js b/libraries/video/shared/state.js new file mode 100644 index 00000000000..b84cff8f997 --- /dev/null +++ b/libraries/video/shared/state.js @@ -0,0 +1,47 @@ +/** + * @typedef {Object} State + * @summary simple state object. Can be subclassed + * @function updateState + * @function getState + * @function clearState + */ + +/** + * @summary factory to create a simple state object + * @returns {State} + */ +export default function stateFactory() { + let state = {}; + + /** + * @function State#updateState + * @summary updates the state + * @param {Object} stateUpdate + */ + function updateState(stateUpdate) { + Object.assign(state, stateUpdate); + } + + /** + * @function State#getState + * @summary provides the current state + * @returns {Object} the current state + */ + function getState() { + return state; + } + + /** + * @function State#clearState + * @summary erases the current state + */ + function clearState() { + state = {}; + } + + return { + updateState, + getState, + clearState + }; +} diff --git a/libraries/video/shared/vastXmlBuilder.js b/libraries/video/shared/vastXmlBuilder.js new file mode 100644 index 00000000000..35547acc479 --- /dev/null +++ b/libraries/video/shared/vastXmlBuilder.js @@ -0,0 +1,77 @@ +import { getGlobal } from '../../../src/prebidGlobal.js'; + +export function buildVastWrapper(adId, adTagUrl, impressionUrl, impressionId, errorUrl) { + let wrapperBody = getAdSystemNode('Prebid org', getGlobal().version); + + if (adTagUrl) { + wrapperBody += getAdTagUriNode(adTagUrl); + } + + if (impressionUrl) { + wrapperBody += getImpressionNode(impressionUrl, impressionId); + } + + if (errorUrl) { + wrapperBody += getErrorNode(errorUrl); + } + + return getVastNode(getAdNode(getWrapperNode(wrapperBody), adId), '4.2'); +} + +export function getVastNode(body, vastVersion) { + return getNode('VAST', body, { version: vastVersion }); +} + +export function getAdNode(body, adId) { + return getNode('Ad', body, { id: adId }); +} + +export function getWrapperNode(body) { + return getNode('Wrapper', body); +} + +export function getAdSystemNode(system, version) { + return getNode('AdSystem', system, { version }); +} + +export function getAdTagUriNode(adTagUrl) { + return getUrlNode('VASTAdTagURI', adTagUrl); +} + +export function getImpressionNode(pingUrl, id) { + return getUrlNode('Impression', pingUrl, { id }); +} + +export function getErrorNode(pingUrl) { + return getUrlNode('Error', pingUrl); +} + +// Helpers + +function getUrlNode(labelName, url, attributes) { + const body = ``; + return getNode(labelName, body, attributes); +} + +function getNode(labelName, body, attributes) { + const openingLabel = getOpeningLabel(labelName, attributes); + return `<${openingLabel}>${body}`; +} + +/* +attributes is a KVP Object. + */ +function getOpeningLabel(name, attributes) { + if (!attributes) { + return name; + } + + return Object.keys(attributes).reduce((label, key) => { + const value = attributes[key]; + if (!value) { + return label; + } + + return label + ` ${key}="${value}"`; + }, name); +} diff --git a/libraries/video/shared/vastXmlEditor.js b/libraries/video/shared/vastXmlEditor.js new file mode 100644 index 00000000000..b586e5b4c29 --- /dev/null +++ b/libraries/video/shared/vastXmlEditor.js @@ -0,0 +1,115 @@ +import { getErrorNode, getImpressionNode, buildVastWrapper } from './vastXmlBuilder.js'; + +export const XML_MIME_TYPE = 'application/xml'; + +export function VastXmlEditor(xmlUtil_) { + const xmlUtil = xmlUtil_; + + function getVastXmlWithTracking(vastXml, adId, impressionUrl, impressionId, errorUrl) { + const impressionDoc = getImpressionDoc(impressionUrl, impressionId); + const errorDoc = getErrorDoc(errorUrl); + if (!adId && !impressionDoc && !errorDoc) { + return vastXml; + } + + const vastXmlDoc = xmlUtil.parse(vastXml); + appendTrackingNodes(vastXmlDoc, impressionDoc, errorDoc); + replaceAdId(vastXmlDoc, adId); + return xmlUtil.serialize(vastXmlDoc); + } + + function appendTrackingNodes(vastXmlDoc, impressionDoc, errorDoc) { + const nodes = vastXmlDoc.querySelectorAll('InLine,Wrapper'); + const nodeCount = nodes.length; + for (let i = 0; i < nodeCount; i++) { + const node = nodes[i]; + // A copy of the child is required until we reach the last node. + const requiresCopy = i < nodeCount - 1; + appendChild(node, impressionDoc, requiresCopy); + appendChild(node, errorDoc, requiresCopy); + } + } + + function replaceAdId(vastXmlDoc, adId) { + if (!adId) { + return; + } + + const adNode = vastXmlDoc.querySelector('Ad'); + if (!adNode) { + return; + } + + adNode.id = adId; + } + + return { + getVastXmlWithTracking, + buildVastWrapper + } + + function getImpressionDoc(impressionUrl, impressionId) { + if (!impressionUrl) { + return; + } + + const impressionNode = getImpressionNode(impressionUrl, impressionId); + return xmlUtil.parse(impressionNode); + } + + function getErrorDoc(errorUrl) { + if (!errorUrl) { + return; + } + + const errorNode = getErrorNode(errorUrl); + return xmlUtil.parse(errorNode); + } + + function appendChild(node, child, copy) { + if (!child) { + return; + } + + const doc = copy ? child.cloneNode(true) : child; + node.appendChild(doc.documentElement); + } +} + +function XMLUtil() { + let parser; + let serializer; + + function getParser() { + if (!parser) { + // DOMParser instantiation is costly; instantiate only once throughout Prebid lifecycle. + parser = new DOMParser(); + } + return parser; + } + + function getSerializer() { + if (!serializer) { + // XMLSerializer instantiation is costly; instantiate only once throughout Prebid lifecycle. + serializer = new XMLSerializer(); + } + return serializer; + } + + function parse(xmlString) { + return getParser().parseFromString(xmlString, XML_MIME_TYPE); + } + + function serialize(xmlDoc) { + return getSerializer().serializeToString(xmlDoc); + } + + return { + parse, + serialize + }; +} + +export function vastXmlEditorFactory() { + return VastXmlEditor(XMLUtil()); +} diff --git a/modules/.submodules.json b/modules/.submodules.json index bd00333a1d9..e4678a86b71 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -75,6 +75,10 @@ "enrichmentFpdModule", "validationFpdModule", "topicsFpdModule" + ], + "videoModule": [ + "jwplayerVideoProvider", + "videojsVideoProvider" ] } -} \ No newline at end of file +} diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index cabbb448960..77ffe0f6b94 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -43,7 +43,7 @@ const URL = 'https://ib.adnxs.com/ut/v3/prebid'; const URL_SIMPLE = 'https://ib.adnxs-simple.com/ut/v3/prebid'; const VIDEO_TARGETING = ['id', 'minduration', 'maxduration', 'skippable', 'playback_method', 'frameworks', 'context', 'skipoffset']; -const VIDEO_RTB_TARGETING = ['minduration', 'maxduration', 'skip', 'skipafter', 'playbackmethod', 'api']; +const VIDEO_RTB_TARGETING = ['minduration', 'maxduration', 'skip', 'skipafter', 'playbackmethod', 'api', 'startdelay']; const USER_PARAMS = ['age', 'externalUid', 'segments', 'gender', 'dnt', 'language']; const APP_DEVICE_PARAMS = ['geo', 'device_id']; // appid is collected separately const DEBUG_PARAMS = ['enabled', 'dongle', 'member_id', 'debug_timeout']; @@ -920,6 +920,17 @@ function bidToTag(bid) { tag['video_frameworks'] = apiTmp; } break; + + case 'startdelay': + case 'placement': + const contextKey = 'context'; + if (typeof tag.video[contextKey] !== 'number') { + const placement = videoMediaType['placement']; + const startdelay = videoMediaType['startdelay']; + const context = getContextFromPlacement(placement) || getContextFromStartDelay(startdelay); + tag.video[contextKey] = VIDEO_MAPPING[contextKey][context]; + } + break; } }); } @@ -967,6 +978,32 @@ function transformSizes(requestSizes) { return sizes; } +function getContextFromPlacement(ortbPlacement) { + if (!ortbPlacement) { + return; + } + + if (ortbPlacement === 2) { + return 'in-banner'; + } else if (ortbPlacement > 2) { + return 'outstream'; + } +} + +function getContextFromStartDelay(ortbStartDelay) { + if (!ortbStartDelay) { + return; + } + + if (ortbStartDelay === 0) { + return 'pre_roll'; + } else if (ortbStartDelay === -1) { + return 'mid_roll'; + } else if (ortbStartDelay === -2) { + return 'post_roll'; + } +} + function hasUserInfo(bid) { return !!bid.params.user; } diff --git a/modules/gridNMBidAdapter.js b/modules/gridNMBidAdapter.js index bfe5f3952bc..6f8eaba43d3 100644 --- a/modules/gridNMBidAdapter.js +++ b/modules/gridNMBidAdapter.js @@ -34,8 +34,6 @@ const LOG_ERROR_MESS = { hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' }; -const VIDEO_KEYS = ['mimes', 'protocols', 'startdelay', 'placement', 'linearity', 'skip', 'skipmin', 'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate', 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend', 'delivery', 'pos', 'companionad', 'api', 'companiontype']; - export const spec = { code: BIDDER_CODE, supportedMediaTypes: [ VIDEO ], @@ -105,7 +103,7 @@ export const spec = { const impObj = { id: bidId.toString(), tagid: secid.toString(), - video: createVideoForImp(video, sizes, mediaTypes && mediaTypes.video), + video: createVideoForImp(mergeDeep({}, video, mediaTypes && mediaTypes.video), sizes), ext: { divid: adUnitCode.toString() } @@ -386,13 +384,7 @@ function createRenderer (bid, rendererParams) { return renderer; } -function createVideoForImp({ mind, maxd, size, ...paramsVideo }, bidSizes, bidVideo = {}) { - VIDEO_KEYS.forEach((key) => { - if (!(key in paramsVideo) && key in bidVideo) { - paramsVideo[key] = bidVideo[key]; - } - }); - +function createVideoForImp({ mind, maxd, size, ...paramsVideo }, bidSizes) { if (size && isStr(size)) { const sizeArray = size.split('x'); if (sizeArray.length === 2 && parseInt(sizeArray[0]) && parseInt(sizeArray[1])) { @@ -402,7 +394,7 @@ function createVideoForImp({ mind, maxd, size, ...paramsVideo }, bidSizes, bidVi } if (!paramsVideo.w || !paramsVideo.h) { - const playerSizes = bidVideo.playerSize && bidVideo.playerSize.length === 2 ? bidVideo.playerSize : bidSizes; + const playerSizes = paramsVideo.playerSize && paramsVideo.playerSize.length === 2 ? paramsVideo.playerSize : bidSizes; if (playerSizes) { const playerSize = playerSizes[0]; if (playerSize) { @@ -411,9 +403,13 @@ function createVideoForImp({ mind, maxd, size, ...paramsVideo }, bidSizes, bidVi } } - const durationRangeSec = bidVideo.durationRangeSec || []; - const minDur = mind || durationRangeSec[0] || bidVideo.minduration; - const maxDur = maxd || durationRangeSec[1] || bidVideo.maxduration; + if (paramsVideo.playerSize) { + delete paramsVideo.playerSize; + } + + const durationRangeSec = paramsVideo.durationRangeSec || []; + const minDur = mind || durationRangeSec[0] || paramsVideo.minduration; + const maxDur = maxd || durationRangeSec[1] || paramsVideo.maxduration; if (minDur) { paramsVideo.minduration = minDur; diff --git a/modules/jwplayerVideoProvider.js b/modules/jwplayerVideoProvider.js new file mode 100644 index 00000000000..d606e8121a7 --- /dev/null +++ b/modules/jwplayerVideoProvider.js @@ -0,0 +1,929 @@ +import { + PROTOCOLS, API_FRAMEWORKS, VIDEO_MIME_TYPE, PLAYBACK_METHODS, PLACEMENT, VPAID_MIME_TYPE, AD_POSITION +} from '../libraries/video/constants/ortb.js'; +import { + SETUP_COMPLETE, SETUP_FAILED, DESTROYED, AD_REQUEST, AD_BREAK_START, AD_LOADED, AD_STARTED, AD_IMPRESSION, AD_PLAY, + AD_TIME, AD_PAUSE, AD_CLICK, AD_SKIPPED, AD_ERROR, AD_COMPLETE, AD_BREAK_END, PLAYLIST, PLAYBACK_REQUEST, + AUTOSTART_BLOCKED, PLAY_ATTEMPT_FAILED, CONTENT_LOADED, PLAY, PAUSE, BUFFER, TIME, SEEK_START, SEEK_END, MUTE, VOLUME, + RENDITION_UPDATE, ERROR, COMPLETE, PLAYLIST_COMPLETE, FULLSCREEN, PLAYER_RESIZE, VIEWABLE, CAST +} from '../libraries/video/constants/events.js'; +import { PLAYBACK_MODE } from '../libraries/video/constants/enums.js'; +import stateFactory from '../libraries/video/shared/state.js'; +import { JWPLAYER_VENDOR } from '../libraries/video/constants/vendorCodes.js'; +import { getEventHandler } from '../libraries/video/shared/eventHandler.js'; +import { submodule } from '../src/hook.js'; + +/** + * @constructor + * @param {videoProviderConfig} config + * @param {Object} jwplayer_ - JW Player global factory + * @param {State} adState_ + * @param {State} timeState_ + * @param {CallbackStorage} callbackStorage_ + * @param {Object} utils + * @returns {VideoProvider} + */ +export function JWPlayerProvider(config, jwplayer_, adState_, timeState_, callbackStorage_, utils, sharedUtils) { + const jwplayer = jwplayer_; + let player = null; + let playerVersion = null; + const playerConfig = config.playerConfig; + const divId = config.divId; + let adState = adState_; + let timeState = timeState_; + let callbackStorage = callbackStorage_; + let pendingSeek = {}; + let supportedMediaTypes = null; + let minimumSupportedPlayerVersion = '8.20.1'; + let setupCompleteCallbacks = []; + let setupFailedCallbacks = []; + const MEDIA_TYPES = [ + VIDEO_MIME_TYPE.MP4, + VIDEO_MIME_TYPE.OGG, + VIDEO_MIME_TYPE.WEBM, + VIDEO_MIME_TYPE.AAC, + VIDEO_MIME_TYPE.HLS + ]; + + function init() { + if (!jwplayer) { + triggerSetupFailure(-1); // TODO: come up with code for player absent + return; + } + + playerVersion = jwplayer.version; + + if (playerVersion < minimumSupportedPlayerVersion) { + triggerSetupFailure(-2); // TODO: come up with code for version not supported + return; + } + + player = jwplayer(divId); + if (player.getState() === undefined) { + setupPlayer(playerConfig); + } else { + const payload = getSetupCompletePayload(); + setupCompleteCallbacks.forEach(callback => callback(SETUP_COMPLETE, payload)); + setupCompleteCallbacks = []; + } + } + + function getId() { + return divId; + } + + function getOrtbVideo() { + if (!player) { + return; + } + + const config = player.getConfig() || {}; + const adConfig = config.advertising || {}; + supportedMediaTypes = supportedMediaTypes || utils.getSupportedMediaTypes(MEDIA_TYPES); + + const video = { + mimes: supportedMediaTypes, + protocols: [ + PROTOCOLS.VAST_2_0, + PROTOCOLS.VAST_3_0, + PROTOCOLS.VAST_4_0, + PROTOCOLS.VAST_2_0_WRAPPER, + PROTOCOLS.VAST_3_0_WRAPPER, + PROTOCOLS.VAST_4_0_WRAPPER + ], + h: player.getHeight(), // TODO does player call need optimization ? + w: player.getWidth(), // TODO does player call need optimization ? + startdelay: utils.getStartDelay(), + placement: utils.getPlacement(adConfig, player), + // linearity is omitted because both forms are supported. + // sequence - TODO not yet supported + battr: adConfig.battr, + maxextended: -1, // extension is allowed, and there is no time limit imposed. + boxingallowed: 1, + playbackmethod: [ utils.getPlaybackMethod(config) ], + playbackend: 1, // TODO: need to account for floating player - https://developer.jwplayer.com/jwplayer/docs/jw8-embed-an-outstream-player , https://developer.jwplayer.com/jwplayer/docs/jw8-player-configuration-reference#section-float-on-scroll + // companionad - TODO add in future version + // companiontype - TODO add in future version + // minbitrate - TODO add in future version + // maxbitrate - TODO add in future version + // delivery - omitted because all are supported. + // minduration - Is there value to specifying ? + // maxduration - Is there value to specifying ? + api: [ + API_FRAMEWORKS.VPAID_2_0 + ], + }; + + if (utils.isOmidSupported(adConfig.adClient)) { + video.api.push(API_FRAMEWORKS.OMID_1_0); + } + + Object.assign(video, utils.getSkipParams(adConfig)); + + if (player.getFullscreen()) { // TODO does player call need optimization ? + // only specify ad position when in Fullscreen since computational cost is low + // ad position options are listed in oRTB 2.5 section 5.4 + // https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf + video.pos = AD_POSITION.FULL_SCREEN; // TODO make constant in oRTB + } + + return video; + } + + function getOrtbContent() { + if (!player) { + return; + } + + const item = player.getPlaylistItem() || {}; // TODO does player call need optimization ? + let { duration, playbackMode } = timeState.getState(); + if (duration === undefined) { + duration = player.getDuration(); + } + + const content = { + url: item.file, + title: item.title, + cat: item.iabCategories, + keywords: item.tags, + len: duration, + embeddable: 1 + }; + + if (playbackMode !== undefined) { + content.livestream = Math.min(playbackMode, 1); + } + + const mediaId = item.mediaid; + if (mediaId) { + content.id = 'jw_' + mediaId; + } + + const jwpseg = item.jwpseg; + const dataSegment = utils.getSegments(jwpseg); + const contentDatum = utils.getContentDatum(mediaId, dataSegment); + if (contentDatum) { + content.data = [contentDatum]; + } + + const isoLanguageCode = utils.getIsoLanguageCode(player); + if (isoLanguageCode) { + content.language = isoLanguageCode; + } + + return content; + } + + function setAdTagUrl(adTagUrl, options) { + if (!player) { + return; + } + + player.playAd(adTagUrl || options.adXml, options); + } + + function onEvent(externalEventName, callback, basePayload) { + if (externalEventName === SETUP_COMPLETE) { + setupCompleteCallbacks.push(callback); + } else if (externalEventName === SETUP_FAILED) { + setupFailedCallbacks.push(callback); + } + + if (!player) { + return; + } + + let getEventPayload; + + switch (externalEventName) { + case SETUP_COMPLETE: + getEventPayload = () => { + setupCompleteCallbacks = []; + return getSetupCompletePayload(); + }; + break; + + case SETUP_FAILED: + getEventPayload = e => { + setupFailedCallbacks = []; + return { + playerVersion, + errorCode: e.code, + errorMessage: e.message, + sourceError: e.sourceError + }; + }; + break; + + case AD_REQUEST: + case AD_PLAY: + case AD_PAUSE: + getEventPayload = e => ({ adTagUrl: e.tag }); + break; + + case AD_BREAK_START: + getEventPayload = e => { + timeState.clearState(); + return { offset: e.adPosition }; + }; + break; + + case AD_LOADED: + getEventPayload = e => { + adState.updateForEvent(e); + const adConfig = player.getConfig().advertising; + adState.updateState(utils.getSkipParams(adConfig)); + return adState.getState(); + }; + break; + + case AD_STARTED: + // JW Player adImpression fires when the ad starts, regardless of viewability. + getEventPayload = () => adState.getState(); + break; + + case AD_IMPRESSION: + case AD_CLICK: + getEventPayload = () => Object.assign({}, adState.getState(), timeState.getState()); + break; + + case AD_TIME: + getEventPayload = e => { + timeState.updateForEvent(e); + return { + adTagUrl: e.tag, + time: e.position, + duration: e.duration, + }; + }; + break; + + case AD_SKIPPED: + getEventPayload = e => { + adState.clearState(); + return { + time: e.position, + duration: e.duration, + }; + }; + break; + + case AD_ERROR: + getEventPayload = e => { + const extraPayload = Object.assign({ + playerErrorCode: e.adErrorCode, + vastErrorCode: e.code, + errorMessage: e.message, + sourceError: e.sourceError + // timeout + }, adState.getState(), timeState.getState()); + adState.clearState(); + return extraPayload; + }; + break; + + case AD_COMPLETE: + getEventPayload = e => { + adState.clearState(); + return { adTagUrl: e.tag }; + }; + break; + + case AD_BREAK_END: + getEventPayload = e => ({ offset: e.adPosition }); + break; + + case PLAYLIST: + getEventPayload = e => { + const playlistItemCount = e.playlist.length; + return { + playlistItemCount, + autostart: player.getConfig().autostart + }; + }; + break; + + case PLAYBACK_REQUEST: + getEventPayload = e => ({ playReason: e.playReason }); + break; + + case AUTOSTART_BLOCKED: + getEventPayload = e => ({ + sourceError: e.error, + errorCode: e.code, + errorMessage: e.message + }); + break; + + case PLAY_ATTEMPT_FAILED: + getEventPayload = e => ({ + playReason: e.playReason, + sourceError: e.sourceError, + errorCode: e.code, + errorMessage: e.message + }); + break; + + case CONTENT_LOADED: + getEventPayload = e => { + const { item, index } = e; + return { + contentId: item.mediaid, + contentUrl: item.file, // cover other sources ? util ? + title: item.title, + description: item.description, + playlistIndex: index, + contentTags: item.tags + }; + }; + break; + + case BUFFER: + getEventPayload = () => timeState.getState(); + break; + + case TIME: + getEventPayload = e => { + timeState.updateForEvent(e); + return { + position: e.position, + duration: e.duration + }; + }; + break; + + case SEEK_START: + getEventPayload = e => { + const duration = e.duration; + const offset = e.offset; + pendingSeek = { + duration, + offset + }; + return { + position: e.position, + destination: offset, + duration: duration + }; + } + break; + + case SEEK_END: + getEventPayload = () => { + const extraPayload = { + position: pendingSeek.offset, + duration: pendingSeek.duration + }; + pendingSeek = {}; + return extraPayload; + }; + break; + + case MUTE: + getEventPayload = e => ({ mute: e.mute }); + break; + + case VOLUME: + getEventPayload = e => ({ volumePercentage: e.volume }); + break; + + case RENDITION_UPDATE: + getEventPayload = e => { + const bitrate = e.bitrate; + const level = e.level; + return { + videoReportedBitrate: bitrate, + audioReportedBitrate: bitrate, + encodedVideoWidth: level.width, + encodedVideoHeight: level.height, + videoFramerate: e.frameRate + }; + }; + break; + + case ERROR: + getEventPayload = e => ({ + sourceError: e.sourceError, + errorCode: e.code, + errorMessage: e.message, + }); + break; + + case COMPLETE: + getEventPayload = e => timeState.clearState(); + break; + + case FULLSCREEN: + getEventPayload = e => ({ fullscreen: e.fullscreen }); + break; + + case PLAYER_RESIZE: + getEventPayload = e => ({ + height: e.height, + width: e.width, + }); + break; + + case VIEWABLE: + getEventPayload = e => ({ + viewable: e.viewable, + viewabilityPercentage: player.getPercentViewable() * 100, + }); + break; + + case CAST: + getEventPayload = e => ({ casting: e.active }); + break; + + case PLAY: + case PAUSE: + case PLAYLIST_COMPLETE: + case DESTROYED: + break; + + default: + return; + } + + const jwEventName = utils.getJwEvent(externalEventName); + const eventHandler = getEventHandler(externalEventName, callback, basePayload, getEventPayload) + player.on(jwEventName, eventHandler); + callbackStorage.storeCallback(externalEventName, eventHandler, callback); + } + + function offEvent(event, callback) { + const jwEvent = utils.getJwEvent(event); + if (!callback) { + player.off(jwEvent); + return; + } + + const eventHandler = callbackStorage.getCallback(event, callback); + if (!eventHandler) { + return; + } + + player.off(jwEvent, eventHandler); + } + + function destroy() { + if (!player) { + return; + } + player.remove(); + player = null; + } + + return { + init, + getId, + getOrtbVideo, + getOrtbContent, + setAdTagUrl, + onEvent, + offEvent, + destroy + }; + + function setupPlayer(config) { + if (!config) { + return; + } + player.setup(utils.getJwConfig(config)); + } + + function getSetupCompletePayload() { + return { + divId, + playerVersion, + type: SETUP_COMPLETE, + viewable: player.getViewable(), + viewabilityPercentage: player.getPercentViewable() * 100, + mute: player.getMute(), + volumePercentage: player.getVolume() + }; + } + + function triggerSetupFailure(errorCode) { + if (!setupFailedCallbacks.length) { + return; + } + + const payload = { + divId, + playerVersion, + type: SETUP_FAILED, + errorCode, + errorMessage: '', + sourceError: null + }; + + setupFailedCallbacks.forEach(callback => callback(SETUP_FAILED, payload)); + setupFailedCallbacks = []; + } +} + +/** + * @param {videoProviderConfig} config + * @param {sharedUtils} sharedUtils + * @returns {VideoProvider} + */ +const jwplayerSubmoduleFactory = function (config, sharedUtils) { + const adState = adStateFactory(); + const timeState = timeStateFactory(); + const callbackStorage = callbackStorageFactory(); + return JWPlayerProvider(config, window.jwplayer, adState, timeState, callbackStorage, utils, sharedUtils); +} + +jwplayerSubmoduleFactory.vendorCode = JWPLAYER_VENDOR; +submodule('video', jwplayerSubmoduleFactory); +export default jwplayerSubmoduleFactory; + +// HELPERS + +export const utils = { + getJwConfig: function(config) { + if (!config) { + return; + } + + const params = config.params || {}; + const jwConfig = params.vendorConfig || {}; + if (jwConfig.autostart === undefined && config.autoStart !== undefined) { + jwConfig.autostart = config.autoStart; + } + + if (jwConfig.mute === undefined && config.mute !== undefined) { + jwConfig.mute = config.mute; + } + + if (!jwConfig.key && config.licenseKey !== undefined) { + jwConfig.key = config.licenseKey; + } + + if (config.setupAds === false) { + return jwConfig; + } + + const advertising = jwConfig.advertising || { client: 'vast' }; + if (!jwConfig.file && !jwConfig.playlist && !jwConfig.source) { + // TODO verify accuracy + advertising.outstream = true; + } + + const bids = advertising.bids || {}; + bids.prebid = true; + advertising.bids = bids; + + jwConfig.advertising = advertising; + return jwConfig; + }, + + getJwEvent: function(eventName) { + switch (eventName) { + case SETUP_COMPLETE: + return 'ready'; + + case SETUP_FAILED: + return 'setupError'; + + case DESTROYED: + return 'remove'; + + case AD_STARTED: + return AD_IMPRESSION; + + case AD_IMPRESSION: + return 'adViewableImpression'; + + case PLAYBACK_REQUEST: + return 'playAttempt'; + + case AUTOSTART_BLOCKED: + return 'autostartNotAllowed'; + + case CONTENT_LOADED: + return 'playlistItem'; + + case SEEK_START: + return 'seek'; + + case SEEK_END: + return 'seeked'; + + case RENDITION_UPDATE: + return 'visualQuality'; + + case PLAYER_RESIZE: + return 'resize'; + + default: + return eventName; + } + }, + + getSkipParams: function(adConfig) { + const skipParams = {}; + const skipoffset = adConfig.skipoffset; + if (skipoffset !== undefined) { + const skippable = skipoffset >= 0; + skipParams.skip = skippable ? 1 : 0; + if (skippable) { + skipParams.skipmin = skipoffset + 2; + skipParams.skipafter = skipoffset; + } + } + return skipParams; + }, + + getSupportedMediaTypes: function(mediaTypes = []) { + const el = document.createElement('video'); + return mediaTypes + .filter(mediaType => el.canPlayType(mediaType)) + .concat(VPAID_MIME_TYPE); // Always allow VPAIDs. + }, + + getStartDelay: function() { + // todo calculate + // need to know which ad we are bidding on + // Might have to implement and set in Pb-video ; would required ad unit as param. + }, + + /** + * Determine the ad placement + * @param {Object} adConfig + * @param {Object} player + * @return {PLACEMENT|OrtbVideoParams.placement|undefined} + */ + getPlacement: function(adConfig, player) { + if (!adConfig.outstream) { + // https://developer.jwplayer.com/jwplayer/docs/jw8-embed-an-outstream-player for more info on outstream + return PLACEMENT.INSTREAM; + } + + if (player.getFloating()) { + return PLACEMENT.FLOATING; + } + + const placement = adConfig.placement; + if (!placement) { + return; + } + + return PLACEMENT[placement.toUpperCase()]; + }, + + getPlaybackMethod: function({ autoplay, mute, autoplayAdsMuted }) { + if (autoplay) { + // Determine whether player is going to start muted. + const isMuted = mute || autoplayAdsMuted; // todo autoplayAdsMuted only applies to preRoll + return isMuted ? PLAYBACK_METHODS.AUTOPLAY_MUTED : PLAYBACK_METHODS.AUTOPLAY; + } + /* + TODO + could support the following with float player: + 5 Initiates on Entering Viewport with Sound On + 6 Initiates on Entering Viewport with Sound Off by Default + */ + return PLAYBACK_METHODS.CLICK_TO_PLAY; + }, + + /** + * Indicates if Omid is supported + * + * @param {string} adClient - The identifier of the ad plugin requesting the bid + * @returns {boolean} - support of omid + */ + isOmidSupported: function(adClient) { + const omidIsLoaded = window.OmidSessionClient !== undefined; + return omidIsLoaded && adClient === 'vast'; + }, + + /** + * Gets ISO 639 language code of current audio track. + * @param {Object} player + * @returns {string|undefined} ISO 639 language code. + */ + getIsoLanguageCode: function(player) { + const audioTracks = player.getAudioTracks(); + if (!audioTracks || !audioTracks.length) { + return; + } + + const currentTrackIndex = Math.max(player.getCurrentAudioTrack() || 0, 0); // returns -1 when there are no alternative tracks. + const audioTrack = audioTracks[currentTrackIndex]; + return audioTrack && audioTrack.language; + }, + + /** + * Converts an array of jwpsegs into an array of data segments compliant with the oRTB content.data[index].segment + * @param {[String]} jwpsegs - jwplayer contextual targeting segments + * @return {[Object]|undefined} list of data segments compliant with the oRTB content.data[index].segment spec + */ + getSegments: function (jwpsegs) { + if (!jwpsegs || !jwpsegs.length) { + return; + } + + const formattedSegments = jwpsegs.reduce((convertedSegments, rawSegment) => { + convertedSegments.push({ + id: rawSegment, + value: rawSegment + }); + return convertedSegments; + }, []); + + return formattedSegments; + }, + + /** + * Creates an object compliant with the oRTB content.data[index] spec. + * @param {String} mediaId - content identifier + * @param {[Object]} segments - list of data segments compliant with the oRTB content.data[index].segment spec + * @return {Object} - Object compliant with the oRTB content.data[index] spec. + */ + getContentDatum: function (mediaId, segments) { + if (!mediaId && !segments) { + return; + } + + const contentData = { + name: 'jwplayer.com', + ext: {} + }; + + if (mediaId) { + contentData.ext.cids = [mediaId]; + } + + if (segments) { + contentData.segment = segments; + contentData.ext.segtax = 502; + } + + return contentData; + } +} + +/** + * Tracks which functions are attached to events + * @typedef CallbackStorage + * @function storeCallback + * @function getCallback + * @function clearStorage + */ + +/** + * @returns {CallbackStorage} + */ +export function callbackStorageFactory() { + let storage = {}; + + function storeCallback(eventType, eventHandler, callback) { + let eventHandlers = storage[eventType]; + if (!eventHandlers) { + eventHandlers = storage[eventType] = {}; + } + + eventHandlers[callback] = eventHandler; + } + + function getCallback(eventType, callback) { + let eventHandlers = storage[eventType]; + if (!eventHandlers) { + return; + } + + const eventHandler = eventHandlers[callback]; + delete eventHandlers[callback]; + return eventHandler; + } + + function clearStorage() { + storage = {}; + } + + return { + storeCallback, + getCallback, + clearStorage + } +} + +// STATE + +/** + * @returns {State} + */ +export function adStateFactory() { + const adState = Object.assign({}, stateFactory()); + + function updateForEvent(event) { + const updates = { + adTagUrl: event.tag, + offset: event.adPosition, + loadTime: event.timeLoading, + vastAdId: event.id, // TODO: delete from spec!! seems JW Player specific + adDescription: event.description, + adServer: event.adsystem, + adTitle: event.adtitle, + advertiserId: event.advertiserId, + advertiserName: event.advertiser, + dealId: event.dealId, + // adCategories + linear: event.linear, + vastVersion: event.vastversion, + // campaignId: + creativeUrl: event.mediaFile, // TODO: per AP, mediafile might be object w/ file property. verify + adId: event.adId, + universalAdId: event.universalAdId, + creativeId: event.creativeAdId, + creativeType: event.creativetype, + redirectUrl: event.clickThroughUrl, + adPlacementType: convertPlacementToOrtbCode(event.placement), + waterfallIndex: event.witem, + waterfallCount: event.wcount, + adPodCount: event.podcount, + adPodIndex: event.sequence, + wrapperAdIds: event.wrapperAdIds + }; + + if (event.client === 'googima' && !updates.wrapperAdIds) { + updates.wrapperAdIds = parseImaAdWrapperIds(event); + } + + this.updateState(updates); + } + + adState.updateForEvent = updateForEvent; + + function convertPlacementToOrtbCode(placement) { + switch (placement) { + case 'instream': + return PLACEMENT.INSTREAM; + + case 'banner': + return PLACEMENT.BANNER; + + case 'article': + return PLACEMENT.ARTICLE; + + case 'feed': + return PLACEMENT.FEED; + + case 'interstitial': + case 'slider': + case 'floating': + return PLACEMENT.INTERSTITIAL_SLIDER_FLOATING; + } + } + + function parseImaAdWrapperIds(adEvent) { + const ima = adEvent.ima; + const ad = ima && ima.ad; + if (!ad) { + return; + } + + const adProperties = Object.keys(ad); + adProperties.forEach(property => { + const value = ad[property]; + const wrapperIds = value.adWrapperIds; + if (wrapperIds) { + return wrapperIds; + } + }); + } + + return adState; +} + +/** + * @returns {State} + */ +export function timeStateFactory() { + const timeState = Object.assign({}, stateFactory()); + + function updateForEvent(event) { + const { position, duration } = event; + this.updateState({ + time: position, + duration, + playbackMode: getPlaybackMode(duration) + }); + } + + timeState.updateForEvent = updateForEvent; + + function getPlaybackMode(duration) { + if (duration > 0) { + return PLAYBACK_MODE.VOD; + } else if (duration < 0) { + return PLAYBACK_MODE.DVR; + } + + return PLAYBACK_MODE.LIVE; + } + + return timeState; +} diff --git a/modules/jwplayerVideoProvider.md b/modules/jwplayerVideoProvider.md new file mode 100644 index 00000000000..54a9c1fb84d --- /dev/null +++ b/modules/jwplayerVideoProvider.md @@ -0,0 +1,25 @@ +# Overview + +Module Name: JW Player Video Provider +Module Type: Video Submodule +Video Player: JW player +Player website: https://www.jwplayer.com/html5-video-player/ +Maintainer: karim@jwplayer.com + +# Description + +Video provider to connect the Prebid Video Module to JW Player. + +# Requirements + +Your page must embed a build of JW Player. +i.e. +```html + + + +``` + +[Additional embed instructions](https://docs.jwplayer.com/platform/docs/players-get-started) + +[Obtaining a license](https://info.jwplayer.com/contact-us/) diff --git a/modules/spotxBidAdapter.js b/modules/spotxBidAdapter.js index 5059341baaa..874207adcf8 100644 --- a/modules/spotxBidAdapter.js +++ b/modules/spotxBidAdapter.js @@ -149,7 +149,7 @@ export const spec = { } } - const mimes = getBidIdParameter('mimes', bid.params) || ['application/javascript', 'video/mp4', 'video/webm']; + const mimes = getBidIdParameter('mimes', bid.params) || deepAccess(bid, 'mediaTypes.video.mimes') || ['application/javascript', 'video/mp4', 'video/webm']; const spotxReq = { id: bid.bidId, @@ -176,28 +176,29 @@ export const spec = { spotxReq.bidfloor = getBidIdParameter('price_floor', bid.params); } - if (getBidIdParameter('start_delay', bid.params) != '') { - spotxReq.video.startdelay = 0 + Boolean(getBidIdParameter('start_delay', bid.params)); + const startdelay = getBidIdParameter('start_delay', bid.params) || deepAccess(bid, 'mediaTypes.video.startdelay'); + if (startdelay) { + spotxReq.video.startdelay = 0 + Boolean(startdelay); } - if (getBidIdParameter('min_duration', bid.params) != '') { - spotxReq.video.minduration = getBidIdParameter('min_duration', bid.params); + const minduration = getBidIdParameter('min_duration', bid.params) || deepAccess(bid, 'mediaTypes.video.minduration'); + if (minduration) { + spotxReq.video.minduration = minduration; } - if (getBidIdParameter('max_duration', bid.params) != '') { - spotxReq.video.maxduration = getBidIdParameter('max_duration', bid.params); + const maxduration = getBidIdParameter('max_duration', bid.params) || deepAccess(bid, 'mediaTypes.video.maxduration'); + if (maxduration) { + spotxReq.video.maxduration = maxduration; } - if (getBidIdParameter('placement_type', bid.params) != '') { - spotxReq.video.ext.placement = getBidIdParameter('placement_type', bid.params); + const placement = getBidIdParameter('placement_type', bid.params) || deepAccess(bid, 'mediaTypes.video.placement'); + if (placement) { + spotxReq.video.ext.placement = placement; } - if (getBidIdParameter('position', bid.params) != '') { - spotxReq.video.ext.pos = getBidIdParameter('position', bid.params); - } else { - if (deepAccess(bid, 'mediaTypes.video.pos')) { - spotxReq.video.ext.pos = deepAccess(bid, 'mediaTypes.video.pos'); - } + const position = getBidIdParameter('position', bid.params) || deepAccess(bid, 'mediaTypes.video.pos'); + if (position) { + spotxReq.video.ext.pos = position; } if (bid.crumbs && bid.crumbs.pubcid) { diff --git a/modules/synacormediaBidAdapter.js b/modules/synacormediaBidAdapter.js index 845d6b4b5fb..4ebed12cb05 100644 --- a/modules/synacormediaBidAdapter.js +++ b/modules/synacormediaBidAdapter.js @@ -71,7 +71,7 @@ export const spec = { seatId = bid.params.seatId; } const tagIdOrPlacementId = bid.params.tagId || bid.params.placementId; - let pos = parseInt(bid.params.pos, 10); + let pos = parseInt(bid.params.pos || deepAccess(bid.mediaTypes, 'video.pos'), 10); if (isNaN(pos)) { logWarn(`Synacormedia: there is an invalid POS: ${bid.params.pos}`); pos = 0; diff --git a/modules/videoModule/addingSubmodule.md b/modules/videoModule/addingSubmodule.md new file mode 100644 index 00000000000..874718be1a7 --- /dev/null +++ b/modules/videoModule/addingSubmodule.md @@ -0,0 +1,521 @@ +# How to Add a Video Submodule + +Video submodules interact with the Video Module to integrate Prebid with Video Players, allowing Prebid to automatically: +- render bids in the desired video player +- mark used bids as won +- trigger player and media events +- populate the oRTB Video Impression and Content params in the bid request + +## Overview + +The Prebid Video Module simplifies the way Prebid integrates with video players by acting as a single point of contact for everything video. +In order for the Video Module to connect to a video player, a submodule must be implemented. The submodule acts as a bridge between the Video Module and the video player. +The Video Module will route commands and tasks to the appropriate submodule instance. +A submodule is expected to work for a specific video player. i.e. the JW Player submodule is used to integrate Prebid with JW Player. The video.js submdule connects to video.js. +Publishers who use players from different vendors on the same page can use multiple video submodules. + +## Requirements + +The Video Module only supports integration with Video Players that meet the following requirements: +- Must support parsing and reproduction of VAST ads + - Input can be an ad tag URL or the actual Vast XML. +- Must expose an API that allows the procurement of [Open RTB params](https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf) for Video (section 3.2.7) and Content (section 3.2.16). +- Must emit javascript events for Ads and Media + - see [Event Registration](#event-registration) + +## Creating a Submodule + +### Step 1: Add a markdown file describing the submodule + +Create a markdown file under `modules` with the name of the module suffixed with 'VideoProvider', i.e. `exampleVideoProvider.md`. + +Example markdown file: +```markdown +# Overview + +Module Name: Example Video Provider +Module Type: Video Submodule +Video Player: Example player +Player website: example-player.com +Maintainer: someone@example.com + +# Description + +Video provider for Example Player. Contact someone@example.com for information. + +# Requirements + +Your page must link the Example Player build from our CDN. Alternatively yu can use npm to load the build. +``` + +### Step 2: Add a Vendor Code + +Vendor codes are required to indicate which submodule type to instantiate. Add your vendor code constant to an export const in `vendorCodes.js` in Prebid.js under `libraries/video/constants/vendorCodes.js`. +i.e. in `vendorCodes.js`: + +```javascript +export const EXAMPLE_PLAYER_VENDOR = 3; +``` + +### Step 2: Build the Module + +Now create a javascript file under `modules` with the name of the module suffixed with 'VideoProvider', e.g., `exampleVideoProvider.js`. + +#### The Submodule factory + +The Video Module will need a submodule instance for every player instance registered with Prebid. You will therefore need to implement a submodule factory which is called with a `videoProviderConfig` argument and returns a Video Provider instance. +Your submodule should import your vendor code constant and set it to a `vendorCode` property on your submodule factory. +Your submodule should also import the `submodule` function from `src/hook.js` and should use it to register as a submodule of `'video'`. + +**Code Example** + +```javascript +import { submodule } from '../src/hook.js'; + +function exampleSubmoduleFactory(videoProviderConfig) { + const videoProvider = { + // implementation + }; + + return videoProvider; +} + +exampleSubmoduleFactory.vendorCode = EXAMPLE_VENDOR; +submodule('video', exampleSubmoduleFactory); +``` + +#### The Submodule object + +The submodule object must adhere to the `VideoProvider` interface defined in the `coreVideo.js` inline documentation. + +#### Event registration + +Submodules must support attaching and detaching event listeners on the video player. The list of events are defined in the Events file in the Video Library: `libraries/video/constants/events.js`. +All events and their params must be supported. + +##### Event params + +All Video Module events include a `divId` and `type` param in the payload by default. +The `divId` is the div id string of the player emitting the event; it can be used as an identifier. The `type` is the string name of the event. +The remaining Payload params are listed in the following: + +###### SETUP_COMPLETE + +| argument name | type | description | +| ------------- | ---- | ----------- | +| playerVersion | string | The version of the player on the page | +| viewable | boolean | Is the player currently viewable? | +| viewabilityPercentage | number | The percentage of the video that is currently viewable on the user's screen. | +| mute | boolean | Whether or not the player is currently muted. | +| volumePercentage | number | The volume of the player, as a percentage | + +###### SETUP_FAILED + +| argument name | type | description | +| ------------- | ---- | ----------- | +| playerVersion | string | The version of the player on the page | +| errorCode | number | The identifier of the error preventing the media from rendering | +| errorMessage | string | Developer friendly description of the reason the error occurred. | +| sourceError | object | The underlying root Error which prevented the playback. | + +###### DESTROYED +No additional params. + +###### AD_REQUEST + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | + +###### AD_BREAK_START + +| argument name | type | description | +| ------------- | ---- | ----------- | +| offset | string | Scheduled position in the video for the ad to play. For mid-rolls, will be the position in seconds as string. Other options: 'pre' (pre-roll), 'post' (post-roll), 'api' (ad was not scheduled) | + +###### AD_LOADED + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | +| offset | string | Scheduled position in the video for the ad to play. For mid-rolls, will be the position in seconds as string. Other options: 'pre' (pre-roll), 'post' (post-roll), 'api' (ad was not scheduled) | +| loadTime | number | Time the ad took to load in milliseconds | +| vastAdId | string | The ID given to the ad within the ad tag's XML. Nullable when absent from the VAST xml. | +| adDescription | string | Description of the ad pulled from the ad tag's XML. Nullable when absent from the VAST xml. | +| adServer | string | Ad server used (e.g. dart or mediamind) from the vast tag. Nullable when absent from the VAST xml. | +| adTitle | string | Title of the ad pulled from the ad tag's XML. Nullable when absent from the VAST xml. | +| advertiserId | string | Optional identifier for the advertiser, provided by the ad server. Nullable when absent from the VAST xml. | +| advertiserName | string | Name of the advertiser as defined by the ad serving party, from the vast XML. Nullable when absent from the VAST xml. | +| dealId | string | The ID of the Ads deal. Generally relates to Direct Sold Ad Campaigns. Nullable when absent from the VAST xml. | +| linear | boolean | Is the ad linear or not? | +| vastVersion | string | Version of VAST being reported from the tag | +| creativeUrl | string | The URL representing the VPAID or MP4 ad that is run | +| adId | string | Unique Ad ID - refers to the 'attribute' of the node within the VAST. Nullable when absent from the VAST xml. | +| universalAdId | string | Unique identifier for an ad in VAST4. Nullable when absent from the VAST xml. | +| creativeId | string | Ad server's unique ID for the creative pulled from the ad tag's XML. Should be used to specify the ad server’s unique identifier as opposed to the Universal Ad Id which is used for maintaining a creative id for the ad across multiple systems. Nullable when absent from the VAST xml. | +| creativeType | string | The MIME type of the ad creative currently being displayed | +| redirectUrl | string | the url to which the viewer is being redirected after clicking the ad. Nullable when absent from the VAST xml. | +| adPlacementType | number | The video placements per IAB guidelines. Enum list: In-Stream: 1, In-Banner: 2, In-Article: 3, In-Feed: 4, Interstitial/Slider/Floating: 5 | +| waterfallIndex | number | Index of the current item in the ad waterfall | +| waterfallCount | number | The count of items in a given ad waterfall | +| adPodCount | number | the total number of ads in the pod | +| adPodIndex | number | The index of the currently playing ad within an ad pod | +| wrapperAdIds | array[string] | Ad IDs of the VAST Wrappers that were loaded while loading the Ad tag. The list returned starts at the inline ad (innermost) and traverses to the outermost wrapper ad. An empty array is returned if there are no wrapper ads. | + +###### AD_STARTED + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | +| offset | string | Scheduled position in the video for the ad to play. For mid-rolls, will be the position in seconds as string. Other options: 'pre' (pre-roll), 'post' (post-roll), 'api' (ad was not scheduled) | +| loadTime | number | Time the ad took to load in milliseconds | +| vastAdId | string | The ID given to the ad within the ad tag's XML. Nullable when absent from the VAST xml. | +| adDescription | string | Description of the ad pulled from the ad tag's XML. Nullable when absent from the VAST xml. | +| adServer | string | Ad server used (e.g. dart or mediamind) from the vast tag. Nullable when absent from the VAST xml. | +| adTitle | string | Title of the ad pulled from the ad tag's XML. Nullable when absent from the VAST xml. | +| advertiserId | string | Optional identifier for the advertiser, provided by the ad server. Nullable when absent from the VAST xml. | +| advertiserName | string | Name of the advertiser as defined by the ad serving party, from the vast XML. Nullable when absent from the VAST xml. | +| dealId | string | The ID of the Ads deal. Generally relates to Direct Sold Ad Campaigns. Nullable when absent from the VAST xml. | +| linear | boolean | Is the ad linear or not? | +| vastVersion | string | Version of VAST being reported from the tag | +| creativeUrl | string | The URL representing the VPAID or MP4 ad that is run | +| adId | string | Unique Ad ID - refers to the 'attribute' of the node within the VAST. Nullable when absent from the VAST xml. | +| universalAdId | string | Unique identifier for an ad in VAST4. Nullable when absent from the VAST xml. | +| creativeId | string | Ad server's unique ID for the creative pulled from the ad tag's XML. Should be used to specify the ad server’s unique identifier as opposed to the Universal Ad Id which is used for maintaining a creative id for the ad across multiple systems. Nullable when absent from the VAST xml. | +| creativeType | string | The MIME type of the ad creative currently being displayed | +| redirectUrl | string | the url to which the viewer is being redirected after clicking the ad. Nullable when absent from the VAST xml. | +| adPlacementType | number | The video placements per IAB guidelines. Enum list: In-Stream: 1, In-Banner: 2, In-Article: 3, In-Feed: 4, Interstitial/Slider/Floating: 5 | +| waterfallIndex | number | Index of the current item in the ad waterfall | +| waterfallCount | number | The count of items in a given ad waterfall | +| adPodCount | number | the total number of ads in the pod | +| adPodIndex | number | The index of the currently playing ad within an ad pod | +| wrapperAdIds | array[string] | Ad IDs of the VAST Wrappers that were loaded while loading the Ad tag. The list returned starts at the inline ad (innermost) and traverses to the outermost wrapper ad. An empty array is returned if there are no wrapper ads. | + + + +###### AD_IMPRESSION + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | +| offset | string | Scheduled position in the video for the ad to play. For mid-rolls, will be the position in seconds as string. Other options: 'pre' (pre-roll), 'post' (post-roll), 'api' (ad was not scheduled) | +| loadTime | number | Time the ad took to load in milliseconds | +| vastAdId | string | The ID given to the ad within the ad tag's XML. Nullable when absent from the VAST xml. | +| adDescription | string | Description of the ad pulled from the ad tag's XML. Nullable when absent from the VAST xml. | +| adServer | string | Ad server used (e.g. dart or mediamind) from the vast tag. Nullable when absent from the VAST xml. | +| adTitle | string | Title of the ad pulled from the ad tag's XML. Nullable when absent from the VAST xml. | +| advertiserId | string | Optional identifier for the advertiser, provided by the ad server. Nullable when absent from the VAST xml. | +| advertiserName | string | Name of the advertiser as defined by the ad serving party, from the vast XML. Nullable when absent from the VAST xml. | +| dealId | string | The ID of the Ads deal. Generally relates to Direct Sold Ad Campaigns. Nullable when absent from the VAST xml. | +| linear | boolean | Is the ad linear or not? | +| vastVersion | string | Version of VAST being reported from the tag | +| creativeUrl | string | The URL representing the VPAID or MP4 ad that is run | +| adId | string | Unique Ad ID - refers to the 'attribute' of the node within the VAST. Nullable when absent from the VAST xml. | +| universalAdId | string | Unique identifier for an ad in VAST4. Nullable when absent from the VAST xml. | +| creativeId | string | Ad server's unique ID for the creative pulled from the ad tag's XML. Should be used to specify the ad server’s unique identifier as opposed to the Universal Ad Id which is used for maintaining a creative id for the ad across multiple systems. Nullable when absent from the VAST xml. | +| creativeType | string | The MIME type of the ad creative currently being displayed | +| redirectUrl | string | the url to which the viewer is being redirected after clicking the ad. Nullable when absent from the VAST xml. | +| adPlacementType | number | The video placements per IAB guidelines. Enum list: In-Stream: 1, In-Banner: 2, In-Article: 3, In-Feed: 4, Interstitial/Slider/Floating: 5 | +| waterfallIndex | number | Index of the current item in the ad waterfall | +| waterfallCount | number | The count of items in a given ad waterfall | +| adPodCount | number | the total number of ads in the pod | +| adPodIndex | number | The index of the currently playing ad within an ad pod | +| wrapperAdIds | array[string] | Ad IDs of the VAST Wrappers that were loaded while loading the Ad tag. The list returned starts at the inline ad (innermost) and traverses to the outermost wrapper ad. An empty array is returned if there are no wrapper ads. | +| time | number | The playback time in the ad when the event occurs, in seconds. | +| duration | number | Total duration of an ad in seconds | + +###### AD_PLAY + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | + +###### AD_TIME + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | +| time | number | The current poisition in the ad timeline | +| duration | number | Total duration of an ad in seconds | + +###### AD_PAUSE + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | + +###### AD_CLICK + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | +| offset | string | Scheduled position in the video for the ad to play. For mid-rolls, will be the position in seconds as string. Other options: 'pre' (pre-roll), 'post' (post-roll), 'api' (ad was not scheduled) | +| loadTime | number | Time the ad took to load in milliseconds | +| vastAdId | string | The ID given to the ad within the ad tag's XML. Nullable when absent from the VAST xml. | +| adDescription | string | Description of the ad pulled from the ad tag's XML. Nullable when absent from the VAST xml. | +| adServer | string | Ad server used (e.g. dart or mediamind) from the vast tag. Nullable when absent from the VAST xml. | +| adTitle | string | Title of the ad pulled from the ad tag's XML. Nullable when absent from the VAST xml. | +| advertiserId | string | Optional identifier for the advertiser, provided by the ad server. Nullable when absent from the VAST xml. | +| advertiserName | string | Name of the advertiser as defined by the ad serving party, from the vast XML. Nullable when absent from the VAST xml. | +| dealId | string | The ID of the Ads deal. Generally relates to Direct Sold Ad Campaigns. Nullable when absent from the VAST xml. | +| linear | boolean | Is the ad linear or not? | +| vastVersion | string | Version of VAST being reported from the tag | +| creativeUrl | string | The URL representing the VPAID or MP4 ad that is run | +| adId | string | Unique Ad ID - refers to the 'attribute' of the node within the VAST. Nullable when absent from the VAST xml. | +| universalAdId | string | Unique identifier for an ad in VAST4. Nullable when absent from the VAST xml. | +| creativeId | string | Ad server's unique ID for the creative pulled from the ad tag's XML. Should be used to specify the ad server’s unique identifier as opposed to the Universal Ad Id which is used for maintaining a creative id for the ad across multiple systems. Nullable when absent from the VAST xml. | +| creativeType | string | The MIME type of the ad creative currently being displayed | +| redirectUrl | string | the url to which the viewer is being redirected after clicking the ad. Nullable when absent from the VAST xml. | +| adPlacementType | number | The video placements per IAB guidelines. Enum list: In-Stream: 1, In-Banner: 2, In-Article: 3, In-Feed: 4, Interstitial/Slider/Floating: 5 | +| waterfallIndex | number | Index of the current item in the ad waterfall | +| waterfallCount | number | The count of items in a given ad waterfall | +| adPodCount | number | the total number of ads in the pod | +| adPodIndex | number | The index of the currently playing ad within an ad pod | +| wrapperAdIds | array[string] | Ad IDs of the VAST Wrappers that were loaded while loading the Ad tag. The list returned starts at the inline ad (innermost) and traverses to the outermost wrapper ad. An empty array is returned if there are no wrapper ads. | +| time | number | The playback time in the ad when the event occurs, in seconds. | +| duration | number | Total duration of an ad in seconds | + +###### AD_SKIPPED + +| argument name | type | description | +| ------------- | ---- | ----------- | +| time | number | The playback time in the ad when the event occurs, in seconds. | +| duration | number | Total duration of an ad in seconds | + + + +###### AD_ERROR + +| argument name | type | description | +| ------------- | ---- | ----------- | +| playerErrorCode | number | The ad error code from the Player’s internal spec. | +| vastErrorCode | number | The error code for the VAST response that is returned from the request, as defined in the VAST spec. | +| errorMessage | string | Developer friendly description of the reason the error occurred. | +| sourceError | object | The underlying root Error which prevented the playback. | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | +| offset | string | Scheduled position in the video for the ad to play. For mid-rolls, will be the position in seconds as string. Other options: 'pre' (pre-roll), 'post' (post-roll), 'api' (ad was not scheduled) | +| loadTime | number | Time the ad took to load in milliseconds | +| vastAdId | string | The ID given to the ad within the ad tag's XML. Nullable when absent from the VAST xml. | +| adDescription | string | Description of the ad pulled from the ad tag's XML. Nullable when absent from the VAST xml. | +| adServer | string | Ad server used (e.g. dart or mediamind) from the vast tag. Nullable when absent from the VAST xml. | +| adTitle | string | Title of the ad pulled from the ad tag's XML. Nullable when absent from the VAST xml. | +| advertiserId | string | Optional identifier for the advertiser, provided by the ad server. Nullable when absent from the VAST xml. | +| advertiserName | string | Name of the advertiser as defined by the ad serving party, from the vast XML. Nullable when absent from the VAST xml. | +| dealId | string | The ID of the Ads deal. Generally relates to Direct Sold Ad Campaigns. Nullable when absent from the VAST xml. | +| linear | boolean | Is the ad linear or not? | +| vastVersion | string | Version of VAST being reported from the tag | +| creativeUrl | string | The URL representing the VPAID or MP4 ad that is run | +| adId | string | Unique Ad ID - refers to the 'attribute' of the node within the VAST. Nullable when absent from the VAST xml. | +| universalAdId | string | Unique identifier for an ad in VAST4. Nullable when absent from the VAST xml. | +| creativeId | string | Ad server's unique ID for the creative pulled from the ad tag's XML. Should be used to specify the ad server’s unique identifier as opposed to the Universal Ad Id which is used for maintaining a creative id for the ad across multiple systems. Nullable when absent from the VAST xml. | +| creativeType | string | The MIME type of the ad creative currently being displayed | +| redirectUrl | string | the url to which the viewer is being redirected after clicking the ad. Nullable when absent from the VAST xml. | +| adPlacementType | number | The video placements per IAB guidelines. Enum list: In-Stream: 1, In-Banner: 2, In-Article: 3, In-Feed: 4, Interstitial/Slider/Floating: 5 | +| waterfallIndex | number | Index of the current item in the ad waterfall | +| waterfallCount | number | The count of items in a given ad waterfall | +| adPodCount | number | the total number of ads in the pod | +| adPodIndex | number | The index of the currently playing ad within an ad pod | +| wrapperAdIds | array[string] | Ad IDs of the VAST Wrappers that were loaded while loading the Ad tag. The list returned starts at the inline ad (innermost) and traverses to the outermost wrapper ad. An empty array is returned if there are no wrapper ads. | +| time | number | The playback time in the ad when the event occurs, in seconds. | +| duration | number | Total duration of an ad in seconds | + +###### AD_COMPLETE + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | + +###### AD_BREAK_END + +| argument name | type | description | +| ------------- | ---- | ----------- | +| offset | string | Scheduled position in the video for the ad to play. For mid-rolls, will be the position in seconds as string. Other options: 'pre' (pre-roll), 'post' (post-roll), 'api' (ad was not scheduled) | + +###### PLAYLIST + +| argument name | type | description | +| ------------- | ---- | ----------- | +| playlistItemCount | number | The number of items in the current playlist | +| autostart | boolean | Whether or not the player is set to begin playing automatically. | + +###### PLAYBACK_REQUEST + +| argument name | type | description | +| ------------- | ---- | ----------- | +| playReason | string | wWy the play attempt originated. Options: ‘Unknown’ (Unknown reason:we cannot tell), ‘Interaction’ (A viewer interacts with the UI), ‘Auto’ (Autoplay based on the configuration of the player - autoStart), ‘autoOnViewable’ (autoStart when viewable), ‘autoRepeat’ (media automatically restarted after completion, without any user interaction), ‘Api’ (caused by a call on the player’s API), ‘Internal’ (started because of an internal mechanism i.e. playlist progressed to a recommended item) | + +###### AUTOSTART_BLOCKED + +| argument name | type | description | +| ------------- | ---- | ----------- | +| errorCode | number | The identifier of error preventing the media from rendering | +| errorMessage | string | Developer friendly description of the reason the error occurred. | +| sourceError | object | The underlying root Error which prevented the playback. | + +###### PLAY_ATTEMPT_FAILED + +| argument name | type | description | +| ------------- | ---- | ----------- | +| playReason | string | Why the play attempt originated. Options: ‘Unknown’ (Unknown reason:we cannot tell), ‘Interaction’ (A viewer interacts with the UI), ‘Auto’ (Autoplay based on the configuration of the player - autoStart), ‘autoOnViewable’ (autoStart when viewable), ‘autoRepeat’ (media automatically restarted after completion, without any user interaction), ‘Api’ (caused by a call on the player’s API), ‘Internal’ (started because of an internal mechanism i.e. playlist progressed to a recommended item) | +| errorCode | number | The identifier of error preventing the media from rendering | +| errorMessage | string | Developer friendly description of the reason the error occurred. | +| sourceError | object | The underlying root Error which prevented the playback. | + +###### CONTENT_LOADED + +| argument name | type | description | +| ------------- | ---- | ----------- | +| contentId | string | The unique identifier of the media item being rendered by the video player. Nullable when not provided by Publisher, or unknown. | +| contentUrl | string | The URL of the media source of the playlist item | +| title | string | The title of the content; not meant to be used as a unique identifier. Nullable when not provided by Publisher, or unknown. | +| description | string | The description of the content. Nullable when not provided by Publisher, or unknown. | +| playlistIndex | number | The currently playing media item's index in the playlist. | +| contentTags | array[string] | Customer media level tags describing the content. Nullable when not provided by Publisher, or unknown. | + +###### PLAY + +No additional params. + +###### PAUSE + +No additional params. + +###### BUFFER + +| argument name | type | description | +| ------------- | ---- | ----------- | +| time | number | Playback position of the media in seconds | +| duration | number | Current media’s length in seconds | +| playbackMode | number | The current playback mode used by a given player. Enum list: vod: 0, live: 1, dvr: 2 | + +###### TIME + +| argument name | type | description | +| ------------- | ---- | ----------- | +| position | number | Playback position of the media in seconds | +| duration | number | Current media’s length in seconds | + +###### SEEK_START + +| argument name | type | description | +| ------------- | ---- | ----------- | +| position | number | Playback position of the media in seconds, when the seek begins | +| destination | number | Desired playback position of a seek action, in seconds | +| duration | number | Current media’s length in seconds | + +###### SEEK_END + +| argument name | type | description | +| ------------- | ---- | ----------- | +| position | number | Playback position of the media in seconds, when the seek has ended | +| duration | number | Current media’s length in seconds | + +###### MUTE + +| argument name | type | description | +| ------------- | ---- | ----------- | +| mute | boolean | Whether or not the player is currently muted. | + +###### VOLUME + +| argument name | type | description | +| ------------- | ---- | ----------- | +| volumePercentage | number | The volume of the player, as a percentage | + +###### RENDITION_UPDATE + +| argument name | type | description | +| ------------- | ---- | ----------- | +| videoReportedBitrate | number | The bitrate of the currently playing video in kbps as reported by the Adaptive Manifest. | +| audioReportedBitrate | number | The bitrate of the currently playing audio in kbps as reported by the Adaptive Manifest. | +| encodedVideoWidth | number | The encoded width in pixels of the currently playing video rendition. | +| encodedVideoHeight | number | The encoded height in pixels of the currently playing video rendition. | +| videoFramerate | number | The current rate of playback. For a video that is playing twice as fast as the default playback, the playbackRate value should be 2.00 | + +###### ERROR + +| argument name | type | description | +| ------------- | ---- | ----------- | +| errorCode | number | The identifier of the error preventing the media from rendering | +| errorMessage | string | Developer friendly description of the reason the error occurred. | +| sourceError | object | The underlying root Error which prevented the playback. | + +###### COMPLETE + +No additional params. + +###### PLAYLIST_COMPLETE + +No additional params. + +###### FULLSCREEN + +| argument name | type | description | +| ------------- | ---- | ----------- | +| fullscreen | boolean | Whether or not the player is currently in fullscreen | + +###### PLAYER_RESIZE + +| argument name | type | description | +| ------------- | ---- | ----------- | +| height | number | The height of the player in pixels | +| width | number | The width of the player in pixels | + +###### VIEWABLE + +| argument name | type | description | +| ------------- | ---- | ----------- | +| viewable | boolean | Is the player currently viewable? | +| viewabilityPercentage | number | The percentage of the video that is currently viewable on the user's screen. | + +###### CAST + +| argument name | type | description | +| ------------- | ---- | ----------- | +| casting | boolean | Whether or not the current user is casting to a device | + +###### AUCTION_AD_LOAD_ATTEMPT + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | +| adUnitCode | string | Unique identifier that was used when creating the ad unit. | + +###### AUCTION_AD_LOAD_ABORT + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adUnitCode | string | Unique identifier that was used when creating the ad unit. | + +###### BID_IMPRESSION + +| argument name | type | description | +| ------------- | ---- | ----------- | +| bid | object | Information about the Bid which resulted in the Ad Impression | +| adEvent | object | Event payload from the [Ad Impression](#ad-impression-params) | + +###### BID_ERROR + +| argument name | type | description | +| ------------- | ---- | ----------- | +| bid | object | Information about the Bid which resulted in the Ad Error | +| adEvent | object | Event payload from the [Ad Error](#ad-error-params) | + +#### Update .submodules.json + +In prebid.js, add your new submodule to `.submodules.json` under the `videoModule` as such: +{% highlight text %} +``` +{ + "parentModules": { + "videoModule": [ + "exampleVideoProvider" + ] + } +} +``` + +### Shared resources for developers + +A video library containing reusable code and constants has been added to Prebid.js for your convenience. We encourage you to import from this library. +Constants such as event names can be found in the `libraries/video/constants/` folder. diff --git a/modules/videoModule/coreVideo.js b/modules/videoModule/coreVideo.js new file mode 100644 index 00000000000..c06482b0b36 --- /dev/null +++ b/modules/videoModule/coreVideo.js @@ -0,0 +1,234 @@ +import { module } from '../../src/hook.js'; +import { ParentModule, SubmoduleBuilder } from '../../libraries/video/shared/parentModule.js'; + +// define, ortb object, events + +/** + * Video Provider Submodule interface. All submodules of the Core Video module must adhere to this. + * @description attached to a video player instance. + * @typedef {Object} VideoProvider + * @function init - Instantiates the Video Provider and the video player, if not already instantiated. + * @function getId - retrieves the div id (unique identifier) of the attached player instance. + * @function getOrtbVideo - retrieves the oRTB Video params for a player's current video session. + * @function getOrtbContent - retrieves the oRTB Content params for a player's current video session. + * @function setAdTagUrl - Requests that a player render the ad in the provided ad tag url. + * @function onEvent - attaches an event listener to the player instance. + * @function offEvent - removes event listener to the player instance. + * @function destroy - deallocates the player instance + */ + +/** + * @function VideoProvider#init + */ + +/** + * @function VideoProvider#getId + * @returns {string} + */ + +/** + * @function VideoProvider#getOrtbVideo + * @returns {Object} + */ + +/** + * @function VideoProvider#getOrtbContent + * @returns {Object} + */ + +/** + * @function VideoProvider#setAdTagUrl + * @param {string} adTagUrl - URL to a VAST ad tag + * @param {Object} options - Optional params + */ + +/** + * @function VideoProvider#onEvent + * @param {string} event - name of event for which the listener should be added + * @param {function} callback - function that will get called when the event is triggered + * @param {Object} basePayload - Base payload for every event; includes common parameters such as divId and type. Event payload should be built on top of this. + */ + +/** + * @function VideoProvider#offEvent + * @param {string} event - name of event for which the attached listener should be removed + * @param {function} callback - function that was assigned as a callback when the listener was added + */ + +/** + * @function VideoProvider#destroy + */ + +/** + * @typedef {Object} videoProviderConfig + * @name videoProviderConfig + * @summary contains data indicating which submodule to create and which player instance to attach it to + * @property {string} divId - unique identifier of the player instance + * @property {number} vendorCode - numeric identifier of the Video Provider type i.e. video.js or jwplayer + * @property {playerConfig} playerConfig + */ + +/** + * @typedef {Object} playerConfig + * @name playerConfig + * @summary contains data indicating the behavior the player instance should have + * @property {boolean} autoStart - determines if the player should start automatically when instantiated + * @property {boolean} mute - determines if the player should be muted when instantiated + * @property {string} licenseKey - authentication key required for commercial players. Optional for free players. + * @property {playerVendorParams} params + */ + +/** + * @typedef playerVendorParams + * @name playerVendorParams + * @summary configuration options specific to a Video Vendor's Provider + * @property {Object} vendorConfig - the settings object which can be used as an argument when instantiating a player. Specific to the video player's API. + */ + +/** + * @typedef videoEvent + * + */ + +/** + * Routes commands to the appropriate video submodule. + * @typedef {Object} VideoCore + * @class + * @function registerProvider + * @function getOrtbVideo + * @function getOrtbContent + * @function setAdTagUrl + * @function onEvents + * @function offEvents + */ + +/** + * @summary Maps a Video Provider factory to the video player's vendor code. + * @type {vendorSubmoduleDirectory} + */ +const videoVendorDirectory = {}; + +/** + * @constructor + * @param {ParentModule} parentModule_ + * @returns {VideoCore} + */ +export function VideoCore(parentModule_) { + const parentModule = parentModule_; + + /** + * requests that a submodule be instantiated for the specific player instance described by the @providerConfig + * @name VideoCore#registerProvider + * @param {videoProviderConfig} providerConfig + */ + function registerProvider(providerConfig) { + try { + parentModule.registerSubmodule(providerConfig.divId, providerConfig.vendorCode, providerConfig); + } catch (e) {} + } + + /** + * @name VideoCore#getOrtbVideo + * @summary Obtains the oRTB Video params for a player's current video session. + * @param {string} divId - unique identifier of the player instance + * @returns {Object} oRTB Video params + */ + function getOrtbVideo(divId) { + const submodule = parentModule.getSubmodule(divId); + return submodule && submodule.getOrtbVideo(); + } + + /** + * @name VideoCore#getOrtbContent + * @summary Obtains the oRTB Content params for a player's current video session. + * @param {string} divId - unique identifier of the player instance + * @returns {Object} oRTB Content params + */ + function getOrtbContent(divId) { + const submodule = parentModule.getSubmodule(divId); + return submodule && submodule.getOrtbContent(); + } + + /** + * @name VideoCore#setAdTagUrl + * @summary Requests that a player render the ad in the provided ad tag + * @param {string} adTagUrl - URL to a VAST ad tag + * @param {string} divId - unique identifier of the player instance + * @param {Object} options - additional params + */ + function setAdTagUrl(adTagUrl, divId, options) { + const submodule = parentModule.getSubmodule(divId); + submodule && submodule.setAdTagUrl(adTagUrl, options); + } + + /** + * @name VideoCore#onEvents + * @summary attaches event listeners + * @param {[string]} events - List of event names for which the listener should be added + * @param {function} callback - function that will get called when one of the events is triggered + * @param {string} divId - unique identifier of the player instance + */ + function onEvents(events, callback, divId) { + if (!callback) { + return; + } + + const submodule = parentModule.getSubmodule(divId); + if (!submodule) { + return; + } + + for (let i = 0; i < events.length; i++) { + const type = events[i]; + const basePayload = { + divId, + type + }; + submodule.onEvent(type, callback, basePayload); + } + } + + /** + * @name VideoCore#offEvents + * @summary removes event listeners + * @param {[string]} events - List of event names for which the listener should be removed + * @param {function} callback - function that was assigned as a callback when the listener was added + * @param {string} divId - unique identifier of the player instance + */ + function offEvents(events, callback, divId) { + const submodule = parentModule.getSubmodule(divId); + if (!submodule) { + return; + } + + events.forEach(event => { + submodule.offEvent(event, callback); + }); + } + + return { + registerProvider, + getOrtbVideo, + getOrtbContent, + setAdTagUrl, + onEvents, + offEvents + }; +} + +/** + * @function videoCoreFactory + * @summary Factory to create a Video Core instance + * @returns {VideoCore} + */ +export function videoCoreFactory() { + const videoSubmoduleBuilder = SubmoduleBuilder(videoVendorDirectory); + const parentModule = ParentModule(videoSubmoduleBuilder); + return VideoCore(parentModule); +} + +function attachVideoProvider(submoduleFactory) { + videoVendorDirectory[submoduleFactory.vendorCode] = submoduleFactory; +} + +module('video', attachVideoProvider); diff --git a/modules/videoModule/gamAdServerSubmodule.js b/modules/videoModule/gamAdServerSubmodule.js new file mode 100644 index 00000000000..87db71ae38b --- /dev/null +++ b/modules/videoModule/gamAdServerSubmodule.js @@ -0,0 +1,27 @@ +import { GAM_VENDOR } from '../../libraries/video/constants/vendorCodes.js'; +import { getGlobal } from '../../src/prebidGlobal.js'; + +/** + * @constructor + * @param {Object} dfpModule_ - the DFP ad server module + * @returns {AdServerProvider} + */ +function GamAdServerProvider(dfpModule_) { + const dfp = dfpModule_; + + function getAdTagUrl(adUnit, baseAdTag, params) { + return dfp.buildVideoUrl({ adUnit: adUnit, url: baseAdTag, params }); + } + + return { + getAdTagUrl + } +} + +export function gamSubmoduleFactory() { + const dfp = getGlobal().adServers.dfp; + const gamProvider = GamAdServerProvider(dfp); + return gamProvider; +} + +gamSubmoduleFactory.vendorCode = GAM_VENDOR; diff --git a/modules/videoModule/index.js b/modules/videoModule/index.js new file mode 100644 index 00000000000..33ce3248d91 --- /dev/null +++ b/modules/videoModule/index.js @@ -0,0 +1,244 @@ +import { config } from '../../src/config.js'; +import { find } from '../../src/polyfill.js'; +import * as events from '../../src/events.js'; +import { mergeDeep } from '../../src/utils.js'; +import { getGlobal } from '../../src/prebidGlobal.js'; +import CONSTANTS from '../../src/constants.json'; +import { + videoEvents, AUCTION_AD_LOAD_ATTEMPT, AD_IMPRESSION, AD_ERROR, BID_IMPRESSION, BID_ERROR, AUCTION_AD_LOAD_ABORT +} from '../../libraries/video/constants/events.js' +import { PLACEMENT } from '../../libraries/video/constants/ortb.js'; +import { videoCoreFactory } from './coreVideo.js'; +import { gamSubmoduleFactory } from './gamAdServerSubmodule.js'; +import { videoImpressionVerifierFactory } from './videoImpressionVerifier.js'; + +const videoKey = 'video'; + +const allVideoEvents = Object.keys(videoEvents).map(eventKey => videoEvents[eventKey]); +events.addEvents(allVideoEvents.concat([AUCTION_AD_LOAD_ATTEMPT, AUCTION_AD_LOAD_ABORT, BID_IMPRESSION, BID_ERROR]).map(getExternalVideoEventName)); + +/** + * This module adds User Video support to prebid.js + * @module modules/videoModule + */ +export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvents_, gamAdServerFactory_, videoImpressionVerifierFactory_) { + const videoCore = videoCore_; + const getConfig = getConfig_; + const pbGlobal = pbGlobal_; + const requestBids = pbGlobal.requestBids; + const pbEvents = pbEvents_; + const videoEvents = videoEvents_; + const gamAdServerFactory = gamAdServerFactory_; + let gamSubmodule; + let mainContentDivId; + let contentEnrichmentEnabled = true; + const videoImpressionVerifierFactory = videoImpressionVerifierFactory_; + let videoImpressionVerifier; + + function init() { + const cache = getConfig('cache'); + videoImpressionVerifier = videoImpressionVerifierFactory(!!cache); + getConfig(videoKey, ({ video }) => { + video.providers.forEach(provider => { + videoCore.registerProvider(provider); + videoCore.onEvents(videoEvents, (type, payload) => { + pbEvents.emit(getExternalVideoEventName(type), payload); + }, provider.divId); + + const adServerConfig = provider.adServer; + if (!gamSubmodule && adServerConfig) { + gamSubmodule = gamAdServerFactory(); + } + }); + contentEnrichmentEnabled = video.contentEnrichmentEnabled !== false; + mainContentDivId = contentEnrichmentEnabled ? video.mainContentDivId : null; + }); + + requestBids.before(beforeBidsRequested, 40); + + pbEvents.on(CONSTANTS.EVENTS.BID_ADJUSTMENT, function (bid) { + videoImpressionVerifier.trackBid(bid); + }); + + pbEvents.on(getExternalVideoEventName(AD_IMPRESSION), function (payload) { + triggerVideoBidEvent(BID_IMPRESSION, payload); + }); + + pbEvents.on(getExternalVideoEventName(AD_ERROR), function (payload) { + triggerVideoBidEvent(BID_ERROR, payload); + }); + } + + function renderBid(divId, bid, options = {}) { + const adUrl = bid.vastUrl; + options.adXml = bid.vastXml; + options.winner = bid.bidder; + loadAdTag(adUrl, divId, options); + } + + function getOrtbVideo(divId) { + return videoCore.getOrtbVideo(divId); + } + + function getOrtbContent(divId) { + return videoCore.getOrtbContent(divId); + } + + return { init, renderBid, getOrtbVideo, getOrtbContent }; + + function beforeBidsRequested(nextFn, bidderRequest) { + enrichAuction(bidderRequest); + + const bidsBackHandler = bidderRequest.bidsBackHandler; + if (!bidsBackHandler || typeof bidsBackHandler !== 'function') { + pbEvents.on(CONSTANTS.EVENTS.AUCTION_END, auctionEnd); + } + + return nextFn.call(this, bidderRequest); + } + + function enrichAuction(bidderRequest) { + if (mainContentDivId) { + enrichOrtb2(mainContentDivId, bidderRequest); + } + + const adUnits = bidderRequest.adUnits || pbGlobal.adUnits || []; + adUnits.forEach(adUnit => { + const divId = getDivId(adUnit); + enrichAdUnit(adUnit, divId); + if (contentEnrichmentEnabled && !mainContentDivId) { + enrichOrtb2(divId, bidderRequest); + } + }); + } + + function getDivId(adUnit) { + const videoConfig = adUnit.video; + if (!adUnit.mediaTypes.video || !videoConfig) { + return; + } + + return videoConfig.divId; + } + + function enrichAdUnit(adUnit, videoDivId) { + const ortbVideo = getOrtbVideo(videoDivId); + if (!ortbVideo) { + return; + } + + const video = Object.assign({}, adUnit.mediaTypes.video, ortbVideo); + + video.context = ortbVideo.placement === PLACEMENT.INSTREAM ? 'instream' : 'outstream'; + + const width = ortbVideo.w; + const height = ortbVideo.h; + if (width && height) { + video.playerSize = [width, height]; + } + + adUnit.mediaTypes.video = video; + } + + function enrichOrtb2(divId, bidderRequest) { + const ortbContent = getOrtbContent(divId); + if (!ortbContent) { + return; + } + bidderRequest.ortb2 = mergeDeep({}, bidderRequest.ortb2, { site: { content: ortbContent } }); + } + + function auctionEnd(auctionResult) { + auctionResult.adUnits.forEach(adUnit => { + if (adUnit.video) { + renderWinningBid(adUnit); + } + }); + pbEvents.off(CONSTANTS.EVENTS.AUCTION_END, auctionEnd); + } + + function getAdServerConfig(adUnitVideoConfig) { + const globalVideoConfig = getConfig(videoKey); + const globalProviderConfig = globalVideoConfig.providers.find(provider => provider.divId === adUnitVideoConfig.divId) || {}; + if (!globalVideoConfig.adServer && !globalProviderConfig.adServer && !adUnitVideoConfig.adServer) { + return; + } + return mergeDeep({}, globalVideoConfig.adServer, globalProviderConfig.adServer, adUnitVideoConfig.adServer); + } + + function renderWinningBid(adUnit) { + const adUnitCode = adUnit.code; + const options = { adUnitCode }; + + const videoConfig = adUnit.video; + const divId = videoConfig.divId; + const adServerConfig = getAdServerConfig(videoConfig); + let adUrl; + if (adServerConfig) { + adUrl = gamSubmodule.getAdTagUrl(adUnit, adServerConfig.baseAdTagUrl, adServerConfig.params); + } + + if (adUrl) { + loadAdTag(adUrl, divId, options); + return; + } + + const highestCpmBids = pbGlobal.getHighestCpmBids(adUnitCode); + if (!highestCpmBids.length) { + pbEvents.emit(getExternalVideoEventName(AUCTION_AD_LOAD_ABORT), options); + return; + } + + const highestBid = highestCpmBids.shift(); + if (!highestBid) { + return; + } + + renderBid(divId, highestBid, options); + } + + // options: adXml, winner, adUnitCode, + function loadAdTag(adTagUrl, divId, options) { + const payload = Object.assign({ adTagUrl }, options); + pbEvents.emit(getExternalVideoEventName(AUCTION_AD_LOAD_ATTEMPT), payload); + videoCore.setAdTagUrl(adTagUrl, divId, options); + } + + function triggerVideoBidEvent(eventName, adEventPayload) { + const bid = getBid(adEventPayload); + if (!bid) { + return; + } + + pbGlobal.markWinningBidAsUsed(bid); + pbEvents.emit(getExternalVideoEventName(eventName), { bid, adEvent: adEventPayload }); + } + + function getBid(adPayload) { + const { adId, adTagUrl, wrapperAdIds } = adPayload; + const bidIdentifiers = videoImpressionVerifier.getBidIdentifiers(adId, adTagUrl, wrapperAdIds); + if (!bidIdentifiers) { + return; + } + + const { adUnitCode, requestId, auctionId } = bidIdentifiers; + const bidAdId = bidIdentifiers.adId; + const { bids } = pbGlobal.getBidResponsesForAdUnitCode(adUnitCode); + return find(bids, bid => bid.adId === bidAdId && bid.requestId === requestId && bid.auctionId === auctionId); + } +} + +export function pbVideoFactory() { + const videoCore = videoCoreFactory(); + const pbGlobal = getGlobal(); + const pbVideo = PbVideo(videoCore, config.getConfig, pbGlobal, events, allVideoEvents, gamSubmoduleFactory, videoImpressionVerifierFactory); + pbVideo.init(); + pbGlobal.videoModule = pbVideo; + return pbVideo; +} + +function getExternalVideoEventName(eventName) { + return videoKey + eventName.replace(/^./, eventName[0].toUpperCase()); +} + +pbVideoFactory(); diff --git a/modules/videoModule/videoImpressionVerifier.js b/modules/videoModule/videoImpressionVerifier.js new file mode 100644 index 00000000000..60717c0f855 --- /dev/null +++ b/modules/videoModule/videoImpressionVerifier.js @@ -0,0 +1,206 @@ +import { find } from '../../src/polyfill.js'; +import { vastXmlEditorFactory } from '../../libraries/video/shared/vastXmlEditor.js'; +import { generateUUID } from '../../src/utils.js'; + +export const PB_PREFIX = 'pb_'; +export const UUID_MARKER = PB_PREFIX + 'uuid'; + +/** + * Video Impression Verifier interface. All implementations of a Video Impression Verifier must comply with this interface. + * @description adds tracking markers to an ad and extracts the bid identifiers from ad event information. + * @typedef {Object} VideoImpressionVerifier + * @function trackBid - requests that a bid's ad be tracked for impression verification. + * @function getBidIdentifiers - requests information from the ad event data that can be used to match the ad to a tracked bid. + */ + +/** + * @function VideoImpressionVerifier#trackBid + * @param {Object} bid - Bid that should be tracked. + * @return {String} - Identifier for the bid being tracked. + */ + +/** + * @function VideoImpressionVerifier#getBidIdentifiers + * @param {String} adId - In the VAST tag, this value is present in the Ad element's id property. + * @param {String} adTagUrl - The ad tag url that was loaded into the player. + * @param {[String]} adWrapperIds - List of ad id's that were obtained from the different wrappers. Each redirect points to an ad wrapper. + * @return {bidIdentifier} - Object allowing the bid matching the ad event to be identified. + */ + +/** + * @typedef {Object} bidIdentifier + * @property {String} adId - Bid identifier. + * @property {String} adUnitCode - Identifier for the Ad Unit for which the bid was made. + * @property {String} auctionId - Id of the auction in which the bid was made. + * @property {String} requestId - Id of the bid request which resulted in the bid. + */ + +/** + * Factory function for obtaining a Video Impression Verifier. + * @param {Boolean} isCacheUsed - wether Prebid is configured to use a cache. + * @return {VideoImpressionVerifier} + */ +export function videoImpressionVerifierFactory(isCacheUsed) { + const vastXmlEditor = vastXmlEditorFactory(); + const bidTracker = tracker(); + if (isCacheUsed) { + return cachedVideoImpressionVerifier(vastXmlEditor, bidTracker); + } + + return videoImpressionVerifier(vastXmlEditor, bidTracker); +} + +export function videoImpressionVerifier(vastXmlEditor_, bidTracker_) { + const verifier = baseImpressionVerifier(bidTracker_); + const superTrackBid = verifier.trackBid; + const vastXmlEditor = vastXmlEditor_; + + verifier.trackBid = function(bid) { + let { vastXml, vastUrl } = bid; + if (!vastXml && !vastUrl) { + return; + } + + const uuid = superTrackBid(bid); + + if (vastUrl) { + const url = new URL(vastUrl); + url.searchParams.append(UUID_MARKER, uuid); + bid.vastUrl = url.toString(); + } else if (vastXml) { + bid.vastXml = vastXmlEditor.getVastXmlWithTracking(vastXml, uuid); + } + + return uuid; + } + + return verifier; +} + +export function cachedVideoImpressionVerifier(vastXmlEditor_, bidTracker_) { + const verifier = baseImpressionVerifier(bidTracker_); + const superTrackBid = verifier.trackBid; + const superGetBidIdentifiers = verifier.getBidIdentifiers; + const vastXmlEditor = vastXmlEditor_; + + verifier.trackBid = function (bid, globalAdUnits) { + const adIdOverride = superTrackBid(bid); + let { vastXml, vastUrl, adId, adUnitCode } = bid; + const adUnit = find(globalAdUnits, adUnit => adUnitCode === adUnit.code); + const videoConfig = adUnit && adUnit.video; + const adServerConfig = videoConfig && videoConfig.adServer; + const trackingConfig = adServerConfig && adServerConfig.tracking; + let impressionUrl; + let impressionId; + let errorUrl; + const impressionTracking = trackingConfig.impression; + const errorTracking = trackingConfig.error; + + if (impressionTracking) { + impressionUrl = getTrackingUrl(impressionTracking.getUrl, bid); + impressionId = impressionTracking.id || adId + '-impression'; + } + + if (errorTracking) { + errorUrl = getTrackingUrl(errorTracking.getUrl, bid); + } + + if (vastXml) { + vastXml = vastXmlEditor.getVastXmlWithTracking(vastXml, adIdOverride, impressionUrl, impressionId, errorUrl); + } else if (vastUrl) { + vastXml = vastXmlEditor.buildVastWrapper(adIdOverride, vastUrl, impressionUrl, impressionId, errorUrl); + } + + bid.vastXml = vastXml; + return adIdOverride; + } + + verifier.getBidIdentifiers = function (adId, adTagUrl, adWrapperIds) { + // When the video is cached, the ad tag loaded into the player is a parent wrapper of the cache url. + // As a result, the ad tag Url cannot include identifiers. + return superGetBidIdentifiers(adId, null, adWrapperIds); + } + + return verifier; + + function getTrackingUrl(getUrl, bid) { + if (!getUrl || typeof getUrl !== 'function') { + return; + } + + return getUrl(bid); + } +} + +export function baseImpressionVerifier(bidTracker_) { + const bidTracker = bidTracker_; + + function trackBid(bid) { + let { adId, adUnitCode, requestId, auctionId } = bid; + const trackingId = PB_PREFIX + generateUUID(10 ** 13); + bidTracker.store(trackingId, { adId, adUnitCode, requestId, auctionId }); + return trackingId; + } + + function getBidIdentifiers(adId, adTagUrl, adWrapperIds) { + return bidTracker.remove(adId) || getBidForAdTagUrl(adTagUrl) || getBidForAdWrappers(adWrapperIds); + } + + return { + trackBid, + getBidIdentifiers + }; + + function getBidForAdTagUrl(adTagUrl) { + if (!adTagUrl) { + return; + } + + let url; + try { + url = new URL(adTagUrl); + } catch (e) { + return; + } + + const queryParams = url.searchParams; + let uuid = queryParams.get(UUID_MARKER); + return uuid && bidTracker.remove(uuid); + } + + function getBidForAdWrappers(adWrapperIds) { + if (!adWrapperIds || !adWrapperIds.length) { + return; + } + + for (const wrapperId in adWrapperIds) { + const bidInfo = bidTracker.remove(wrapperId); + if (bidInfo) { + return bidInfo; + } + } + } +} + +export function tracker() { + const model = {}; + + function store(key, value) { + model[key] = value; + } + + function remove(key) { + const value = model[key]; + if (!value) { + return; + } + + delete model[key]; + return value; + } + + return { + store, + remove + } +} diff --git a/modules/videojsVideoProvider.js b/modules/videojsVideoProvider.js new file mode 100644 index 00000000000..a142e0fbb84 --- /dev/null +++ b/modules/videojsVideoProvider.js @@ -0,0 +1,854 @@ +import { + SETUP_COMPLETE, SETUP_FAILED, DESTROYED, + PLAYLIST, PLAYBACK_REQUEST, CONTENT_LOADED, PLAY, PAUSE, TIME, SEEK_START, SEEK_END, MUTE, VOLUME, ERROR, COMPLETE, + FULLSCREEN, PLAYER_RESIZE, + AD_REQUEST, AD_IMPRESSION, AD_TIME, AD_COMPLETE, AD_SKIPPED, AD_CLICK, AD_STARTED, AD_ERROR, AD_LOADED, AD_PLAY, AD_PAUSE +} from '../libraries/video/constants/events.js'; +// missing events: , AD_BREAK_START, , AD_BREAK_END, VIEWABLE, BUFFER, CAST, PLAYLIST_COMPLETE, RENDITION_UPDATE, PLAY_ATTEMPT_FAILED, AUTOSTART_BLOCKED +import { + PROTOCOLS, API_FRAMEWORKS, VIDEO_MIME_TYPE, PLAYBACK_METHODS, PLACEMENT, VPAID_MIME_TYPE, AD_POSITION, PLAYBACK_END +} from '../libraries/video/constants/ortb.js'; +import { VIDEO_JS_VENDOR } from '../libraries/video/constants/vendorCodes.js'; +import { submodule } from '../src/hook.js'; +import stateFactory from '../libraries/video/shared/state.js'; +import { PLAYBACK_MODE } from '../libraries/video/constants/enums.js'; +import { getEventHandler } from '../libraries/video/shared/eventHandler.js'; + +/* +Plugins of interest: +https://www.npmjs.com/package/videojs-chromecast +https://www.npmjs.com/package/@silvermine/videojs-airplay +https://www.npmjs.com/package/videojs-airplay +https://www.npmjs.com/package/@silvermine/videojs-chromecast +https://www.npmjs.com/package/videojs-ima +https://github.com/googleads/videojs-ima +https://github.com/videojs/videojs-playlist +https://github.com/videojs/videojs-contrib-ads +https://github.com/videojs/videojs-errors +https://github.com/videojs/videojs-overlay +https://github.com/videojs/videojs-playlist-ui + +inspiration: +https://github.com/Conviva/conviva-js-videojs/blob/master/conviva-videojs-module.js + */ + +const setupFailMessage = 'Failed to instantiate the player'; +const AD_MANAGER_EVENTS = [AD_LOADED, AD_STARTED, AD_IMPRESSION, AD_PLAY, AD_PAUSE, AD_TIME, AD_COMPLETE, AD_SKIPPED]; + +export function VideojsProvider(config, vjs_, adState_, timeState_, callbackStorage_, utils) { + let vjs = vjs_; + // Supplied callbacks are typically wrapped by handlers + // we use this dict to keep track of these pairings + const callbackToHandler = {}; + + const adState = adState_; + const timeState = timeState_; + let player = null; + let playerVersion = null; + let playerIsSetup = false; + const {playerConfig, divId} = config; + let isMuted; + let previousLastTimePosition = 0; + let lastTimePosition = 0; + + let setupCompleteCallbacks = []; + let setupFailedCallbacks = []; + let setupFailedEventHandlers = []; + + // TODO: test with older videojs versions + let minimumSupportedPlayerVersion = '7.17.0'; + + function init() { + if (!vjs) { + triggerSetupFailure(-1, setupFailMessage + ': Videojs not present') + return; + } + + playerVersion = vjs.VERSION; + if (playerVersion < minimumSupportedPlayerVersion) { + triggerSetupFailure(-2, setupFailMessage + ': Videojs version not supported'); + return; + } + + if (!document.getElementById(divId)) { + triggerSetupFailure(-3, setupFailMessage + ': No div found with id ' + divId); + return; + } + + const instantiatedPlayers = vjs.players; + if (instantiatedPlayers && instantiatedPlayers[divId]) { + // already instantiated + player = instantiatedPlayers[divId]; + onReady(); + return; + } + + setupPlayer(playerConfig); + + if (!player) { + triggerSetupFailure(-4, setupFailMessage); + } + } + + function getId() { + return divId; + } + + function getOrtbVideo() { + if (!player) { + return; + } + + let playBackMethod = PLAYBACK_METHODS.CLICK_TO_PLAY; + // returns a boolean or a string with the autoplay strategy + const autoplay = player.autoplay(); + const muted = player.muted() || autoplay === 'muted'; + // check if autoplay is truthy since it may be a bool or string + if (autoplay) { + playBackMethod = muted ? PLAYBACK_METHODS.AUTOPLAY_MUTED : PLAYBACK_METHODS.AUTOPLAY; + } + const supportedMediaTypes = Object.values(VIDEO_MIME_TYPE).filter( + // Follows w3 spec https://www.w3.org/TR/2011/WD-html5-20110113/video.html#dom-navigator-canplaytype + type => player.canPlayType(type) !== '' + ) + + // IMA supports vpaid unless its expliclty turned off + // TODO: needs a reference to the imaOptions used at setup to determine if vpaid can be used + // if (imaOptions && imaOptions.vpaidMode !== 0) { + supportedMediaTypes.push(VPAID_MIME_TYPE); + // } + + const video = { + mimes: supportedMediaTypes, + // Based on the protocol support provided by the videojs-ima plugin + // https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/compatibility + // Need to check for the plugins + protocols: [ + PROTOCOLS.VAST_2_0, + ], + api: [ + API_FRAMEWORKS.VPAID_2_0 // TODO: needs a reference to the imaOptions used at setup to determine if vpaid can be used + ], + // TODO: Make sure this returns dimensions in DIPS + h: player.currentHeight(), + w: player.currentWidth(), + // TODO: implement startdelay since its reccomend param + // both linearity forms are supported so the param is excluded + // sequence - TODO not yet supported + maxextended: -1, + boxingallowed: 1, + playbackmethod: [ playBackMethod ], + playbackend: PLAYBACK_END.VIDEO_COMPLETION, + // Per ortb 7.4 skip is omitted since neither the player nor ima plugin imposes a skip button, or a skipmin/max + }; + + // TODO: Determine placement may not be in stream if videojs is only used to serve ad content + // ~ Sort of resolved check if the player has a source to tell if the placement is instream + // Still cannot reliably check what type of placement the player is if its outstream + // i.e. we can't tell if its interstitial, in article, etc. + if (player.src()) { + video.placement = PLACEMENT.INSTREAM; + } + + // Placement according to IQG Guidelines 4.2.8 + // https://cdn2.hubspot.net/hubfs/2848641/TrustworthyAccountabilityGroup_May2017/Docs/TAG-Inventory-Quality-Guidelines-v2_2-10-18-2016.pdf?t=1509469105938 + const findPosition = vjs.dom.findPosition; + if (player.isFullscreen()) { + video.pos = AD_POSITION.FULL_SCREEN; + } else if (findPosition) { + video.pos = utils.getPositionCode(findPosition(player.el())); + } + + return video; + } + + function getOrtbContent() { + if (!player) { + return; + } + + const content = { + // id:, TODO: find a suitable id for videojs sources + url: player.currentSrc() + }; + // Only include length if player is ready + // player.readyState() returns a level of readiness from 0 to 4 + // https://docs.videojs.com/player#readyState + if (player.readyState()) { + content.len = Math.round(player.duration()); + } + + const mediaItem = utils.getMedia(player); + if (mediaItem) { + for (let param of ['id', 'title', 'description', 'album', 'artist']) { + if (mediaItem[param]) { + content[param] = mediaItem[param]; + } + } + } + + const contentUrl = utils.getValidMediaUrl(mediaItem && mediaItem.src, player.src) + if (contentUrl) { + content.url = contentUrl; + } + + return content; + } + + // Plugins to integrate: https://github.com/googleads/videojs-ima + function setAdTagUrl(adTagUrl, options) { + if (!player.ima || !adTagUrl) { + return; + } + + player.ima.changeAdTag(adTagUrl); + player.ima.requestAds(); + } + + function onEvent(type, callback, payload) { + registerSetupListeners(type, callback, payload); + + if (!player) { + return; + } + + player.ready(() => { + registerListeners(type, callback, payload); + }); + } + + function registerSetupListeners(externalEventName, callback, basePayload) { + // no point in registering for setup failures if already setup. + if (playerIsSetup) { + return; + } + + if (externalEventName === SETUP_COMPLETE) { + setupCompleteCallbacks.push(callback); + } else if (externalEventName === SETUP_FAILED) { + setupFailedCallbacks.push(callback); + registerSetupErrorListener() + } + } + + function registerSetupErrorListener() { + if (!player) { + return + } + + const eventHandler = () => { + /* + Videojs has no specific setup error handler + so we imitate it by hooking to the general error + handler and checking to see if the player has been setup + */ + if (playerIsSetup) { + return; + } + + const error = player.error(); + triggerSetupFailure(error.code, error.message, error); + }; + + player.on(ERROR, eventHandler); + setupFailedEventHandlers.push(eventHandler) + } + + function registerListeners(externalEventName, callback, basePayload) { + if (externalEventName === MUTE) { + const eventHandler = () => { + if (isMuted !== player.muted()) { + basePayload.mute = isMuted = !isMuted; + callback(externalEventName, basePayload); + } + }; + player.on(utils.getVideojsEventName(VOLUME), eventHandler); + return; + } + + let getEventPayload; + + switch (externalEventName) { + case PLAY: + case PAUSE: + case DESTROYED: + break; + + case PLAYBACK_REQUEST: + getEventPayload = e => ({ playReason: 'unknown' }); + break; + + case AD_REQUEST: + getEventPayload = e => { + const adTagUrl = e.AdsRequest.adTagUrl; + adState.updateState({ adTagUrl }); + return { adTagUrl }; + }; + break + + case AD_LOADED: + getEventPayload = (e) => { + const imaAd = e.getAdData && e.getAdData(); + adState.updateForEvent(imaAd); + timeState.clearState(); + return adState.getState(); + }; + break + + case AD_STARTED: + case AD_PLAY: + case AD_PAUSE: + getEventPayload = () => adState.getState(); + break + + case AD_IMPRESSION: + case AD_CLICK: + getEventPayload = () => Object.assign({}, adState.getState(), timeState.getState()); + break + + case AD_TIME: + getEventPayload = (e) => { + const adTimeEvent = e && e.getAdData && e.getAdData(); + timeState.updateForTimeEvent(adTimeEvent); + return Object.assign({}, adState.getState(), timeState.getState()); + }; + break + + case AD_COMPLETE: + getEventPayload = () => { + const currentState = adState.getState(); + adState.clearState(); + return currentState; + }; + break + + case AD_SKIPPED: + getEventPayload = () => { + const currentState = Object.assign({}, adState.getState(), timeState.getState()); + adState.clearState(); + return currentState; + }; + break + + case AD_ERROR: + getEventPayload = e => { + const imaAdError = e.data && e.data.AdError; + const extraPayload = Object.assign({ + playerErrorCode: imaAdError.getErrorCode(), + vastErrorCode: imaAdError.getVastErrorCode(), + errorMessage: imaAdError.getMessage(), + sourceError: imaAdError.getInnerError() + // timeout + }, adState.getState(), timeState.getState()); + adState.clearState(); + return extraPayload; + }; + break + + case PLAYLIST: + getEventPayload = e => ({ + playlistItemCount: utils.getPlaylistCount(player), + autostart: player.autoplay() + }); + break + + case CONTENT_LOADED: + getEventPayload = e => { + const media = utils.getMedia(player); + const contentUrl = utils.getValidMediaUrl(media && media.src, player.src, e && e.target && e.target.currentSrc) + return { + contentId: media && media.id, + contentUrl, + title: media && media.title, + description: media && media.description, + playlistIndex: utils.getCurrentPlaylistIndex(player), + contentTags: media && media.contentTags + }; + }; + break; + + case TIME: + // TODO: might want to check seeking() and/or scrubbing() + getEventPayload = e => { + previousLastTimePosition = lastTimePosition; + const currentTime = player.currentTime(); + const duration = player.duration(); + timeState.updateForTimeEvent({ currentTime, duration }); + lastTimePosition = currentTime; + return { + position: lastTimePosition, + duration + }; + }; + break; + + case SEEK_START: + getEventPayload = e => { + return { + position: previousLastTimePosition, + destination: player.currentTime(), + duration: player.duration() + }; + } + break; + + case SEEK_END: + getEventPayload = () => ({ + position: player.currentTime(), + duration: player.duration() + }); + break; + + case VOLUME: + getEventPayload = e => ({ volumePercentage: player.volume() * 100 }); + break; + + case ERROR: + getEventPayload = e => { + const error = player.error(); + return { + sourceError: error, + errorCode: error.code, + errorMessage: error.message, + }; + }; + break; + + case COMPLETE: + getEventPayload = e => { + previousLastTimePosition = lastTimePosition = 0; + timeState.clearState(); + }; + break; + + case FULLSCREEN: + getEventPayload = e => ({ fullscreen: player.isFullscreen() }); + break; + + case PLAYER_RESIZE: + getEventPayload = e => ({ + height: player.currentHeight(), + width: player.currentWidth(), + }); + break; + + default: + return; + } + + const eventHandler = getEventHandler(externalEventName, callback, basePayload, getEventPayload); + + if (externalEventName === PLAYLIST) { + registerPlaylistEventListener(eventHandler); + return; + } + + const videojsEventName = utils.getVideojsEventName(externalEventName); + + if (AD_MANAGER_EVENTS.includes(externalEventName)) { + player.on('ads-manager', () => player.ima.addEventListener(videojsEventName, eventHandler)); + } else { + player.on(videojsEventName, eventHandler); + } + } + + function registerPlaylistEventListener(eventHandler) { + if (player.playlist) { + // force a playlist event on first item load + player.one('loadstart', eventHandler); + player.on('playlistchange', eventHandler); + } else { + // When playlist plugin is not used, treat each media item as a single item playlist + player.on('loadstart', eventHandler); + } + } + + function offEvent(event, callback) { + const videojsEvent = utils.getVideojsEventName(event) + if (!callback) { + player.off(videojsEvent); + return; + } + + const eventHandler = callbackToHandler[event];// callbackStorage.getCallback(event, callback); + if (eventHandler) { + player.off(videojsEvent, eventHandler); + } + } + + function destroy() { + if (!player) { + return; + } + player.remove(); + player = null; + } + + return { + init, + getId, + getOrtbVideo, + getOrtbContent, + setAdTagUrl, + onEvent, + offEvent, + destroy + }; + + function setupPlayer(config) { + const setupConfig = utils.getSetupConfig(config); + player = vjs(divId, setupConfig, onReady); + } + + function onReady() { + try { + setupAds(); + } catch (e) { + triggerSetupFailure(-5, e.message); + return; + } + triggerSetupComplete(); + } + + // TODO: consider supporting https://www.npmjs.com/package/videojs-vast-vpaid as well + function setupAds() { + if (!player.ima) { + throw new Error(setupFailMessage + ': ima plugin is missing'); + } + + if (typeof player.ima !== 'function') { + // when player.ima is already instantiated, it is an object. Early abort if already instantiated. + return; + } + + const adConfig = utils.getAdConfig(config); + player.ima(adConfig); + } + + function triggerSetupFailure(errorCode, msg, sourceError) { + const payload = { + divId, + playerVersion, + type: SETUP_FAILED, + errorCode, + errorMessage: msg, + sourceError: sourceError + }; + setupFailedCallbacks.forEach(setupFailedCallback => setupFailedCallback(SETUP_FAILED, payload)); + setupFailedCallbacks = []; + } + + function triggerSetupComplete() { + playerIsSetup = true; + const payload = { + divId, + playerVersion, + type: SETUP_COMPLETE, + }; + + setupCompleteCallbacks.forEach(callback => callback(SETUP_COMPLETE, payload)); + setupCompleteCallbacks = []; + + isMuted = player.muted(); + + setupFailedEventHandlers.forEach(eventHandler => player.off('error', eventHandler)); + setupFailedEventHandlers = []; + } +} + +export const utils = { + getSetupConfig: function (config) { + if (!config) { + return; + } + + const params = config.params || {}; + const videojsConfig = params.vendorConfig || {}; + + if (videojsConfig.autostart === undefined && config.autostart !== undefined) { + videojsConfig.autostart = config.autostart + } + + if (videojsConfig.muted === undefined && config.mute !== undefined) { + videojsConfig.muted = config.mute; + } + + return videojsConfig; + }, + + getAdConfig: function (config) { + const params = config && config.params; + if (!params) { + return {}; + } + + return params.adPluginConfig || {}; // TODO: add adPluginConfig to spec + }, + + getPositionCode: function({left, top, width, height}) { + const bottom = window.innerHeight - top - height; + const right = window.innerWidth - left - width; + + if (left < 0 || right < 0 || top < 0) { + return AD_POSITION.UNKNOWN; + } + + return bottom >= 0 ? AD_POSITION.ABOVE_THE_FOLD : AD_POSITION.BELOW_THE_FOLD; + }, + + getVideojsEventName: function(eventName) { + switch (eventName) { + case SETUP_COMPLETE: + return 'ready'; + case SETUP_FAILED: + return 'error'; + case DESTROYED: + return 'dispose'; + case AD_REQUEST: + return 'ads-request'; + case AD_LOADED: + return 'loaded' + case AD_STARTED: + return 'start'; + case AD_IMPRESSION: + return 'impression'; + case AD_PLAY: + return 'resume' + case AD_PAUSE: + return PAUSE; + case AD_TIME: + return 'adProgress'; + case AD_CLICK: + return 'click'; + case AD_COMPLETE: + return COMPLETE; + case AD_SKIPPED: + return 'skip'; + case AD_ERROR: + return 'adserror'; + case CONTENT_LOADED: + return 'loadstart'; + case PLAY: + return PLAY + 'ing'; + case PLAYBACK_REQUEST: + return PLAY; + case SEEK_START: + return 'seeking'; + case SEEK_END: + return 'seeked'; + case TIME: + return TIME + 'update'; + case VOLUME: + return VOLUME + 'change'; + case MUTE: + return MUTE + 'change'; + case PLAYER_RESIZE: + return 'playerresize'; + case FULLSCREEN: + return FULLSCREEN + 'change'; + case COMPLETE: + return 'ended'; + default: + return eventName; + } + /* + The following video.js events might map to an event in our spec + 'loadstart', + 'progress', buffer load ? + 'suspend', + 'abort', + 'error', + 'emptied', + 'stalled', + 'loadedmetadata', meta + 'loadeddata', meta + 'canplay', + 'canplaythrough', + 'waiting', buffer? + 'durationchange', meta-duration + 'ratechange', + */ + }, + + getMedia: function(player) { + const playlistItem = this.getCurrentPlaylistItem(player); + if (playlistItem) { + return playlistItem.sources[0]; + } + + return player.getMedia(); + }, + + getValidMediaUrl: function(mediaSrc, playerSrc, eventTargetSrc) { + return this.getMediaUrl(mediaSrc) || this.getMediaUrl(playerSrc) || this.getMediaUrl(eventTargetSrc); + }, + + getMediaUrl: function(source) { + if (!source) { + return; + } + + if (Array.isArray(source) && source.length) { + return this.parseSource(source[0]); + } + + return this.parseSource(source) + }, + + parseSource: function (source) { + const type = typeof source; + if (type === 'string') { + return source; + } else if (type === 'object') { + return source.src; + } + }, + + getPlaylistCount: function (player) { + const playlist = player.playlist; // has playlist plugin + if (!playlist) { + return 1; + } + return playlist.lastIndex && playlist.lastIndex() + 1; + }, + + getCurrentPlaylistIndex: function (player) { + const playlist = player.playlist; // has playlist plugin + if (!playlist) { + return 0; + } + return playlist.currentIndex && playlist.currentIndex(); + }, + + getCurrentPlaylistItem: function(player) { + const playlist = player.playlist; // has playlist plugin + if (!playlist) { + return; + } + + const currentIndex = this.getCurrentPlaylistIndex(player); + if (!currentIndex) { + return + } + + const item = playlist()[currentIndex]; + return item; + } +}; + +const videojsSubmoduleFactory = function (config) { + const adState = adStateFactory(); + const timeState = timeStateFactory(); + const callbackStorage = null; + // videojs factory is stored to window by default + const vjs = window.videojs; + return VideojsProvider(config, vjs, adState, timeState, callbackStorage, utils); +} + +videojsSubmoduleFactory.vendorCode = VIDEO_JS_VENDOR; +submodule('video', videojsSubmoduleFactory); +export default videojsSubmoduleFactory; + +// STATE + +/** + * @returns {State} + */ +export function adStateFactory() { + const adState = Object.assign({}, stateFactory()); + + function updateForEvent(event) { + if (!event) { + return; + } + + const skippable = event.skippable; + // TODO: possibly can check traffickingParameters to determine if winning bid is passed + const updates = { + adId: event.adId, + adServer: event.adSystem, + advertiserName: event.advertiserName, + redirectUrl: event.clickThroughUrl, + creativeId: event.creativeId || event.creativeAdId, + dealId: event.dealId, + adDescription: event.description, + linear: event.linear, + creativeUrl: event.mediaUrl, + adTitle: event.title, + universalAdId: event.universalAdIdValue, + creativeType: event.contentType, + wrapperAdIds: event.adWrapperIds, + skip: skippable ? 1 : 0, + // missing fields: + // loadTime + // advertiserId - TODO: does this even exist ? If not, remove from spec + // vastVersion + // adCategories + // campaignId + // waterfallIndex + // waterfallCount + // skipmin + // adTagUrl - for now, only has request ad tag + // adPlacementType + }; + + const adPodInfo = event.adPodInfo; + if (adPodInfo && adPodInfo.podIndex > -1) { + updates.adPodCount = adPodInfo.totalAds; + updates.adPodIndex = adPodInfo.adPosition - 1; // Per IMA docs, adPosition is 1 based. + } + + if (adPodInfo && adPodInfo.timeOffset) { + switch (adPodInfo.timeOffset) { + case -1: + updates.offset = 'post'; + break + + case 0: + // TODO: Defaults to 0 if this ad is not part of a pod, or the pod is not part of an ad playlist. - need to check if loaded dynamically and pass last content time update + updates.offset = 'pre'; + break + + default: + updates.offset = '' + adPodInfo.timeOffset; + } + } + + if (skippable) { + updates.skipafter = event.skipTimeOffset; + } + + this.updateState(updates); + } + + adState.updateForEvent = updateForEvent; + + return adState; +} + +export function timeStateFactory() { + const timeState = Object.assign({}, stateFactory()); + + function updateForTimeEvent(event) { + const { currentTime, duration } = event; + this.updateState({ + time: currentTime, + duration, + playbackMode: getPlaybackMode(duration) + }); + } + + timeState.updateForTimeEvent = updateForTimeEvent; + + function getPlaybackMode(duration) { + if (duration > 0) { + return PLAYBACK_MODE.VOD; + } else if (duration < 0) { + return PLAYBACK_MODE.DVR; + } + + return PLAYBACK_MODE.LIVE; + } + + return timeState; +} diff --git a/modules/videojsVideoProvider.md b/modules/videojsVideoProvider.md new file mode 100644 index 00000000000..70f4daa64e1 --- /dev/null +++ b/modules/videojsVideoProvider.md @@ -0,0 +1,17 @@ +# Overview + +Module Name: Video.js Video Provider +Module Type: Video Submodule +Video Player: video.js +Player website: https://videojs.com/ +Maintainer: Prebid Video Task Force + +# Description + +Video provider to connect the Prebid Video Module to video.js. + +# Requirements + +- Your page must include a build of video.js. For instructions see https://videojs.com/getting-started . +- Your video.js instance must include the Google IMA plugin. + - The Google IMA plugin must be accessible publicly in order for the Video.js Video Provider to reference it. diff --git a/package-lock.json b/package-lock.json index ffc179f2914..daa59e6ad12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.21.0-pre", + "version": "7.23.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -96,6 +96,10 @@ "through2": "^4.0.2", "url": "^0.11.0", "url-parse": "^1.0.5", + "video.js": "^7.17.0", + "videojs-contrib-ads": "^6.9.0", + "videojs-ima": "^1.11.0", + "videojs-playlist": "^5.0.0", "webdriverio": "^7.6.1", "webpack": "^5.70.0", "webpack-bundle-analyzer": "^4.5.0", @@ -1673,6 +1677,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -1790,6 +1806,33 @@ "xtend": "~4.0.1" } }, + "node_modules/@hapi/boom": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", + "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "dev": true, + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/cryptiles": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", + "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, "node_modules/@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -2301,6 +2344,12 @@ "@types/node": "*" } }, + "node_modules/@types/linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", + "dev": true + }, "node_modules/@types/lodash": { "version": "4.14.179", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz", @@ -2334,6 +2383,16 @@ "@types/lodash": "*" } }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, "node_modules/@types/mdast": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", @@ -2501,6 +2560,55 @@ "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, + "node_modules/@videojs/http-streaming": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.2.tgz", + "integrity": "sha512-K1raSfO/pq5r8iUas3OSYni0kXOj91n8ealIpV02khghzGv9LQ6O3YUqYd/eAhJ1HIrmZWOnrYpK/P+mhUExXQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "3.0.5", + "aes-decrypter": "3.1.3", + "global": "^4.4.0", + "m3u8-parser": "4.7.1", + "mpd-parser": "0.21.1", + "mux.js": "6.0.1", + "video.js": "^6 || ^7" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + }, + "peerDependencies": { + "video.js": "^6 || ^7" + } + }, + "node_modules/@videojs/vhs-utils": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz", + "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "global": "^4.4.0", + "url-toolkit": "^2.2.1" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, + "node_modules/@videojs/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-7J361GiN1tXpm+gd0xz2QWr3xNWBE+rytvo8J3KuggFaLg+U37gZQ2BuPLcnkfGffy2e+ozY70RHC8jt7zjA6Q==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "global": "~4.4.0", + "is-function": "^1.0.1" + } + }, "node_modules/@vue/compiler-core": { "version": "3.2.38", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.38.tgz", @@ -3195,6 +3303,18 @@ "node": ">=8" } }, + "node_modules/@wdio/mocha-framework/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@wdio/mocha-framework/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -3606,6 +3726,15 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@xmldom/xmldom": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz", + "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -3657,6 +3786,47 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dev": true, + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adm-zip": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.2.1.tgz", + "integrity": "sha512-J2LiZpRxcLsJm2IwoekNa6COwzEZnMwCJ3vxz0UCw2NYUH2WFi7svuDrVccq5KpBGmzGUgFa0L0FwEmKmu/rzQ==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-decrypter": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz", + "integrity": "sha512-VkG9g4BbhMBy+N5/XodDeV6F02chEk9IpgRTq/0bS80y4dzy79VH2Gtms02VXomf3HmyRe3yyJYkJ990ns+d6A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^3.0.5", + "global": "^4.4.0", + "pkcs7": "^1.0.4" + } + }, "node_modules/agent-base": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", @@ -3687,7 +3857,6 @@ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true, - "optional": true, "engines": { "node": ">=0.4.2" } @@ -3958,6 +4127,15 @@ "node": ">=0.10.0" } }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -4089,6 +4267,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -4098,6 +4282,24 @@ "safer-buffer": "~2.1.0" } }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, "node_modules/assert": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", @@ -4146,6 +4348,27 @@ "node": ">=8" } }, + "node_modules/astw": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", + "integrity": "sha512-E/4z//dvN0lfr8zAx8hXeQ8o3nRoQaL/wqI7fAALEvh/40mnyUxfFB9MwyDHYKVDtS3cp3Pow5s96djZR5lkWw==", + "dev": true, + "dependencies": { + "acorn": "^4.0.3" + } + }, + "node_modules/astw/node_modules/acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -4760,6 +4983,12 @@ "node": ">=0.10.0" } }, + "node_modules/Base64": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz", + "integrity": "sha512-reGEWshDmTDQDsCec/HduOO9Wyj6yMOupMfhIf3ugN1TDlK2NQW4DDJSqNNtp380SNcvRfXtO8HSCQot0d0SMw==", + "dev": true + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -4816,6 +5045,69 @@ "tweetnacl": "^0.14.3" } }, + "node_modules/beefy": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/beefy/-/beefy-1.1.0.tgz", + "integrity": "sha512-olZqTbw6gnofdbG98uAKvG6O/AjV6WGuPsKpYF41VQK39sUYvulm86RssD1K/iVNkkSJ8cuYeheJ8Nk2gz16wA==", + "dev": true, + "dependencies": { + "chokidar": "0.8.1", + "colors": "~0.6.0-1", + "ignorepatterns": "1.0.1", + "mime": "~1.2.9", + "nopt": "~2.1.1", + "open": "0.0.3", + "portfinder": "~0.2.1", + "response-stream": "0.0.0", + "script-injector": "~0.1.0", + "sse-stream": "0.0.4", + "through": "~2.2.0" + }, + "bin": { + "beefy": "bin/beefy" + } + }, + "node_modules/beefy/node_modules/chokidar": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-0.8.1.tgz", + "integrity": "sha512-Bl/CteHnM5g3eKGPMkraZQW7Yzk2Gu87eE3jdaMfCNJP79sVa54M5KHStr3WtJl4vVoVSndVDws6IFLTmMa3Lw==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "dev": true, + "hasInstallScript": true + }, + "node_modules/beefy/node_modules/colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/beefy/node_modules/mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", + "dev": true + }, + "node_modules/beefy/node_modules/nopt": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.1.2.tgz", + "integrity": "sha512-x8vXm7BZ2jE1Txrxh/hO74HTuYZQEbo8edoRcANgdZ4+PCV+pbjd/xdummkmjjC7LU5EjPzlu8zEq/oxWylnKA==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/beefy/node_modules/through": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", + "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", + "dev": true + }, "node_modules/beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", @@ -4918,6 +5210,12 @@ "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", "dev": true }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, "node_modules/body": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", @@ -4988,6 +5286,20 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, + "node_modules/boom": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", + "integrity": "sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, + "optional": true, + "dependencies": { + "hoek": "0.9.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5010,12 +5322,581 @@ "node": ">=8" } }, + "node_modules/brfs": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-0.0.9.tgz", + "integrity": "sha512-5bjo0XG6pPGTFJsS4rtvP1vvwLp3UstdF062l10RKcfG60+izXak0DFcfQwMtBQNGlFm588mM2WvD02hJErVYg==", + "dev": true, + "dependencies": { + "escodegen": "0.0.17", + "falafel": "~0.1.6", + "through": "~2.2.0" + }, + "bin": { + "brfs": "bin/cmd.js" + } + }, + "node_modules/brfs/node_modules/escodegen": { + "version": "0.0.17", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-0.0.17.tgz", + "integrity": "sha512-muX87X0L2dvVJ4ZPKAJLQlcyg2qhl6ps8Ow8vOAcuoFIrZLtXNMGfjnD19LSTrZ1SBHQsI+tvD8YlsJqHhfXrw==", + "dev": true, + "dependencies": { + "esprima": "~1.0.2", + "estraverse": "~0.0.4" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.4.0" + }, + "optionalDependencies": { + "source-map": ">= 0.1.2" + } + }, + "node_modules/brfs/node_modules/esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/brfs/node_modules/estraverse": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-0.0.4.tgz", + "integrity": "sha512-21DfBCsFJGb3HZr0vEBH1Wk1tGSbbzA8I/xtSSoy/pRtupHv0OgBmObcNGXM3ec6/pOXTOOUYY9/5bfluzz0sw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/brfs/node_modules/through": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", + "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", + "dev": true + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "node_modules/browser-pack": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-3.2.0.tgz", + "integrity": "sha512-BHla5EbbxjNyLMFUMamVjeTY+q1QwHbrYNXlWOkw71QcBqAQF7maJyNh3OI/V0d5YyNdMYD6tiPhJB9ukBo99Q==", + "dev": true, + "dependencies": { + "combine-source-map": "~0.3.0", + "concat-stream": "~1.4.1", + "defined": "~0.0.0", + "JSONStream": "~0.8.4", + "through2": "~0.5.1", + "umd": "^2.1.0" + }, + "bin": { + "browser-pack": "bin/cmd.js" + } + }, + "node_modules/browser-pack/node_modules/concat-stream": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", + "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.9", + "typedarray": "~0.0.5" + } + }, + "node_modules/browser-pack/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/browser-pack/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/browser-pack/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/browser-pack/node_modules/through2": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", + "integrity": "sha512-zexCrAOTbjkBCXGyozn7hhS3aEaqdrc59mAD2E3dKYzV1vFuEGQ1hEDJN2oQMQFwy4he2zyLqPZV+AlfS8ZWJA==", + "dev": true, + "dependencies": { + "readable-stream": "~1.0.17", + "xtend": "~3.0.0" + } + }, + "node_modules/browser-pack/node_modules/through2/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/browser-pack/node_modules/xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/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, + "dependencies": { + "resolve": "1.1.7" + } + }, + "node_modules/browser-resolve/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, "node_modules/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 }, + "node_modules/browserify": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-8.1.3.tgz", + "integrity": "sha512-0KKOkCQXCvP64qm73CtESE92pVnB5MkjA2W/Tmf+S4uPHVY4/SeCwO7wdr4mkke5ySoVyMqsOcMa5zo6uh9c9A==", + "dev": true, + "dependencies": { + "assert": "~1.3.0", + "browser-pack": "^3.2.0", + "browser-resolve": "^1.3.0", + "browserify-zlib": "~0.1.2", + "buffer": "^3.0.0", + "builtins": "~0.0.3", + "commondir": "0.0.1", + "concat-stream": "~1.4.1", + "console-browserify": "^1.1.0", + "constants-browserify": "~0.0.1", + "crypto-browserify": "^3.0.0", + "deep-equal": "~0.2.1", + "defined": "~0.0.0", + "deps-sort": "^1.3.5", + "domain-browser": "~1.1.0", + "duplexer2": "~0.0.2", + "events": "~1.0.0", + "glob": "^4.0.5", + "http-browserify": "^1.4.0", + "https-browserify": "~0.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^6.2.0", + "isarray": "0.0.1", + "JSONStream": "~0.8.3", + "labeled-stream-splicer": "^1.0.0", + "module-deps": "^3.6.3", + "os-browserify": "~0.1.1", + "parents": "^1.0.1", + "path-browserify": "~0.0.0", + "process": "^0.10.0", + "punycode": "~1.2.3", + "querystring-es3": "~0.2.0", + "readable-stream": "^1.0.33-1", + "resolve": "~0.7.1", + "shallow-copy": "0.0.1", + "shasum": "^1.0.0", + "shell-quote": "~0.0.1", + "stream-browserify": "^1.0.0", + "string_decoder": "~0.10.0", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^1.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "~0.0.0", + "umd": "~2.1.0", + "url": "~0.10.1", + "util": "~0.10.1", + "vm-browserify": "~0.0.1", + "xtend": "^3.0.0" + }, + "bin": { + "browserify": "bin/cmd.js" + } + }, + "node_modules/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, + "dependencies": { + "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" + } + }, + "node_modules/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, + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/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, + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dev": true, + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/browserify-sign/node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify-sign/node_modules/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, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==", + "dev": true, + "dependencies": { + "pako": "~0.2.0" + } + }, + "node_modules/browserify/node_modules/assert": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.3.0.tgz", + "integrity": "sha512-5aKcpD+XnHpZ7EGxsuo6uoILNh0rvm0Ypa17GlkrF2CNSPhvdgi3ft9XsL2ajdVOI2I3xuGZnHvlXAeqTZYvXg==", + "dev": true, + "dependencies": { + "util": "0.10.3" + } + }, + "node_modules/browserify/node_modules/assert/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", + "dev": true + }, + "node_modules/browserify/node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", + "dev": true, + "dependencies": { + "inherits": "2.0.1" + } + }, + "node_modules/browserify/node_modules/base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/browserify/node_modules/buffer": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.2.tgz", + "integrity": "sha512-c3M77NkHJxS0zx/ErxXhDLr1v3y2MDXPeTJPvLNOaIYJ4ymHBUFQ9EXzt9HYuqAJllMoNb/EZ8hIiulnQFAUuQ==", + "dev": true, + "dependencies": { + "base64-js": "0.0.8", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/browserify/node_modules/buffer/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/browserify/node_modules/commondir": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-0.0.1.tgz", + "integrity": "sha512-Ghe1LmLv3G3c0XJYu+c88MCRIPqWQ67qaqKY1KvuN4uPAjfUj+y4hvcpZ2kCPrjpRNyklW4dpAZZ8a7vOh50tg==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/browserify/node_modules/concat-stream": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", + "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.9", + "typedarray": "~0.0.5" + } + }, + "node_modules/browserify/node_modules/deep-equal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", + "integrity": "sha512-FXgye2Jr6oEk01S7gmSrHrPEQ1ontR7wwl+nYiZ8h4SXlHVm0DYda74BIPcHz2s2qPz4+375IcAz1vsWLwddgQ==", + "dev": true + }, + "node_modules/browserify/node_modules/duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "dev": true, + "dependencies": { + "readable-stream": "~1.1.9" + } + }, + "node_modules/browserify/node_modules/events": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/events/-/events-1.0.2.tgz", + "integrity": "sha512-XK19KwlDJo8XsceooxNDK1pObtcT44+Xte6V/jQc4a+fHq1qEouThyyX2ePmS0hS8RcCulmRxzg+T8jiLKAFFQ==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/browserify/node_modules/glob": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", + "integrity": "sha512-I0rTWUKSZKxPSIAIaqhSXTM/DiII6wame+rEC3cFA5Lqmr9YmdL7z6Hj9+bdWtTvoY1Su4/OiMLmb37Y7JzvJQ==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^2.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/browserify/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/browserify/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/browserify/node_modules/minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dev": true, + "dependencies": { + "brace-expansion": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/browserify/node_modules/process": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", + "integrity": "sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/browserify/node_modules/punycode": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.2.4.tgz", + "integrity": "sha512-h/vscxLPvI2l7k/0dFUKZ5I5TgMCJ/Pl+J6rw77PDuQM6UApf/GaRVkjv/YSm2k+fbp7Yw8dxsoe29DolT7h7w==", + "dev": true, + "engines": [ + "node", + "rhino" + ] + }, + "node_modules/browserify/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/browserify/node_modules/resolve": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.7.4.tgz", + "integrity": "sha512-zxmAcifDjKxmUbk7chQdKhDSn8ml08g+MYyU37xhEXBp+N81cfbYsm4e0Gn9jtLbAvbR8w8Ox09xqUZtPuCoeA==", + "dev": true + }, + "node_modules/browserify/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/browserify/node_modules/through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "dependencies": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/browserify/node_modules/through2/node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/browserify/node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dev": true, + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/browserify/node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", + "dev": true + }, + "node_modules/browserify/node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/browserify/node_modules/xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, "node_modules/browserslist": { "version": "4.21.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", @@ -5202,6 +6083,12 @@ "node": ">=0.10" } }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, "node_modules/buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", @@ -5211,6 +6098,12 @@ "node": ">=0.2.0" } }, + "node_modules/builtins": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-0.0.7.tgz", + "integrity": "sha512-T8uCGKc0/2aLVt6omt8JxDRBoWEMkku+wFesxnhxnt4NygVZG99zqxo7ciK8eebszceKamGoUiLdkXCgGQyrQw==", + "dev": true + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -5315,43 +6208,6 @@ "node": ">=4" } }, - "node_modules/cac/node_modules/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, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cac/node_modules/path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -5364,29 +6220,6 @@ "node": ">=0.10.0" } }, - "node_modules/cac/node_modules/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, - "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cac/node_modules/read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -5426,18 +6259,6 @@ "node": ">=0.10.0" } }, - "node_modules/cac/node_modules/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, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cac/node_modules/supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -5521,6 +6342,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -5539,6 +6369,34 @@ "node": ">=6" } }, + "node_modules/camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==", + "dev": true, + "dependencies": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/can-autoplay": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/can-autoplay/-/can-autoplay-3.0.2.tgz", + "integrity": "sha512-Ih6wc7yJB4TylS/mLyAW0Dj5Nh3Gftq/g966TcxgvpNCOzlbqTs85srAq7mwIspo4w8gnLCVVGroyCHfh6l9aA==", + "dev": true + }, "node_modules/caniuse-lite": { "version": "1.0.30001390", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001390.tgz", @@ -5560,6 +6418,18 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -5749,6 +6619,16 @@ "node": ">=6.0" } }, + "node_modules/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, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -5999,6 +6879,35 @@ "node": ">=0.1.90" } }, + "node_modules/combine-source-map": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.3.0.tgz", + "integrity": "sha512-HRKa6g9SC1xd6ifto8ay6SxvyHaaQ50/8NO1ZONXx2hsIF9t/52qXa7Eeivaf5KFOSowK7Nm8TkIL/VC4khdBA==", + "dev": true, + "dependencies": { + "convert-source-map": "~0.3.0", + "inline-source-map": "~0.3.0", + "source-map": "~0.1.31" + } + }, + "node_modules/combine-source-map/node_modules/convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha512-+4nRk0k3oEpwUB7/CalD7xE2z4VmtEnnq0GO2IPTkrooTrAhEsWvuLF5iWP1dXrwluki/azwXV1ve7gtYuPldg==", + "dev": true + }, + "node_modules/combine-source-map/node_modules/source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "dev": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -6021,6 +6930,15 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/commander": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.0.0.tgz", + "integrity": "sha512-qebjpyeaA/nJ4w3EO2cV2++/zEkccPnjWogzA2rff+Lk8ILI75vULeTmyd4wPxWdKwtP3J+G39IXVZadh0UHyw==", + "dev": true, + "engines": { + "node": ">= 0.6.x" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -6101,6 +7019,16 @@ "node": ">=0.10.0" } }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "node_modules/connect": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", @@ -6140,6 +7068,18 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "node_modules/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 + }, + "node_modules/constants-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-0.0.1.tgz", + "integrity": "sha512-FL+diDS9AKR5BAA2M+GNk8lnH64tRE3zepTG9hucxc7o04LgCRhkQZhF7u/OKHZT8LLRT+sZEi9qFzXUchq9pA==", + "dev": true + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -6348,6 +7288,49 @@ "node": ">= 6" } }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/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, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/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, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "node_modules/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", @@ -6376,6 +7359,42 @@ "node": ">= 8" } }, + "node_modules/cryptiles": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", + "integrity": "sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, + "optional": true, + "dependencies": { + "boom": "0.4.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/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, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + } + }, "node_modules/crypto-js": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", @@ -6413,6 +7432,37 @@ "node": ">=0.10.0" } }, + "node_modules/cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==", + "dev": true, + "dependencies": { + "through": "X.X.X" + } + }, + "node_modules/ctype": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", + "integrity": "sha512-T6CEkoSV4q50zW3TlTHMbzy1E5+zlnNcY+yb7tWVYlTwPhx9LpnfAkd4wecpWknDyptp4k97LUZeInlf6jdzBg==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", + "dev": true, + "dependencies": { + "array-find-index": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -6502,6 +7552,15 @@ "ms": "^2.1.1" } }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -6685,6 +7744,12 @@ "node": ">=0.10.0" } }, + "node_modules/defined": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", + "integrity": "sha512-zpqiCT8bODLu3QSmLLic8xJnYWBFjOSu/fBCm189oAiTtPq/PSanNACKZDS7kgSyCJY7P+IcODzlIogBK/9RBg==", + "dev": true + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -6702,6 +7767,80 @@ "node": ">= 0.6" } }, + "node_modules/deps-sort": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-1.3.9.tgz", + "integrity": "sha512-aEnmQuu/Hf5h8akL8QshYWzk9MVBg/JYMyNq/Lz68i69nR17tunjP6o/AC6Tn48c8ayzG6aeKs6OoFOtVCtvrQ==", + "dev": true, + "dependencies": { + "JSONStream": "^1.0.3", + "shasum": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^1.0.0" + }, + "bin": { + "deps-sort": "bin/cmd.js" + } + }, + "node_modules/deps-sort/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/deps-sort/node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/deps-sort/node_modules/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, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/deps-sort/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/deps-sort/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/deps-sort/node_modules/through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "dependencies": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -6711,6 +7850,16 @@ "node": ">=6" } }, + "node_modules/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, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -6746,6 +7895,37 @@ "node": ">=0.10.0" } }, + "node_modules/detective": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", + "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "dev": true, + "dependencies": { + "acorn": "^5.2.1", + "defined": "^1.0.0" + } + }, + "node_modules/detective/node_modules/acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detective/node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/devtools": { "version": "7.16.16", "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", @@ -6804,6 +7984,16 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "node_modules/di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", @@ -6828,6 +8018,23 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/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, + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -7042,6 +8249,22 @@ "void-elements": "^2.0.0" } }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "node_modules/domain-browser": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha512-fJ5MoHxe69h3E4/lJtFRhcWwLb04bhIBSfvCEMS1YDH+/9yEZTqBHTSTgch8nCP5tE5k2gdQEjodUqJzy7qJ9Q==", + "dev": true, + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, "node_modules/dset": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz", @@ -7176,6 +8399,27 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.243.tgz", "integrity": "sha512-BgLD2gBX43OSXwlT01oYRRD5NIB4n3okTRxkzEAC6G0SZG4TTlyrWMjbOo0fajCwqwpRtMHXQNMjtRN6qpNtfw==" }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -7272,6 +8516,15 @@ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", "dev": true }, + "node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/errno": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", @@ -7379,9 +8632,9 @@ } }, "node_modules/es5-ext": { - "version": "0.10.57", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.57.tgz", - "integrity": "sha512-L7cCNoPwTkAp7IBHxrKLsh7NKiVFkcdxlP9vbVw9QUvb7gF0Mz9bEBN0WY9xqdTjGF907EMT/iG013vnbqwu1Q==", + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -7413,6 +8666,20 @@ "es6-symbol": "^3.1.1" } }, + "node_modules/es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", + "dev": true, + "dependencies": { + "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" + } + }, "node_modules/es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", @@ -7434,6 +8701,29 @@ "es6-promise": "^4.0.3" } }, + "node_modules/es6-set": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", + "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "es6-iterator": "~2.0.3", + "es6-symbol": "^3.1.3", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-set/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, "node_modules/es6-symbol": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", @@ -7572,6 +8862,21 @@ "node": ">= 0.8.0" } }, + "node_modules/escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==", + "dev": true, + "dependencies": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/eslint": { "version": "7.32.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", @@ -7972,6 +9277,18 @@ "node": ">=10" } }, + "node_modules/eslint/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8032,6 +9349,19 @@ "node": ">=0.10.0" } }, + "node_modules/esprima-fb": { + "version": "10001.1.0-dev-harmony-fb", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-10001.1.0-dev-harmony-fb.tgz", + "integrity": "sha512-z2dx3A/ZGNamsDjJS4FZPXnpoRCEkQXqouKBCOaJifyx4HkEVoSQ3YWFX18Scut1Aq9gnctzLWcWJgKkL0xNQw==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", @@ -8083,6 +9413,15 @@ "node": ">=4.0" } }, + "node_modules/estraverse-fb": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.2.tgz", + "integrity": "sha512-wp3lfRrWy5EQD9TqesuYM1SKVP4ERT0cUatb4e8Vznf4K5IOpREhuyXZxGj3a9s9mvX5vGZKNHA4R9D4kp9Q9A==", + "dev": true, + "peerDependencies": { + "estraverse": "*" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -8152,6 +9491,16 @@ "node": ">=0.8.x" } }, + "node_modules/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, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, "node_modules/execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -8651,6 +10000,31 @@ "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", "dev": true }, + "node_modules/falafel": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-0.1.6.tgz", + "integrity": "sha512-r1s3VwKzm6PB35MZmnfZoF6NTgSKRxf8How2lBsrDq81OsYXb/2fR8ysfURHCTlFpqJDQVA88iB70wFrFRYDsA==", + "dev": true, + "dependencies": { + "esprima": "~1.0.2" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/falafel/node_modules/esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", @@ -8782,6 +10156,58 @@ "node": ">=10" } }, + "node_modules/fileset": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", + "integrity": "sha512-aK3PFyHSwWsBJCarRxMRIXSGamfroi9ehG8f4e5A2n5nSlEVHe8y44jNTIN4+HdZSpK3FNV0EdihH1iDWTdnGg==", + "dev": true, + "dependencies": { + "glob": "5.x", + "minimatch": "2.x" + } + }, + "node_modules/fileset/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fileset/node_modules/minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dev": true, + "dependencies": { + "brace-expansion": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA==", + "dev": true, + "dependencies": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -9025,6 +10451,23 @@ "node": ">= 0.12" } }, + "node_modules/formatio": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", + "integrity": "sha512-cPh7is6k3d8tIUh+pnXXuAbD/uhSXGgqLPw0UrYpv5lfdJ+MMMSjx40JNpqP7Top9Nt25YomWEiRmkHbOvkCaA==", + "deprecated": "This package is unmaintained. Use @sinonjs/formatio instead", + "dev": true, + "dependencies": { + "samsam": "~1.1" + } + }, + "node_modules/formatio/node_modules/samsam": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.3.tgz", + "integrity": "sha512-t9rCPskf50hZ53eH8Z+cSWD4LfJBac+8vSSuzi1Y2HzygyXxtAl0BaR3hr6iI6A+nFQbkmJNC/brQLNEeVnrmg==", + "deprecated": "This package has been deprecated in favour of @sinonjs/samsam", + "dev": true + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -9239,6 +10682,24 @@ "node": ">= 4.0.0" } }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dev": true, + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", + "dev": true, + "dependencies": { + "is-property": "^1.0.0" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -9299,6 +10760,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -9345,6 +10815,79 @@ "assert-plus": "^1.0.0" } }, + "node_modules/gh-got": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-1.1.0.tgz", + "integrity": "sha512-jo4rP5ugI6fZGjS0vmvHlM8P7EBA39p8to4r2i+LqYXxeg4M8qnPXiKaetDfH0YLXkO9Hfsa2mKIjMsGJwcdGQ==", + "dev": true, + "dependencies": { + "got": "^3.2.0", + "object-assign": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gh-got/node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/gh-got/node_modules/got": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/got/-/got-3.3.1.tgz", + "integrity": "sha512-7chPlc0pWHjvq7B6dEEXz4GphoDupOvBSSl6AwRsAJX7GPTZ+bturaZiIigX4Dp6KrAP67nvzuKkNc0SLA0DKg==", + "dev": true, + "dependencies": { + "duplexify": "^3.2.0", + "infinity-agent": "^2.0.0", + "is-redirect": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "nested-error-stacks": "^1.0.0", + "object-assign": "^3.0.0", + "prepend-http": "^1.0.0", + "read-all-stream": "^3.0.0", + "timed-out": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gh-got/node_modules/got/node_modules/object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gh-got/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gh-got/node_modules/object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha512-CdsOUYIh5wIiozhJ3rLQgmUTgcyzFwZZrqhkKhODMoGtPKM+wt0h0CNIoauJWMsS9822EdzPsF/6mb4nLvPN5g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/git-up": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/git-up/-/git-up-6.0.0.tgz", @@ -9370,6 +10913,18 @@ "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==", "dev": true }, + "node_modules/github-url-from-git": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-url-from-git/-/github-url-from-git-1.5.0.tgz", + "integrity": "sha512-WWOec4aRI7YAykQ9+BHmzjyNlkfJFG8QLXnDTsLz/kZefq7qkzdfo4p6fkYYMIq1aj+gZcQs/1HQhQh3DPPxlQ==", + "dev": true + }, + "node_modules/github-url-from-username-repo": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/github-url-from-username-repo/-/github-url-from-username-repo-1.0.2.tgz", + "integrity": "sha512-Tj8CQqRoFVTglGdQ8FQmfq8gOOoOYZX7tnOKP8jq8Hdz2OTDhxvtlkLAbrqMYZ7X/YdaYQoUG1IBWxISBfqZ+Q==", + "dev": true + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -9660,6 +11215,16 @@ "node": ">=0.10.0" } }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, "node_modules/global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", @@ -10048,34 +11613,6 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/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, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-cli/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/gulp-cli/node_modules/path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -10088,29 +11625,6 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/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, - "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-cli/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/gulp-cli/node_modules/read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -10170,18 +11684,6 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/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, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/gulp-cli/node_modules/which-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", @@ -10433,6 +11935,9 @@ "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" } }, "node_modules/gulp-eslint/node_modules/cross-spawn/node_modules/semver": { @@ -10806,6 +12311,18 @@ "node": ">=6" } }, + "node_modules/gulp-eslint/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gulp-eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -11228,17 +12745,6 @@ "lodash._root": "^3.0.0" } }, - "node_modules/gulp-util/node_modules/lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "dependencies": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, "node_modules/gulp-util/node_modules/lodash.template": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", @@ -11457,6 +12963,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha512-kaNz5OTAYYmt646Hkqw50/qyxP2vFnTVu5AQ1Zmk22Kk5+4Qx6BpO8+u7IKsML5fOsFk0ZT0AcCJNYwcvaLBvw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -11549,6 +13064,64 @@ "node": ">=0.10.0" } }, + "node_modules/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, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash-base/node_modules/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, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "node_modules/hast-util-is-element": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz", @@ -11608,6 +13181,23 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hawk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", + "integrity": "sha512-am8sVA2bCJIw8fuuVcKvmmNnGFUGW8spTkVtj2fXTEZVkfN42bwFZFtDem57eFi+NSxurJB8EQ7Jd3uCHLn8Vw==", + "deprecated": "This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "dev": true, + "optional": true, + "dependencies": { + "boom": "0.4.x", + "cryptiles": "0.2.x", + "hoek": "0.9.x", + "sntp": "0.2.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -11626,6 +13216,28 @@ "node": ">=12.0.0" } }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hoek": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -11663,6 +13275,147 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/html-select": { + "version": "2.3.24", + "resolved": "https://registry.npmjs.org/html-select/-/html-select-2.3.24.tgz", + "integrity": "sha512-kQ+YZoVQ8Aux6bUqMVc0iufcZOv03+xYZ4J5v2beT5wkNrW/e2roZ8pnU4LunVOVBGFkbodFKR0TvuMkTdyrJQ==", + "dev": true, + "dependencies": { + "cssauron": "^1.1.0", + "duplexer2": "~0.0.2", + "inherits": "^2.0.1", + "minimist": "~0.0.8", + "readable-stream": "^1.0.27-1", + "split": "~0.3.0", + "stream-splicer": "^1.2.0", + "through2": "^1.0.0" + }, + "bin": { + "html-select": "bin/cmd.js" + } + }, + "node_modules/html-select/node_modules/duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "dev": true, + "dependencies": { + "readable-stream": "~1.1.9" + } + }, + "node_modules/html-select/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/html-select/node_modules/minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", + "dev": true + }, + "node_modules/html-select/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/html-select/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/html-select/node_modules/through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "dependencies": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/html-tokenize": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-1.2.5.tgz", + "integrity": "sha512-7sCme3w9Hiv/kfL6sO6ePTGAV5fY6P7WDZyOs0zfXXU8vsS1ps1CQfGe0J1yuAdcCnOJ9h66RLYX/e9Cife8yw==", + "dev": true, + "dependencies": { + "inherits": "~2.0.1", + "minimist": "~0.0.8", + "readable-stream": "~1.0.27-1", + "through2": "~0.4.1" + }, + "bin": { + "html-tokenize": "bin/cmd.js" + } + }, + "node_modules/html-tokenize/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/html-tokenize/node_modules/minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", + "dev": true + }, + "node_modules/html-tokenize/node_modules/object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==", + "dev": true + }, + "node_modules/html-tokenize/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/html-tokenize/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/html-tokenize/node_modules/through2": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", + "integrity": "sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==", + "dev": true, + "dependencies": { + "readable-stream": "~1.0.17", + "xtend": "~2.1.1" + } + }, + "node_modules/html-tokenize/node_modules/xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", + "dev": true, + "dependencies": { + "object-keys": "~0.4.0" + }, + "engines": { + "node": ">=0.4" + } + }, "node_modules/html-void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", @@ -11673,6 +13426,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/http-browserify": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz", + "integrity": "sha512-Irf/LJXmE3cBzU1eaR4+NEX6bmVLqt1wkmDiA7kBwH7zmb0D8kBAXsDmQ88hhj/qv9iEZKlyGx/hrMcFi8sOHw==", + "dev": true, + "dependencies": { + "Base64": "~0.2.0", + "inherits": "~2.0.1" + } + }, "node_modules/http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -11742,6 +13505,12 @@ "node": ">=10.19.0" } }, + "node_modules/https-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", + "integrity": "sha512-EjDQFbgJr1vDD/175UJeSX3ncQ3+RUnCL5NkthQGHvF4VNHlzTy8ifJfTqz47qiPRqaFH58+CbuG3x51WuB1XQ==", + "dev": true + }, "node_modules/https-proxy-agent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", @@ -11795,6 +13564,15 @@ "node": ">= 4" } }, + "node_modules/ignorepatterns": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignorepatterns/-/ignorepatterns-1.0.1.tgz", + "integrity": "sha512-9bm+Wivwyocr88go3y04hpX3qdFs6EgsxrjjpcI9C2GAqxcWYVMJaS9h9KL8ftJk1xP/8NzPxfHk6K1X7p0CRQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -11829,6 +13607,36 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==", + "dev": true, + "dependencies": { + "repeating": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==", + "dev": true + }, + "node_modules/individual": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz", + "integrity": "sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g==", + "dev": true + }, + "node_modules/infinity-agent": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz", + "integrity": "sha512-CnfUJe5o2S9aAQWXGMhDZI4UL39MAJV3guOTfHHIdos4tuVHkl1j/J+1XLQn+CLIvqcpgQR/p+xXYXzcrhCe5w==", + "dev": true + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -11850,6 +13658,27 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "node_modules/inline-source-map": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.3.1.tgz", + "integrity": "sha512-RNlldBXZ7BBcVm3HjXIXiwKxih1lnuKbzeLBRDSB/qaqk8/g4JEZBjxpBQMhqEthQyGv7ycu8r/8PKGgBdIqrA==", + "dev": true, + "dependencies": { + "source-map": "~0.3.0" + } + }, + "node_modules/inline-source-map/node_modules/source-map": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz", + "integrity": "sha512-jz8leTIGS8+qJywWiO9mKza0hJxexdeIYXhDHw9avTQcXSNAGk3hiiRMpmI2Qf9dOrZDrDpgH9VNefzuacWC9A==", + "dev": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/inquirer": { "version": "8.1.5", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", @@ -11936,6 +13765,143 @@ "node": ">=8" } }, + "node_modules/insert-module-globals": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-6.6.3.tgz", + "integrity": "sha512-ryk8hTKUZCc300SPOOwx30WhE5oRUssPDVlIoO8vtoMNBy5HGeesVRl3HF7ra4ll42T0IdnwD9XR9svh6+RRhg==", + "dev": true, + "dependencies": { + "combine-source-map": "~0.6.1", + "concat-stream": "~1.4.1", + "is-buffer": "^1.1.0", + "JSONStream": "^1.0.3", + "lexical-scope": "^1.2.0", + "process": "~0.11.0", + "through2": "^1.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "insert-module-globals": "bin/cmd.js" + } + }, + "node_modules/insert-module-globals/node_modules/combine-source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.6.1.tgz", + "integrity": "sha512-XKRNtuZRlVDTuSGKsfZpXYz80y0XDbYS4a+FzafTgmYHy/ckruFBx7Nd6WaQnFHVI3O6IseWVdXUvZutMpjSkQ==", + "dev": true, + "dependencies": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.5.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.4.2" + } + }, + "node_modules/insert-module-globals/node_modules/concat-stream": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", + "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.9", + "typedarray": "~0.0.5" + } + }, + "node_modules/insert-module-globals/node_modules/convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", + "dev": true + }, + "node_modules/insert-module-globals/node_modules/inline-source-map": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.5.0.tgz", + "integrity": "sha512-2WtHG0qX9OH9TVcxsLVfq3Tzr+qtL6PtWgoh0XAAKe4KkdA/57Q+OGJuRJHA4mZ2OZnkJ/ZAaXf9krLB12/nIg==", + "dev": true, + "dependencies": { + "source-map": "~0.4.0" + } + }, + "node_modules/insert-module-globals/node_modules/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 + }, + "node_modules/insert-module-globals/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/insert-module-globals/node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/insert-module-globals/node_modules/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, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/insert-module-globals/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/insert-module-globals/node_modules/source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha512-Y8nIfcb1s/7DcobUz1yOO1GSp7gyL+D9zLHDehT7iRESqGSxjJ448Sg7rvfgsRJCnKLdSl11uGf0s9X80cH0/A==", + "dev": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/insert-module-globals/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/insert-module-globals/node_modules/through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "dependencies": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, "node_modules/internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -12255,6 +14221,12 @@ "node": ">=8" } }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, "node_modules/is-generator-function": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", @@ -12300,6 +14272,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-my-ip-valid": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", + "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", + "dev": true + }, + "node_modules/is-my-json-valid": { + "version": "2.20.6", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", + "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", + "dev": true, + "dependencies": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^5.0.0", + "xtend": "^4.0.0" + } + }, "node_modules/is-nan": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", @@ -12382,6 +14373,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -12409,6 +14409,21 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "dev": true + }, + "node_modules/is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -12847,6 +14862,39 @@ "url": "https://bevry.me/fund" } }, + "node_modules/jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha512-mkk3vzUHFjzKjpCXeu+IjXeZD+QOTjUUdubgmHtHTDwvAO2ZTkMTTVrapts5CWz3JvJryh/4KWZpjeZrCepZ3A==", + "deprecated": "Jade has been renamed to pug, please install the latest version of pug instead of jade", + "dev": true, + "dependencies": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "bin": { + "jade": "bin/jade" + } + }, + "node_modules/jade/node_modules/commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha512-0fLycpl1UMTGX257hRsu/arL/cUbcvQM4zMKwvLvzXtfdezIV4yotPS2dYtknF+NmEfWSoCEF6+hj9XLm/6hEw==", + "dev": true, + "engines": { + "node": ">= 0.4.x" + } + }, + "node_modules/jade/node_modules/mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/jake": { "version": "10.8.5", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", @@ -13201,6 +15249,12 @@ "node": ">= 10.13.0" } }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -13232,12 +15286,77 @@ "node": ">=4" } }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, + "node_modules/jsdoc": { + "version": "3.6.11", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.11.tgz", + "integrity": "sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.9.4", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "taffydb": "2.6.2", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdoc/node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/jsdoc/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jsdoc/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -13267,6 +15386,15 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, + "node_modules/json-parse-helpfulerror": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", + "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==", + "dev": true, + "dependencies": { + "jju": "^1.1.0" + } + }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -13279,6 +15407,15 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/json-stable-stringify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", + "integrity": "sha512-nKtD/Qxm7tWdZqJoldEC7fF0S41v0mWbeaXG3637stOWfyGxTgWTYE2wtfKmjzpvxv2MA2xzxsXOIiwUpkX6Qw==", + "dev": true, + "dependencies": { + "jsonify": "~0.0.0" + } + }, "node_modules/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", @@ -13314,6 +15451,65 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jsonlint": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.3.tgz", + "integrity": "sha512-jMVTMzP+7gU/IyC6hvKyWpUU8tmTkK5b3BPNuMI9U8Sit+YAWLlZwB6Y6YrdCxfg2kNz05p3XY3Bmm4m26Nv3A==", + "dev": true, + "dependencies": { + "JSV": "^4.0.x", + "nomnom": "^1.5.x" + }, + "bin": { + "jsonlint": "lib/cli.js" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/jsonparse": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz", + "integrity": "sha512-fw7Q/8gFR8iSekUi9I+HqWIap6mywuoe7hQIg3buTVjuZgALKj4HAmm0X6f+TaL4c9NJbvyFQdaI2ppr5p6dnQ==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/JSONStream": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz", + "integrity": "sha512-l0NN3IcqrZfZBJp7JWDJIHsnPV7yzJWqsYxQzL8Fwdx1BmEMjLuvtYkv+P9pbvpyfP75/f4MeDZhWNU4is32uA==", + "dev": true, + "dependencies": { + "jsonparse": "0.0.5", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "index.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -13329,6 +15525,15 @@ "node": ">=0.6.0" } }, + "node_modules/JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha512-ZJ6wx9xaKJ3yFUhq5/sk82PJMuUyLk277I8mQeyDgCTjGdjWJIvPfaU5LIXaMuaN2UO1X3kZH4+lgphublZUHw==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/just-clone": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", @@ -13768,6 +15973,18 @@ "node": ">=10" } }, + "node_modules/kew": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.1.7.tgz", + "integrity": "sha512-TQRJfHoVm4f2exuRqjcpURhzGcC4GEIPyiLquo4mBfz0JgsVg19VeyTmKp6RKSOIhHQ6F4SgEhsnUlBduGV9Yw==", + "dev": true + }, + "node_modules/keycode": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.1.tgz", + "integrity": "sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==", + "dev": true + }, "node_modules/keyv": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.1.1.tgz", @@ -13786,6 +16003,15 @@ "node": ">=0.10.0" } }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -13817,6 +16043,23 @@ "url": "https://github.com/sindresorhus/ky?sponsor=1" } }, + "node_modules/labeled-stream-splicer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-1.0.2.tgz", + "integrity": "sha512-3KBjPRnXrYC5h2jEf/d6hO7Lcl+38QzRVTOyHA2sFzZVMYwsUFuejlrOMwAjmz13hVBr9ruDS1RwE4YEz8P58w==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "isarray": "~0.0.1", + "stream-splicer": "^1.1.0" + } + }, + "node_modules/labeled-stream-splicer/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, "node_modules/last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", @@ -13888,6 +16131,15 @@ "node": ">= 0.8.0" } }, + "node_modules/lexical-scope": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", + "integrity": "sha512-ntJ8IcBCuKwudML7vAuT/L0aIMU0+9vO25K4CjLPYgzf1NZ0bAhJJBZrvkO+oUGgKcbdkH8UZdRsaEg+wULLRw==", + "dev": true, + "dependencies": { + "astw": "^2.0.0" + } + }, "node_modules/liftoff": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", @@ -13950,6 +16202,15 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -13973,6 +16234,55 @@ "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", "dev": true }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -14001,12 +16311,87 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash._arraycopy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", + "integrity": "sha512-RHShTDnPKP7aWxlvXKiDT6IX2jCs6YZLCtNhOru/OX2Q/tzX295vVBK5oX1ECtN+2r86S0Ogy8ykP1sgCZAN0A==", + "dev": true + }, + "node_modules/lodash._arrayeach": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", + "integrity": "sha512-Mn7HidOVcl3mkQtbPsuKR0Fj0N6Q6DQB77CtYncZcJc0bx5qv2q4Gl6a0LC1AN+GSxpnBDNnK3CKEm9XNA4zqQ==", + "dev": true + }, + "node_modules/lodash._arraymap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz", + "integrity": "sha512-IhRssF2bzQoFQ2Q5H1O52HuJY+OtcHDZekEhaMJ6RkUF+gpLlAsizSRsKp3Ho555ANRk69DFp5b4LOlym4S0bw==", + "dev": true + }, + "node_modules/lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==", + "dev": true, + "dependencies": { + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "node_modules/lodash._baseclone": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", + "integrity": "sha512-1K0dntf2dFQ5my0WoGKkduewR6+pTNaqX03kvs45y7G5bzl4B3kTR4hDfJIc2aCQDeLyQHhS280tc814m1QC1Q==", + "dev": true, + "dependencies": { + "lodash._arraycopy": "^3.0.0", + "lodash._arrayeach": "^3.0.0", + "lodash._baseassign": "^3.0.0", + "lodash._basefor": "^3.0.0", + "lodash.isarray": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, "node_modules/lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", "dev": true }, + "node_modules/lodash._basedifference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz", + "integrity": "sha512-4BcJlOv36b3v+kHdJWcgsDi96ns8neNLuDtbzzjW3+eh3XhFVmFPH2tu6GJK2e5eRYMQ8izHU35iAyNjRyDtCQ==", + "dev": true, + "dependencies": { + "lodash._baseindexof": "^3.0.0", + "lodash._cacheindexof": "^3.0.0", + "lodash._createcache": "^3.0.0" + } + }, + "node_modules/lodash._baseflatten": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz", + "integrity": "sha512-fESngZd+X4k+GbTxdMutf8ohQa0s3sJEHIcwtu4/LsIQ2JTDzdRxDCMQjW+ezzwRitLmHnacVVmosCbxifefbw==", + "dev": true, + "dependencies": { + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "node_modules/lodash._basefor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", + "integrity": "sha512-6bc3b8grkpMgDcVJv9JYZAk/mHgcqMljzm7OsbmcE2FGUMmmLQTPHlh/dFqR8LA0GQ7z4K67JSotVKu5058v1A==", + "dev": true + }, + "node_modules/lodash._baseindexof": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", + "integrity": "sha512-bSYo8Pc/f0qAkr8fPJydpJjtrHiSynYfYBjtANIgXv5xEf1WlTC63dIDlgu0s9dmTvzRu1+JJTxcIAHe+sH0FQ==", + "dev": true + }, "node_modules/lodash._basetostring": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", @@ -14019,6 +16404,38 @@ "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", "dev": true }, + "node_modules/lodash._bindcallback": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==", + "dev": true + }, + "node_modules/lodash._cacheindexof": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", + "integrity": "sha512-S8dUjWr7SUT/X6TBIQ/OYoCHo1Stu1ZRy6uMUSKqzFnZp5G5RyQizSm6kvxD2Ewyy6AVfMg4AToeZzKfF99T5w==", + "dev": true + }, + "node_modules/lodash._createassigner": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", + "integrity": "sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==", + "dev": true, + "dependencies": { + "lodash._bindcallback": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash.restparam": "^3.0.0" + } + }, + "node_modules/lodash._createcache": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", + "integrity": "sha512-ev5SP+iFpZOugyab/DEUQxUeZP5qyciVTlgQ1f4Vlw7VUcCD8fVnyIqVUEIaoFH9zjAqdgi69KiofzvVmda/ZQ==", + "dev": true, + "dependencies": { + "lodash._getnative": "^3.0.0" + } + }, "node_modules/lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", @@ -14031,6 +16448,22 @@ "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", "dev": true }, + "node_modules/lodash._pickbyarray": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz", + "integrity": "sha512-tHzBIfgugzI7HV0y8MJS1z/ryWDh8NyD6AV+so9vlplRnhD4qBuwoyDt7g241ad3F43YDFghCN+R3iaFd4Azvw==", + "dev": true + }, + "node_modules/lodash._pickbycallback": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz", + "integrity": "sha512-DVP27YmN0lB+j/Tgd/+gtxfmW/XihgWpQpHptBuwyp2fD9zEBRwwcnw6Qej16LUV8LRFuTqyoc0i6ON97d/C5w==", + "dev": true, + "dependencies": { + "lodash._basefor": "^3.0.0", + "lodash.keysin": "^3.0.0" + } + }, "node_modules/lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", @@ -14126,12 +16559,61 @@ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", "dev": true }, + "node_modules/lodash.istypedarray": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz", + "integrity": "sha512-lGWJ6N8AA3KSv+ZZxlTdn4f6A7kMfpJboeyvbFdE7IU9YAgweODqmOgdUHOA+c6lVWeVLysdaxciFXi+foVsWw==", + "dev": true + }, + "node_modules/lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", + "dev": true, + "dependencies": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "node_modules/lodash.keysin": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", + "integrity": "sha512-YDB/5xkL3fBKFMDaC+cfGV00pbiJ6XoJIfRmBhv7aR6wWtbCW6IzkiWnTfkiHTF6ALD7ff83dAtB3OEaSoyQPg==", + "dev": true, + "dependencies": { + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "node_modules/lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==", + "dev": true + }, "node_modules/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 }, + "node_modules/lodash.omit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-3.1.0.tgz", + "integrity": "sha512-vC3fSzZDmPlwk+kCGYMQyUpPeRBgmOK/WrhmjlWVUjEch35gQR3iRbCV9rL7KgMHVeVhnq7A+TRrPvzvg67y9w==", + "dev": true, + "dependencies": { + "lodash._arraymap": "^3.0.0", + "lodash._basedifference": "^3.0.0", + "lodash._baseflatten": "^3.0.0", + "lodash._bindcallback": "^3.0.0", + "lodash._pickbyarray": "^3.0.0", + "lodash._pickbycallback": "^3.0.0", + "lodash.keysin": "^3.0.0", + "lodash.restparam": "^3.0.0" + } + }, "node_modules/lodash.pickby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", @@ -14169,6 +16651,16 @@ "lodash._reinterpolate": "^3.0.0" } }, + "node_modules/lodash.toplainobject": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz", + "integrity": "sha512-wMI0Ju1bvSmnBS3EcRRH/3zDnZOPpDtMtNDzbbNMKuTrEpALsf+sPyMeogmv63Y11qZQO7H1xFzohIEGRMjPYA==", + "dev": true, + "dependencies": { + "lodash._basecopy": "^3.0.0", + "lodash.keysin": "^3.0.0" + } + }, "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", @@ -14271,6 +16763,19 @@ "loose-envify": "cli.js" } }, + "node_modules/loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==", + "dev": true, + "dependencies": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/loupe": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", @@ -14310,6 +16815,17 @@ "es5-ext": "~0.10.2" } }, + "node_modules/m3u8-parser": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.7.1.tgz", + "integrity": "sha512-pbrQwiMiq+MmI9bl7UjtPT3AK603PV9bogNlr83uC+X9IoxqL5E4k7kU7fMQ0dpRgxgeSMygqUa0IMLQNXLBNA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^3.0.5", + "global": "^4.4.0" + } + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -14365,6 +16881,15 @@ "node": ">=0.10.0" } }, + "node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/map-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", @@ -14383,6 +16908,38 @@ "node": ">=0.10.0" } }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.5", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.5.tgz", + "integrity": "sha512-PI1qEHHkTNWT+X6Ip9w+paonfIQ+QZP9sCeMYi47oqhH+EsW8CrJ8J7CzV19QVOj6il8ATGbK2nTECj22ZHGvQ==", + "dev": true, + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/markdown-table": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.2.tgz", @@ -14393,6 +16950,58 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/markdownlint": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.0.6.tgz", + "integrity": "sha512-2jxomIcTY+HWnrMWv7Q/T93d7yp4RXNGkoQXWq5II1TgyQj5pFDoB7HZSCX57ATk9zZTb1++jwXR3uHn6AKmew==", + "dev": true, + "dependencies": { + "markdown-it": "^4.2.2" + } + }, + "node_modules/markdownlint/node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "node_modules/markdownlint/node_modules/linkify-it": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz", + "integrity": "sha512-eGHwtlABkp1NOJSiKUNqBf3SYAS5jPHtvRXPAgNaQwTqmkTahjtiLH9NtxdR5IOPhNvwNMN/diswSfZKzUkhGg==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/markdownlint/node_modules/markdown-it": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz", + "integrity": "sha512-Rl8dHHeLuAh3E72OPY0tY7CLvlxgHiLhlshIYswAAabAg4YDBLa6e/LTgNkkxBO2K61ESzoquPQFMw/iMrT1PA==", + "dev": true, + "dependencies": { + "argparse": "~1.0.2", + "entities": "~1.1.1", + "linkify-it": "~1.2.0", + "mdurl": "~1.0.0", + "uc.micro": "^1.0.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/marked": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz", + "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/marky": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.4.tgz", @@ -14441,6 +17050,17 @@ "node": ">=0.10.0" } }, + "node_modules/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, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/mdast-util-definitions": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", @@ -14783,6 +17403,79 @@ "node": ">=4.3.0 <5.0.0 || >=5.10" } }, + "node_modules/meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -15482,6 +18175,25 @@ "node": ">=0.10.0" } }, + "node_modules/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, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, "node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -15531,6 +18243,27 @@ "node": ">=4" } }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/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 + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -15581,12 +18314,11 @@ "dev": true }, "node_modules/mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", + "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", "dev": true, "dependencies": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", @@ -15621,6 +18353,111 @@ "url": "https://opencollective.com/mochajs" } }, + "node_modules/mocha-phantomjs": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/mocha-phantomjs/-/mocha-phantomjs-3.6.0.tgz", + "integrity": "sha512-siI6m2uw3Xyjruz9eEP8JTVHOtnOxdmnEqXM0IrOt3Nbw4oPJw6u8Q6MG6hqnbH9fJ3i60F3bYlmSEbgwuNsQw==", + "dev": true, + "dependencies": { + "commander": "~2.0.0", + "mocha": "~1.20.1" + }, + "bin": { + "mocha-phantomjs": "bin/mocha-phantomjs" + }, + "peerDependencies": { + "phantomjs": "1.9.1 - 1.9.7-15" + } + }, + "node_modules/mocha-phantomjs/node_modules/diff": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.7.tgz", + "integrity": "sha512-0bTLzyr1S59cPsgAD/lR+ivvHTbgPb+k/mUR6WGqma1J6QDU+kUegI8uQFuH/cMUNK7JGN3Tk1Y5Jf2MO85WrA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/mocha-phantomjs/node_modules/glob": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", + "integrity": "sha512-WPaLsMHD1lYEqAmIQI6VOJSPwuBdGShDWnj1yUo0vQqEO809R8W3LM9OVU13CnnDhyv/EiNwOtxEW74SmrzS6w==", + "dev": true, + "dependencies": { + "graceful-fs": "~2.0.0", + "inherits": "2", + "minimatch": "~0.2.11" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha-phantomjs/node_modules/graceful-fs": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", + "integrity": "sha512-hcj/NTUWv+C3MbqrVb9F+aH6lvTwEHJdx2foBxlrVq5h6zE8Bfu4pv4CAAqbDcZrw/9Ak5lsRXlY9Ao8/F0Tuw==", + "deprecated": "please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/mocha-phantomjs/node_modules/growl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz", + "integrity": "sha512-VWv7s1EI41AG2LiCr7uAuxWikLDN1SQOuEUc37d/P34NAIIYgkvWYngNw0d9d9iCrDFL0SYCE9UQpxhIjjtuLg==", + "dev": true + }, + "node_modules/mocha-phantomjs/node_modules/lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==", + "dev": true + }, + "node_modules/mocha-phantomjs/node_modules/minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha512-zZ+Jy8lVWlvqqeM8iZB7w7KmQkoJn8djM585z88rywrEbzoqawVa9FR5p2hwD+y74nfuKOjmNvi9gtWJNLqHvA==", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dev": true, + "dependencies": { + "lru-cache": "2", + "sigmund": "~1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha-phantomjs/node_modules/mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true + }, + "node_modules/mocha-phantomjs/node_modules/mocha": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.20.1.tgz", + "integrity": "sha512-25Nq3BuIYCy80uEix+hBlZcr/gnLzpcYqfsaPAxZm2qbMFmed8I3nP8N05KagK4BTkGYUvsRJ47istvRqFO8fw==", + "deprecated": "Mocha v1.x is no longer supported.", + "dev": true, + "dependencies": { + "commander": "2.0.0", + "debug": "*", + "diff": "1.0.7", + "glob": "3.2.3", + "growl": "1.7.x", + "jade": "0.26.3", + "mkdirp": "0.3.5" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 0.4.x" + } + }, "node_modules/mocha/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -15860,6 +18697,18 @@ "node": ">=8" } }, + "node_modules/mocha/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mocha/node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", @@ -15893,6 +18742,131 @@ "node": ">=10" } }, + "node_modules/module-deps": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-3.9.1.tgz", + "integrity": "sha512-EbWWlSGaCVidEsLsSzkY6l/jm0IcGDSQ8tGwtjM8joTrxqxP0om02Px9Np8D7FMZ/vZFdsOGbio+WqkKQxYuTA==", + "dev": true, + "dependencies": { + "browser-resolve": "^1.7.0", + "concat-stream": "~1.4.5", + "defined": "^1.0.0", + "detective": "^4.0.0", + "duplexer2": "0.0.2", + "inherits": "^2.0.1", + "JSONStream": "^1.0.3", + "parents": "^1.0.0", + "readable-stream": "^1.1.13", + "resolve": "^1.1.3", + "stream-combiner2": "~1.0.0", + "subarg": "^1.0.0", + "through2": "^1.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "module-deps": "bin/cmd.js" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/module-deps/node_modules/concat-stream": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", + "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.9", + "typedarray": "~0.0.5" + } + }, + "node_modules/module-deps/node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/module-deps/node_modules/duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "dev": true, + "dependencies": { + "readable-stream": "~1.1.9" + } + }, + "node_modules/module-deps/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/module-deps/node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/module-deps/node_modules/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, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/module-deps/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/module-deps/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/module-deps/node_modules/through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "dependencies": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha512-pEk4ECWQXV6z2zjhRZUongnLJNUeGQJ3w6OQ5ctGwD+i5o93qjRQUk2Rt6VdNeu3sEP0AB4LcfvdebpxBRVr4g==", + "dev": true + }, "node_modules/morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -15933,6 +18907,21 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "node_modules/mpd-parser": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.21.1.tgz", + "integrity": "sha512-BxlSXWbKE1n7eyEPBnTEkrzhS3PdmkkKdM1pgKbPnPOH0WFZIc0sPOWi7m0Uo3Wd2a4Or8Qf4ZbS7+ASqQ49fw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^3.0.5", + "@xmldom/xmldom": "^0.7.2", + "global": "^4.4.0" + }, + "bin": { + "mpd-to-m3u8-json": "bin/parse.js" + } + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -16013,6 +19002,23 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/mux.js": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-6.0.1.tgz", + "integrity": "sha512-22CHb59rH8pWGcPGW5Og7JngJ9s+z4XuSlYvnxhLuc58cA1WqGDQPzuG8I+sPm1/p0CdgpzVTaKW408k5DNn8w==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.11.2", + "global": "^4.4.0" + }, + "bin": { + "muxjs-transmux": "bin/transmux.js" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, "node_modules/nan": { "version": "2.15.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", @@ -16064,6 +19070,14 @@ "node": ">=0.10.0" } }, + "node_modules/natives": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", + "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", + "deprecated": "This module relies on Node.js's internals and will break at some point. Do not use it, and update to graceful-fs@4.x.", + "dev": true, + "optional": true + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -16093,6 +19107,15 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/nested-error-stacks": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", + "integrity": "sha512-o32anp9JA7oezPOFSfG2BBXSdHepOm5FpJvwxHWDtfJ3Bg3xdi68S6ijPlEOfUg6quxZWyvJM+8fHk1yMDKspA==", + "dev": true, + "dependencies": { + "inherits": "~2.0.1" + } + }, "node_modules/next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -16177,6 +19200,68 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, + "node_modules/node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==", + "deprecated": "Use uuid module instead", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha512-5s0JxqhDx9/rksG2BTMVN1enjWSvPidpoSgViZU4ZXULyTe+7jxcCRLB6f42Z0l1xYJpleCBtSyY6Lwg3uu5CQ==", + "deprecated": "Package no longer supported. Contact support@npmjs.com for more info.", + "dev": true, + "dependencies": { + "chalk": "~0.4.0", + "underscore": "~1.6.0" + } + }, + "node_modules/nomnom/node_modules/ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha512-3iF4FIKdxaVYT3JqQuY3Wat/T2t7TRbbQ94Fu50ZUCbLy4TFbTzr90NOHQodQkNqmeEGCw8WbeP78WNi6SKYUA==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/nomnom/node_modules/chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha512-sQfYDlfv2DGVtjdoQqxS0cEZDroyG8h6TamA6rvxwlrU5BaSLDx9xhatBYl2pxZ7gmpNaPFVwBtdGdu5rQ+tYQ==", + "dev": true, + "dependencies": { + "ansi-styles": "~1.0.0", + "has-color": "~0.1.0", + "strip-ansi": "~0.1.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/nomnom/node_modules/strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha512-behete+3uqxecWlDAm5lmskaSaISA+ThQ4oNNBDTBJt0x2ppR6IPqfZNuj6BLaLJ/Sji4TPZlcRyOis8wXQTLg==", + "dev": true, + "bin": { + "strip-ansi": "cli.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/nomnom/node_modules/underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ==", + "dev": true + }, "node_modules/nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -16189,6 +19274,12 @@ "nopt": "bin/nopt.js" } }, + "node_modules/nopt-usage": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/nopt-usage/-/nopt-usage-0.1.0.tgz", + "integrity": "sha512-Tg2sISrWBbSsCRqpEMmdxn3KZfacrd0N2NYpZQIq0MHxGHMjwzYlxeB9pVIom/g7CBK28atDUQsTlOfG0wOsNA==", + "dev": true + }, "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -16243,6 +19334,43 @@ "node": ">= 0.10" } }, + "node_modules/npm-license": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/npm-license/-/npm-license-0.2.3.tgz", + "integrity": "sha512-Sm6zqTVReBGe1C5A3Vr7pqYFmawM3oF/MKhhk0LRAOZPEOygr96KkiJ5P0ZQMDP3F7HRW6zyy7gxIIos+6foww==", + "dev": true, + "dependencies": { + "mkdirp": "~0.5.0", + "nopt": "~3.0.1", + "nopt-usage": "^0.1.0", + "package-license": "~0.1.1", + "pkginfo": "^0.3.0", + "read-installed": "~3.1.3", + "treeify": "~1.0.1", + "underscore": "~1.4.4" + }, + "bin": { + "npm-license": "bin/npm-license" + } + }, + "node_modules/npm-license/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/npm-license/node_modules/underscore": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==", + "dev": true + }, "node_modules/npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -16264,6 +19392,73 @@ "node": ">=4" } }, + "node_modules/npmconf": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/npmconf/-/npmconf-0.0.24.tgz", + "integrity": "sha512-LX0bX+RmuBuEITg26i7+dx+d9cfYU+giB7eOiSkT5IwvuAzzIx02u4GXwSC3jsQMDMb/kXC57R8tybRSVYfbWw==", + "deprecated": "this package has been reintegrated into npm and is now out of date with respect to npm", + "dev": true, + "dependencies": { + "config-chain": "~1.1.1", + "inherits": "~1.0.0", + "ini": "~1.1.0", + "mkdirp": "~0.3.3", + "nopt": "2", + "once": "~1.1.1", + "osenv": "0.0.3", + "semver": "~1.1.0" + } + }, + "node_modules/npmconf/node_modules/inherits": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha512-Al67oatbRSo3RV5hRqIoln6Y5yMVbJSIn4jEJNL7VCImzq/kLr7vvb6sFRJXqr8rpHc/2kJOM+y0sPKN47VdzA==", + "dev": true + }, + "node_modules/npmconf/node_modules/ini": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.1.0.tgz", + "integrity": "sha512-B6L/jfyFRcG2dqKiHggWnfby52Iy07iabE4F6srQAr/OmVKBRE5uU+B5MQ+nQ7NiYnjz93gENh1GhqHzpDgHgA==", + "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/npmconf/node_modules/mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true + }, + "node_modules/npmconf/node_modules/nopt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz", + "integrity": "sha512-gIOTA/uJuhPwFqp+spY7VQ1satbnGlD+iQVZxI18K6hs8Evq4sX81Ml7BB5byP/LsbR2yBVtmvdEmhi7evJ6Aw==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/npmconf/node_modules/once": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/once/-/once-1.1.1.tgz", + "integrity": "sha512-frdJr++QKEg4+JylTX+NNLgSoO6M2pDNYOOXe4WGIYKKBADBI9nU3oa06y4D4FpAJ3obAsjExeBOnscYJB9Blw==", + "dev": true + }, + "node_modules/npmconf/node_modules/semver": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-1.1.4.tgz", + "integrity": "sha512-9causpLEkYDrfTz7cprleLz9dnlb0oKsKRHl33K92wJmXLhVc2dGlrQGJT/sjtLOAyuoQZl+ClI77+lnvzPSKg==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -16558,6 +19753,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/open/-/open-0.0.3.tgz", + "integrity": "sha512-Vm6nsJHcKV8kdOtHESAFAymOOf1VlKrttpwTqtLxvxRDIh8PSw4lWq5qk88QkAvNwnkv/1dNi2lvedhmam/ggw==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -16588,6 +19792,24 @@ "node": ">=4" } }, + "node_modules/optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", + "dev": true, + "dependencies": { + "wordwrap": "~0.0.2" + } + }, + "node_modules/optimist/node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -16714,6 +19936,12 @@ "readable-stream": "^2.0.1" } }, + "node_modules/os-browserify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz", + "integrity": "sha512-aZicJZccvxWOZ0Bja2eAch2L8RIJWBuRYmM8Gwl/JjNtRltH0Itcz4eH/ESyuIWfse8cc93ZCf0XrzhXK2HEDA==", + "dev": true + }, "node_modules/os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -16744,6 +19972,12 @@ "node": ">=0.10.0" } }, + "node_modules/osenv": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.0.3.tgz", + "integrity": "sha512-VBk1bfdaO4gh3OWO8LBuDY2alp0buL8YzQ6t13xyc8PQPrnUg5AgQvINQx3UkS4dom8UGCL597q4Y2+M4TPvmw==", + "dev": true + }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -16804,6 +20038,18 @@ "node": ">=4" } }, + "node_modules/package-license": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/package-license/-/package-license-0.1.2.tgz", + "integrity": "sha512-Q5zmx+M9ZJneMpYS6MlYL77gqeMYWuyErXMnQ/83WCztmYQD7Z0U9XGLvX9OKFFXwRj2NzdzlM0y9Jzcww2O1Q==", + "dev": true + }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -16816,6 +20062,28 @@ "node": ">=6" } }, + "node_modules/parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==", + "dev": true, + "dependencies": { + "path-platform": "~0.11.15" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", @@ -16913,6 +20181,12 @@ "node": ">=0.10.0" } }, + "node_modules/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 + }, "node_modules/path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", @@ -16937,6 +20211,12 @@ "node": ">=0.10.0" } }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -16951,6 +20231,15 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", @@ -16977,6 +20266,29 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -16995,6 +20307,22 @@ "through": "~2.3" } }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -17007,6 +20335,239 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "node_modules/phantomjs": { + "version": "1.9.7-15", + "resolved": "https://registry.npmjs.org/phantomjs/-/phantomjs-1.9.7-15.tgz", + "integrity": "sha512-s4PSN1L0iVwgv9ZkrSKcfojyPAtwGWhXxjn2p1P/ljuw3cx+FW3hKP00x247mIYbKeKSMylOd4euDQOMpUIAsg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "adm-zip": "0.2.1", + "kew": "~0.1.7", + "mkdirp": "0.3.5", + "ncp": "0.4.2", + "npmconf": "0.0.24", + "progress": "^1.1.5", + "request": "2.36.0", + "request-progress": "^0.3.1", + "rimraf": "~2.2.2", + "which": "~1.0.5" + }, + "bin": { + "phantomjs": "bin/phantomjs" + } + }, + "node_modules/phantomjs/node_modules/asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.9" + } + }, + "node_modules/phantomjs/node_modules/assert-plus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", + "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/phantomjs/node_modules/async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==", + "dev": true, + "optional": true + }, + "node_modules/phantomjs/node_modules/aws-sign2": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", + "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", + "dev": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/phantomjs/node_modules/combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", + "dev": true, + "optional": true, + "dependencies": { + "delayed-stream": "0.0.5" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/phantomjs/node_modules/delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/phantomjs/node_modules/forever-agent": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/phantomjs/node_modules/form-data": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", + "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", + "dev": true, + "optional": true, + "dependencies": { + "async": "~0.9.0", + "combined-stream": "~0.0.4", + "mime": "~1.2.11" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/phantomjs/node_modules/hawk": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.0.0.tgz", + "integrity": "sha512-Sg+VzrI7TjUomO0rjD6UXawsj50ykn5sB/xKNW/IenxzRVyw/wt9A2FLzYpGL/r0QG5hyXY8nLx/2m8UutoDcg==", + "deprecated": "This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "dev": true, + "optional": true, + "dependencies": { + "boom": "0.4.x", + "cryptiles": "0.2.x", + "hoek": "0.9.x", + "sntp": "0.2.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/phantomjs/node_modules/http-signature": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", + "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", + "dev": true, + "optional": true, + "dependencies": { + "asn1": "0.1.11", + "assert-plus": "^0.1.5", + "ctype": "0.5.3" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/phantomjs/node_modules/mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", + "dev": true + }, + "node_modules/phantomjs/node_modules/mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true + }, + "node_modules/phantomjs/node_modules/oauth-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", + "dev": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/phantomjs/node_modules/progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/phantomjs/node_modules/qs": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", + "integrity": "sha512-kN+yNdAf29Jgp+AYHUmC7X4QdJPR8czuMWLNLc0aRxkQ7tB3vJQEONKKT9ou/rW7EbqVec11srC9q9BiVbcnHA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/phantomjs/node_modules/request": { + "version": "2.36.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.36.0.tgz", + "integrity": "sha512-iVii/ruMH9i8k++HYYPqi+nb1Pbgz7UOTGbFEiyhl7uDN8PhyFV2lGJa8XLIUS5tyt5scERcLkwqvCNF84Vv2Q==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "dependencies": { + "forever-agent": "~0.5.0", + "json-stringify-safe": "~5.0.0", + "mime": "~1.2.9", + "node-uuid": "~1.4.0", + "qs": "~0.6.0" + }, + "optionalDependencies": { + "aws-sign2": "~0.5.0", + "form-data": "~0.1.0", + "hawk": "~1.0.0", + "http-signature": "~0.10.0", + "oauth-sign": "~0.3.0", + "tough-cookie": ">=0.12.0", + "tunnel-agent": "~0.4.0" + } + }, + "node_modules/phantomjs/node_modules/rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", + "dev": true, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/phantomjs/node_modules/tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", + "dev": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/phantomjs/node_modules/which": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", + "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", + "dev": true, + "bin": { + "which": "bin/which" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -17057,6 +20618,18 @@ "node": ">=0.10.0" } }, + "node_modules/pkcs7": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz", + "integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5" + }, + "bin": { + "pkcs7": "bin/cli.js" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -17139,6 +20712,15 @@ "node": ">=8" } }, + "node_modules/pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha512-yO5feByMzAp96LtP58wvPKSbaKAi/1C4kV9XpTctr6EepnP6F33RBNOiVrdz9BrPA98U2BMFsTNHo44TWcbQ2A==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", @@ -17166,6 +20748,28 @@ "node": ">=0.10.0" } }, + "node_modules/portfinder": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-0.2.1.tgz", + "integrity": "sha512-U7dHe7mfMMP5cIwbqBHh/likunxAEiBsQLiThUWjyeRK6/C3um2uk+VGiekUW8q3h+s793gdNfagCM3aaXMeOg==", + "dev": true, + "dependencies": { + "mkdirp": "0.0.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/portfinder/node_modules/mkdirp": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.0.7.tgz", + "integrity": "sha512-r4Ml2CH2Kl4B0+Lwq1SVru0vjMxdtR+UEb938WTQcsnU+EJz8dUV/HY0LTZh466nUSljia9cvqW3LZLWs3l8LQ==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -17209,6 +20813,15 @@ "node": ">= 0.8.0" } }, + "node_modules/prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", @@ -17280,6 +20893,15 @@ "node": ">= 0.6" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -17305,6 +20927,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "node_modules/protocols": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz", @@ -17329,6 +20957,23 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, + "node_modules/proxyquire": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-1.8.0.tgz", + "integrity": "sha512-mZZq4F50qaBkngvlf9paNfaSb5gtJ0mFPnBjda4NxCpXpMAaVfSLguRr9y2KXF6koOSBf4AanD2inuEQw3aCcA==", + "dev": true, + "dependencies": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.0", + "resolve": "~1.1.7" + } + }, + "node_modules/proxyquire/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -17362,6 +21007,26 @@ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "dependencies": { + "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" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -17535,6 +21200,15 @@ "node": ">=0.4.x" } }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -17562,6 +21236,16 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/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, + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -17590,6 +21274,121 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "node_modules/read-all-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", + "integrity": "sha512-DI1drPHbmBcUDWrJ7ull/F2Qb8HkwBncVx8/RpKYFSIACYaVRQReISYPdZz/mt1y1+qMCOrfReTopERmaxtP6w==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-installed": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-3.1.5.tgz", + "integrity": "sha512-XxD5VDz32T6rLCFfYElTif8/lkqcs9y51Gs2r30rAfT7LUGzJWaXLrwvn6fXkDsTzGcPr7Pj8CggOxwTxl/ozQ==", + "dev": true, + "dependencies": { + "debuglog": "^1.0.1", + "read-package-json": "1", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "optionalDependencies": { + "graceful-fs": "2 || 3" + } + }, + "node_modules/read-installed/node_modules/graceful-fs": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", + "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", + "dev": true, + "optional": true, + "dependencies": { + "natives": "^1.1.3" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/read-installed/node_modules/semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-package-json": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-1.3.3.tgz", + "integrity": "sha512-9bayCl9cbXy3AL0qXhLQ0vliEgpzUVeLegSOrde3ujTHy2W18UsJiMUXEWkjbBB4ZnJzZPVuo2vAW62j4gY7gg==", + "dev": true, + "dependencies": { + "glob": "^5.0.3", + "json-parse-helpfulerror": "^1.0.2", + "normalize-package-data": "^1.0.0" + }, + "optionalDependencies": { + "graceful-fs": "2 || 3" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/read-package-json/node_modules/graceful-fs": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", + "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", + "dev": true, + "optional": true, + "dependencies": { + "natives": "^1.1.3" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/read-package-json/node_modules/normalize-package-data": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-1.0.3.tgz", + "integrity": "sha512-pyPVJAzFiaioifPIsJBEoKJ9YcPHz7UhckZ7wqhBztLLCu6NozkIDrN+frzrCwjXtfunXfaMWIDtcDhnbO8fWA==", + "dev": true, + "dependencies": { + "github-url-from-git": "^1.3.0", + "github-url-from-username-repo": "^1.0.0", + "semver": "2 || 3 || 4" + } + }, + "node_modules/read-package-json/node_modules/semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/read-pkg": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", @@ -17794,6 +21593,39 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, + "node_modules/readable-wrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/readable-wrap/-/readable-wrap-1.0.0.tgz", + "integrity": "sha512-/8n0Mr10S+HGKFygQ42Z40JIXwafPH3A72pwmlNClThgsImV5LJJiCue5Je1asxwY082sYxq/+kTxH6nTn0w3g==", + "dev": true, + "dependencies": { + "readable-stream": "^1.1.13-1" + } + }, + "node_modules/readable-wrap/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/readable-wrap/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/readable-wrap/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, "node_modules/readdir-glob": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", @@ -17803,6 +21635,18 @@ "minimatch": "^3.0.4" } }, + "node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -17815,6 +21659,46 @@ "node": ">=8.10.0" } }, + "node_modules/readline2": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz", + "integrity": "sha512-qs8GGG+hLGMaDOGjd+mDglDoYcHDkjIY7z5RU0/ApsGT0qypyrWskNeemUqD+UxIXiZoMYT5aLwGp4ehoyZhIg==", + "dev": true, + "dependencies": { + "mute-stream": "0.0.4", + "strip-ansi": "^2.0.1" + } + }, + "node_modules/readline2/node_modules/ansi-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readline2/node_modules/mute-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz", + "integrity": "sha512-amvrY4m/7oZamehMoFi1tbwU/kXbVvRTGM2S7F+PZi3n51Jx+9AcSQ3EQsag3tR+hS2higfgOP/Kl8kri/X52A==", + "dev": true + }, + "node_modules/readline2/node_modules/strip-ansi": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", + "integrity": "sha512-2h8q2CP3EeOhDJ+jd932PRMpa3/pOJFGoF22J1U/DNbEK2gSW2DqeF46VjCXsSQXhC+k/l8/gaaRBQKL6hUPfQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^1.0.0" + }, + "bin": { + "strip-ansi": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -17851,6 +21735,19 @@ "node": "*" } }, + "node_modules/redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==", + "dev": true, + "dependencies": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -18216,6 +22113,15 @@ "node": ">= 6" } }, + "node_modules/request-progress": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-0.3.1.tgz", + "integrity": "sha512-+IAgzH8yWAEgHjOOQzYEqRm0BpNlE6xFgsziGMiTxxMhrkBcCOe9bNWH7bDR+XtHToUMgCZlDgLqjk6cAP/+Ig==", + "dev": true, + "dependencies": { + "throttleit": "~0.0.2" + } + }, "node_modules/request/node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", @@ -18249,6 +22155,15 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, + "node_modules/requizzle": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", + "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -18312,6 +22227,12 @@ "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, + "node_modules/response-stream": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/response-stream/-/response-stream-0.0.0.tgz", + "integrity": "sha512-tWH3QWqkXv7AgYRXidIhPKO1SqPix2E0gM3x/vxf60LHQHWNS8AVrB3RnYexPAoo5dOc0bGzDlUgtsBvV3CWLA==", + "dev": true + }, "node_modules/responselike": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", @@ -18358,12 +22279,34 @@ "node": ">=0.12" } }, + "node_modules/rewire": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/rewire/-/rewire-2.5.2.tgz", + "integrity": "sha512-9wOlgRHTOzUv5dQO2XD2qWob+7yi/QXh7SSwLJW5wMAkAdkYuaCtcPuLAXUTllK0MjSvtpxUqAWMuSrrdt9VNw==", + "dev": true + }, "node_modules/rfdc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", "dev": true }, + "node_modules/rfile": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rfile/-/rfile-1.0.0.tgz", + "integrity": "sha512-aNeTpY8g6DYmqPvakau22B0SipQTskO8FtYXzn8qg4X4bN9ExIH8VAhq/L9w7N8HvESYeSSwk3e4GmW+rLLAxQ==", + "dev": true, + "dependencies": { + "callsite": "~1.0.0", + "resolve": "~0.3.0" + } + }, + "node_modules/rfile/node_modules/resolve": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.3.1.tgz", + "integrity": "sha512-mxx/I/wLjxtryDBtrrb0ZNzaYERVWaHpJ0W0Arm8N4l8b+jiX/U5yKcsj0zQpF9UuKN1uz80EUTOudON6OPuaQ==", + "dev": true + }, "node_modules/rgb2hex": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.5.tgz", @@ -18385,6 +22328,54 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/ruglify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ruglify/-/ruglify-1.0.0.tgz", + "integrity": "sha512-XfRj1YJdm/gnZNvmpQ5L+2YGRHglDGMPgJRbitgCxC3GzKVQF/t+ij1aNcNg2AnEXGtLHJDwoSWrAq3TUm0EVg==", + "dev": true, + "dependencies": { + "rfile": "~1.0", + "uglify-js": "~2.2" + } + }, + "node_modules/ruglify/node_modules/source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "dev": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ruglify/node_modules/uglify-js": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", + "integrity": "sha512-viLk+/8G0zm2aKt1JJAVcz5J/5ytdiNaIsKgrre3yvSUjwVG6ZUujGH7E2TiPigZUwLYCe7eaIUEP2Zka2VJPA==", + "dev": true, + "dependencies": { + "optimist": "~0.3.5", + "source-map": "~0.1.7" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -18394,6 +22385,21 @@ "node": ">=0.12.0" } }, + "node_modules/rust-result": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz", + "integrity": "sha512-6cJzSBU+J/RJCF063onnQf0cDUOHs9uZI1oroSGnHOph+CQTIJ5Pp2hK5kEQq1+7yE/EEWfulSNXAQ2jikPthA==", + "dev": true, + "dependencies": { + "individual": "^2.0.0" + } + }, + "node_modules/rx": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz", + "integrity": "sha512-u5qvfulb7NXoY/+OE28920WEgFi6aiDjf5iF9rA2f9tBXejLgTLd0WxkclvIQWjFFHfNJlb7pSTsrjgiDh+Uug==", + "dev": true + }, "node_modules/rxjs": { "version": "7.5.5", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", @@ -18496,6 +22502,17 @@ "ajv": "^6.9.1" } }, + "node_modules/script-injector": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/script-injector/-/script-injector-0.1.7.tgz", + "integrity": "sha512-0iW1D9UKsOPNUVBHvR76KePNS5TamEBN38bT5k7BqsXItsyV5oJTZbVsvOF3YS2xJ7GB7pszmgfDFJbIgHmrDQ==", + "dev": true, + "dependencies": { + "duplexer": "~0.1.1", + "through": "~2.3.4", + "trumpet": "~1.6.3" + } + }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -18743,6 +22760,35 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/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, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==", + "dev": true + }, + "node_modules/shasum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "integrity": "sha512-UTzHm/+AzKfO9RgPgRpDIuMSNie1ubXRaljjlhFMNGYoG7z+rm9AHLPMf70R7887xboDH9Q+5YQbWKObFHEAtw==", + "dev": true, + "dependencies": { + "json-stable-stringify": "~0.0.0", + "sha.js": "~2.4.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -18764,6 +22810,48 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-0.0.1.tgz", + "integrity": "sha512-uEWz7wa9vnCi9w4mvKZMgbHFk3DCKjLQlZcy0tJxUH4NwZjRrPPHXAYIEt2TmJs600Dcgj0Z3fZLZKVPVdGNbQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha512-Ny0KN4dyT8ZSCE0frtcbAJGoM/HTArpyPkeli1/00aYfm0sbD/Gk/4x7N2DP9QKGpBsiQH7n6rpm1L79RtviEQ==", + "dev": true, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/shelljs-nodecli": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shelljs-nodecli/-/shelljs-nodecli-0.1.1.tgz", + "integrity": "sha512-/e+APCWKKW9A8YMHKgDzhWQ21zPuDLjn6ATBczxbp6uUeiCSwvw95ynKAjMsRd1yrd5dlCkMKJoc/Lpwrt2w+A==", + "dev": true, + "dependencies": { + "shelljs": "~0.2" + } + }, + "node_modules/shelljs-nodecli/node_modules/shelljs": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz", + "integrity": "sha512-LQiM15qPbSyzHDFfI4v7EVhjBXG5PUAKWVBnVMBXwdlQSHZtzKYeKGzDHBIqpenPrCsPWqBSOF5o7oSvSfX+CA==", + "dev": true, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -18778,6 +22866,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", + "dev": true + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -18903,6 +22997,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -19108,6 +23211,20 @@ "urix": "^0.1.0" } }, + "node_modules/sntp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", + "integrity": "sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==", + "deprecated": "This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "dev": true, + "optional": true, + "dependencies": { + "hoek": "0.9.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/socket.io": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", @@ -19304,6 +23421,21 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "node_modules/sse-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/sse-stream/-/sse-stream-0.0.4.tgz", + "integrity": "sha512-rnDUubW7a4CZAB5D0r2OtFU/zvY05MoNGHMX6deAYK0wWaizrNcHzimf+Nk5y0sqntGAPpWEnIopWrrAf2TBVg==", + "dev": true, + "dependencies": { + "through": "~2.2.7" + } + }, + "node_modules/sse-stream/node_modules/through": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", + "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", + "dev": true + }, "node_modules/sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", @@ -19460,6 +23592,40 @@ "node": ">= 0.6" } }, + "node_modules/stream-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-1.0.0.tgz", + "integrity": "sha512-e+V5xc4LlkOiRr64kZTUdb11exsbpSnwb9uwmXaHeDXCpfHg7vaefMJOxi21Pe74ZOqjZ87blBcqqpNAM4Ku0g==", + "dev": true, + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^1.0.27-1" + } + }, + "node_modules/stream-browserify/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/stream-browserify/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, "node_modules/stream-buffers": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", @@ -19478,6 +23644,80 @@ "duplexer": "~0.1.1" } }, + "node_modules/stream-combiner2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.0.2.tgz", + "integrity": "sha512-7DO1SfBVnyIyo9ytUjSyVojT5bp1ZY6h3pj7HUs6PwcRSd/r8mBOHbRwYC7nbHRakKzMKyNp5HWJRv4GgVherA==", + "dev": true, + "dependencies": { + "duplexer2": "~0.0.2", + "through2": "~0.5.1" + } + }, + "node_modules/stream-combiner2/node_modules/duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "dev": true, + "dependencies": { + "readable-stream": "~1.1.9" + } + }, + "node_modules/stream-combiner2/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/stream-combiner2/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/stream-combiner2/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/stream-combiner2/node_modules/through2": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", + "integrity": "sha512-zexCrAOTbjkBCXGyozn7hhS3aEaqdrc59mAD2E3dKYzV1vFuEGQ1hEDJN2oQMQFwy4he2zyLqPZV+AlfS8ZWJA==", + "dev": true, + "dependencies": { + "readable-stream": "~1.0.17", + "xtend": "~3.0.0" + } + }, + "node_modules/stream-combiner2/node_modules/through2/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/stream-combiner2/node_modules/xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, "node_modules/stream-exhaust": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", @@ -19490,6 +23730,54 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, + "node_modules/stream-splicer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-1.3.2.tgz", + "integrity": "sha512-nmUMEbdm/sZYqe9dZs7mqJvTYpunsDbIWI5FiBCMc/hMVd6vwzy+ITmo7C3gcLYqrn+uQ1w+EJwooWvJ997JAA==", + "dev": true, + "dependencies": { + "indexof": "0.0.1", + "inherits": "^2.0.1", + "isarray": "~0.0.1", + "readable-stream": "^1.1.13-1", + "readable-wrap": "^1.0.0", + "through2": "^1.0.0" + } + }, + "node_modules/stream-splicer/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/stream-splicer/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/stream-splicer/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/stream-splicer/node_modules/through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "dependencies": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, "node_modules/streamroller": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.4.tgz", @@ -19579,6 +23867,13 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/stringstream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "dev": true, + "optional": true + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -19618,16 +23913,40 @@ "node": ">=0.10.0" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==", "dev": true, + "dependencies": { + "get-stdin": "^4.0.1" + }, + "bin": { + "strip-indent": "cli.js" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", + "dev": true, + "bin": { + "strip-json-comments": "cli.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", + "dev": true, + "dependencies": { + "minimist": "^1.1.0" } }, "node_modules/suffix": { @@ -19675,6 +23994,15 @@ "es6-symbol": "^3.1.1" } }, + "node_modules/syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "dev": true, + "dependencies": { + "acorn-node": "^1.2.0" + } + }, "node_modules/table": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", @@ -19713,6 +24041,12 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, + "node_modules/taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", + "dev": true + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -19964,6 +24298,12 @@ "url": "https://bevry.me/fund" } }, + "node_modules/throttleit": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", + "integrity": "sha512-HtlTFeyYs1elDM2txiIGsdXHaq8kffVaZH/QEBRbo95zQqzlsBx5ELKhkPOZVad9OK9oxzwx6UrQN8Vfh/+yag==", + "dev": true + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -20022,6 +24362,27 @@ "node": ">=0.10.0" } }, + "node_modules/timed-out": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", + "integrity": "sha512-pqqJOi1rF5zNs/ps4vmbE4SFCrM4iR7LW+GHAsHqO/EumqbIWceioevYLM5xZRgQSH6gFgL9J/uB7EcJhQ9niQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==", + "dev": true, + "dependencies": { + "process": "~0.11.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", @@ -20093,6 +24454,13 @@ "node": ">=4" } }, + "node_modules/to-iso-string": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", + "integrity": "sha512-oeHLgfWA7d0CPQa6h0+i5DAJZISz5un0d5SHPkw+Untclcvzv9T+AC3CvGXlZJdOlIbxbTfyyzlqCXc5hjpXYg==", + "deprecated": "to-iso-string has been deprecated, use @segment/to-iso-string instead.", + "dev": true + }, "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -20226,6 +24594,15 @@ "node": "*" } }, + "node_modules/treeify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.0.1.tgz", + "integrity": "sha512-i3MKN4nGEOuVAcd7s5MtAc2+QBExwcaRT/6/CzUSYVYwzM58bJ3H3wwCPu2PEAGjVPHjfIC/MPaXsxPGUk07cg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -20236,6 +24613,15 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -20255,6 +24641,63 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/trumpet": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/trumpet/-/trumpet-1.6.6.tgz", + "integrity": "sha512-A4cn/zuq0AsxS5M8cD+7GUoIhOoK2qkcpFUwlpHnNOsTPzCq7FITZV9lg95ydupJcQRi/kFQzGIn7oN3kNp10w==", + "dev": true, + "dependencies": { + "duplexer2": "~0.0.2", + "html-select": "^2.3.5", + "html-tokenize": "^1.1.1", + "inherits": "^2.0.0", + "readable-stream": "^1.0.27-1", + "through2": "^1.0.0" + } + }, + "node_modules/trumpet/node_modules/duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "dev": true, + "dependencies": { + "readable-stream": "~1.1.9" + } + }, + "node_modules/trumpet/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/trumpet/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/trumpet/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/trumpet/node_modules/through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "dependencies": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, "node_modules/tsconfig-paths": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz", @@ -20285,6 +24728,12 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -20360,20 +24809,6 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, - "node_modules/typescript": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", - "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, "node_modules/typescript-compare": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", @@ -20414,6 +24849,12 @@ "node": "*" } }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, "node_modules/uglify-js": { "version": "3.15.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz", @@ -20427,6 +24868,93 @@ "node": ">=0.8.0" } }, + "node_modules/uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", + "dev": true + }, + "node_modules/umd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/umd/-/umd-2.1.0.tgz", + "integrity": "sha512-mEAJeceExHnblcAwN3BQtDPYOrTy4ALeBh6nQ9KW0cUCd0UU714jAfil2jvq09b67IizwJIiTVFOjE+/52Dyvw==", + "dev": true, + "dependencies": { + "rfile": "~1.0.0", + "ruglify": "~1.0.0", + "through": "~2.3.4", + "uglify-js": "~2.4.0" + }, + "bin": { + "umd": "bin/cli.js" + } + }, + "node_modules/umd/node_modules/async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==", + "dev": true + }, + "node_modules/umd/node_modules/camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/umd/node_modules/source-map": { + "version": "0.1.34", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz", + "integrity": "sha512-yfCwDj0vR9RTwt3pEzglgb3ZgmcXHt6DjG3bjJvzPwTL+5zDQ2MhmSzAcTy0GTiQuCiriSWXvWM1/NhKdXuoQA==", + "dev": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/umd/node_modules/uglify-js": { + "version": "2.4.24", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz", + "integrity": "sha512-tktIjwackfZLd893KGJmXc1hrRHH1vH9Po3xFh1XBjjeGAnN02xJ3SuoA+n1L29/ZaCA18KzCFlckS+vfPugiA==", + "dev": true, + "dependencies": { + "async": "~0.2.6", + "source-map": "0.1.34", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.5.4" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/umd/node_modules/wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/umd/node_modules/yargs": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz", + "integrity": "sha512-5j382E4xQSs71p/xZQsU1PtRA2HXPAjX0E0DkoGLxwNASMOKX6A9doV1NrZmj85u2Pjquz402qonBzz/yLPbPA==", + "dev": true, + "dependencies": { + "camelcase": "^1.0.2", + "decamelize": "^1.0.0", + "window-size": "0.1.0", + "wordwrap": "0.0.2" + } + }, "node_modules/unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", @@ -20461,6 +24989,21 @@ "node": ">=0.10.0" } }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/underscore.string": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", + "integrity": "sha512-yxkabuCaIBnzfIvX3kBxQqCs0ar/bfJwDnFEHJUm/ZrRVhT3IItdRF5cZjARLzEnyQYtIUhsZ2LG2j3HidFOFQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/undertaker": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", @@ -20833,6 +25376,12 @@ "requires-port": "^1.0.0" } }, + "node_modules/url-toolkit": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.5.tgz", + "integrity": "sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg==", + "dev": true + }, "node_modules/url/node_modules/punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", @@ -20848,6 +25397,18 @@ "node": ">=0.10.0" } }, + "node_modules/user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha512-aggiKfEEubv3UwRNqTzLInZpAOmKzwdHqEBmW/hBA/mt99eg+b4VrX6i+IRLxU8+WJYfa33rGwRseg4eElUgsQ==", + "dev": true, + "bin": { + "user-home": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/util": { "version": "0.12.4", "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", @@ -20868,6 +25429,12 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "node_modules/util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", + "dev": true + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -21099,6 +25666,98 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/video.js": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.20.2.tgz", + "integrity": "sha512-hdvAHKAyaL6bCDkeu0pPtFYKi1EDaOUovm7FN1xqBDolUxgH8FKy1WIgTS+Ouuaw7R54SCTcSeXjZEizhy9ouQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/http-streaming": "2.14.2", + "@videojs/vhs-utils": "^3.0.4", + "@videojs/xhr": "2.6.0", + "aes-decrypter": "3.1.3", + "global": "^4.4.0", + "keycode": "^2.2.0", + "m3u8-parser": "4.7.1", + "mpd-parser": "0.21.1", + "mux.js": "6.0.1", + "safe-json-parse": "4.0.0", + "videojs-font": "3.2.0", + "videojs-vtt.js": "^0.15.3" + } + }, + "node_modules/video.js/node_modules/safe-json-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz", + "integrity": "sha512-RjZPPHugjK0TOzFrLZ8inw44s9bKox99/0AZW9o/BEQVrJfhI+fIHMErnPyRa89/yRXUUr93q+tiN6zhoVV4wQ==", + "dev": true, + "dependencies": { + "rust-result": "^1.0.0" + } + }, + "node_modules/videojs-contrib-ads": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/videojs-contrib-ads/-/videojs-contrib-ads-6.9.0.tgz", + "integrity": "sha512-nzKz+jhCGMTYffSNVYrmp9p70s05v6jUMOY3Z7DpVk3iFrWK4Zi/BIkokDWrMoHpKjdmCdKzfJVBT+CrUj6Spw==", + "dev": true, + "dependencies": { + "global": "^4.3.2", + "video.js": "^6 || ^7" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, + "node_modules/videojs-font": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.2.0.tgz", + "integrity": "sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA==", + "dev": true + }, + "node_modules/videojs-ima": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/videojs-ima/-/videojs-ima-1.11.0.tgz", + "integrity": "sha512-ZRoWuGyJ75zamwZgpr0i/gZ6q7Evda/Q6R46gpW88WN7u0ORU7apw/lM1MSG4c3YDXW8LDENgzMAvMZUdifWhg==", + "dev": true, + "dependencies": { + "@hapi/cryptiles": "^5.1.0", + "can-autoplay": "^3.0.0", + "extend": ">=3.0.2", + "lodash": ">=4.17.19", + "lodash.template": ">=4.5.0", + "videojs-contrib-ads": "^6.6.5" + }, + "engines": { + "node": ">=0.8.0" + }, + "peerDependencies": { + "video.js": "^5.19.2 || ^6 || ^7" + } + }, + "node_modules/videojs-playlist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/videojs-playlist/-/videojs-playlist-5.0.0.tgz", + "integrity": "sha512-TM9bytwKqkE05wdWPEKDpkwMGhS/VgMCIsEuNxmX1J1JO9zaTIl4Wm3egf5j1dhIw19oWrqGUV/nK0YNIelCpA==", + "dev": true, + "dependencies": { + "global": "^4.3.2", + "video.js": "^6 || ^7" + }, + "engines": { + "node": ">=4.4.0" + } + }, + "node_modules/videojs-vtt.js": { + "version": "0.15.4", + "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.4.tgz", + "integrity": "sha512-r6IhM325fcLb1D6pgsMkTQT1PpFdUdYZa1iqk7wJEu+QlibBwATPfPc9Bg8Jiym0GE5yP1AG2rMLu+QMVWkYtA==", + "dev": true, + "dependencies": { + "global": "^4.3.1" + } + }, "node_modules/vinyl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", @@ -21202,6 +25861,15 @@ "node": ">= 0.10" } }, + "node_modules/vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha512-NyZNR3WDah+NPkjh/YmhuWSsT4a0mF0BJYgUmvrJ70zxjTXh5Y2Asobxlh0Nfs0PCFB5FVpRJft7NozAWFMwLQ==", + "dev": true, + "dependencies": { + "indexof": "0.0.1" + } + }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -21762,6 +26430,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -21884,6 +26561,18 @@ } } }, + "node_modules/xml-escape": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz", + "integrity": "sha512-gCT82WbwOT9SBI/94j5i0tqHpjHIP/0kP11BS8s2wcBtdcFsDNLS9sLvA+C55fD3hpGhgnE/r7hfeBFkiMATjw==", + "dev": true + }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -22143,269 +26832,1262 @@ } }, "plugins/eslint": { - "name": "eslint-plugin-prebid", "version": "1.0.0", + "integrity": "sha512-DH8lk8H4D+XCWtPm7C27IzzD4lkBHv49YTqOHeS/1mYCp4rn1j3NNNA1gl2q+CNYaAPSZDaS5DwRL/ErDP6O4Q==", "dev": true, - "license": "Apache-2.0" - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", - "requires": { - "@jridgewell/trace-mapping": "^0.3.0" + "dependencies": { + "chalk": "^1.0.0", + "concat-stream": "^1.4.6", + "debug": "^2.1.1", + "doctrine": "^0.6.2", + "escape-string-regexp": "^1.0.2", + "escope": "^3.2.0", + "espree": "^2.2.0", + "estraverse": "^4.1.0", + "estraverse-fb": "^1.3.1", + "globals": "^8.2.0", + "inquirer": "^0.8.2", + "is-my-json-valid": "^2.10.0", + "js-yaml": "^3.2.5", + "lodash.clonedeep": "^3.0.1", + "lodash.merge": "^3.3.2", + "lodash.omit": "^3.1.0", + "minimatch": "^2.0.1", + "mkdirp": "^0.5.0", + "object-assign": "^2.0.0", + "optionator": "^0.5.0", + "path-is-absolute": "^1.0.0", + "path-is-inside": "^1.0.1", + "strip-json-comments": "~1.0.1", + "text-table": "~0.2.0", + "user-home": "^1.0.0", + "xml-escape": "~1.0.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "devDependencies": { + "beefy": "^1.0.0", + "brfs": "0.0.9", + "browserify": "^8.1.3", + "chai": "^1.9.1", + "coveralls": "2.11.2", + "dateformat": "^1.0.8", + "esprima": "^2.4.1", + "esprima-fb": "^10001.1.0-dev-harmony-fb", + "gh-got": "^1.0.3", + "istanbul": "^0.3.5", + "jsdoc": "^3.3.0-beta1", + "jsonlint": "^1.6.2", + "markdownlint": "^0.0.6", + "mocha": "^2.1.0", + "mocha-phantomjs": "3.6.0", + "npm-license": "^0.2.3", + "phantomjs": "1.9.7-15", + "proxyquire": "^1.0.0", + "rewire": "^2.3.4", + "semver": "^4.1.0", + "shelljs": "^0.3.0", + "shelljs-nodecli": "~0.1.0", + "sinon": "1.14.1", + "through": "^2.3.6" + }, + "engines": { + "node": ">=0.10" } }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "requires": { - "@babel/highlight": "^7.18.6" + "plugins/eslint/node_modules/ansi-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "@babel/compat-data": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", - "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==" - }, - "@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" + "plugins/eslint/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "@babel/eslint-parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", - "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", + "plugins/eslint/node_modules/argparse": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", + "integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==", "dev": true, - "requires": { - "eslint-scope": "^5.1.1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" + "dependencies": { + "underscore": "~1.7.0", + "underscore.string": "~2.4.0" } }, - "@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", - "requires": { - "@babel/types": "^7.19.0", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" + "plugins/eslint/node_modules/asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.9" } }, - "@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", - "requires": { - "@babel/types": "^7.16.7" + "plugins/eslint/node_modules/assert-plus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", + "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.8" } }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" + "plugins/eslint/node_modules/assertion-error": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.0.tgz", + "integrity": "sha512-g/gZV+G476cnmtYI+Ko9d5khxSoCSoom/EaNmmCfwpOvBXEJ18qwFrxfP1/CsIqk2no1sAKKwxndV0tP7ROOFQ==", + "dev": true, + "engines": { + "node": "*" } }, - "@babel/helper-compilation-targets": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", - "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", - "requires": { - "@babel/compat-data": "^7.19.0", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", - "semver": "^6.3.0" + "plugins/eslint/node_modules/aws-sign2": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", + "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", + "dev": true, + "optional": true, + "engines": { + "node": "*" } }, - "@babel/helper-create-class-features-plugin": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", - "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" + "plugins/eslint/node_modules/chai": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-1.10.0.tgz", + "integrity": "sha512-E3L9M2SeQU1XagJkE9KJyTAXXHKJkJ1EsKkFp0Rl53lYa3mro2PVgYHNiCb2YRa2nUeyg7aqmI1EIcSBayNd5w==", + "dev": true, + "dependencies": { + "assertion-error": "1.0.0", + "deep-eql": "0.1.3" + }, + "engines": { + "node": ">= 0.4.0" } }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" + "plugins/eslint/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">=0.10.0" } }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", - "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - } + "plugins/eslint/node_modules/cli-width": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz", + "integrity": "sha512-eMU2akIeEIkCxGXUNmDnJq1KzOIiPnJ+rKqRe6hcxE3vIOPvpMrBYOn/Bl7zNlYJj/zQxXquAnozHUCf9Whnsg==", + "dev": true }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + "plugins/eslint/node_modules/combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", + "dev": true, + "optional": true, + "dependencies": { + "delayed-stream": "0.0.5" + }, + "engines": { + "node": ">= 0.8" + } }, - "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "requires": { - "@babel/types": "^7.16.7" + "plugins/eslint/node_modules/commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha512-CD452fnk0jQyk3NfnK+KkR/hUPoHt5pVaKHogtyyv3N0U4QfAal9W0/rXLOg/vVZgQKa7jdtXypKs1YAip11uQ==", + "dev": true, + "engines": { + "node": ">= 0.6.x" } }, - "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "plugins/eslint/node_modules/coveralls": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.11.2.tgz", + "integrity": "sha512-+OK2imSCDXSYaOyAxGVUmzDfDtCYLW+gtdDVpjvq99R5Dyry4Puj3EQ/4YnsxNc6RHsuhx3wIkHSBIRaJZY5YQ==", + "dev": true, + "dependencies": { + "js-yaml": "3.0.1", + "lcov-parse": "0.0.6", + "log-driver": "1.2.4", + "request": "2.40.0" + }, + "bin": { + "coveralls": "bin/coveralls.js" + }, + "engines": { + "node": ">=0.8.6" } }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "requires": { - "@babel/types": "^7.18.6" + "plugins/eslint/node_modules/coveralls/node_modules/esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" } }, - "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", - "requires": { - "@babel/types": "^7.16.7" + "plugins/eslint/node_modules/coveralls/node_modules/js-yaml": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.0.1.tgz", + "integrity": "sha512-dgxgLzZS9qLWAQd/wrVG8tOiRSBJq1Ss9gbd7+fdBhcia3efHjLLpPkcUhKOyVACxTEAgnao3RT1kj1otiW42g==", + "dev": true, + "dependencies": { + "argparse": "~ 0.1.11", + "esprima": "~ 1.0.2" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + }, + "engines": { + "node": ">= 0.6.0" } }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "requires": { - "@babel/types": "^7.18.6" + "plugins/eslint/node_modules/dateformat": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha512-5sFRfAAmbHdIts+eKjR9kYJoF0ViCMVX9yqLu5A7S/v+nd077KgCITOMiirmyCBiZpKLDXbBOkYm6tu7rX/TKg==", + "dev": true, + "dependencies": { + "get-stdin": "^4.0.1", + "meow": "^3.3.0" + }, + "bin": { + "dateformat": "bin/cli.js" + }, + "engines": { + "node": "*" } }, - "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "plugins/eslint/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" } }, - "@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", - "requires": { - "@babel/types": "^7.16.7" + "plugins/eslint/node_modules/deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha512-6sEotTRGBFiNcqVoeHwnfopbSpi5NbH1VWJmYCVkmxMmaVTT0bUTrNaGyBwhgP4MZL012W/mkzIn3Da+iDYweg==", + "dev": true, + "dependencies": { + "type-detect": "0.1.1" + }, + "engines": { + "node": "*" } }, - "@babel/helper-plugin-utils": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", - "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==" + "plugins/eslint/node_modules/delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.0" + } }, - "@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" + "plugins/eslint/node_modules/diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha512-VzVc42hMZbYU9Sx/ltb7KYuQ6pqAw+cbFWVy4XKdkuEL2CFaRLGEnISPs7YdzaUGpi+CpIqvRmu7hPQ4T7EQ5w==", + "dev": true, + "engines": { + "node": ">=0.3.1" } }, - "@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "plugins/eslint/node_modules/doctrine": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz", + "integrity": "sha512-FSGvDB23RFdm/Z2hEINXN1AcBW5I4YBqpGD/lScJV34vuOwrPFyLHN9bwCzLa6lUmqS6ipdp5XlVJRQ6yJ5iSA==", + "dev": true, + "dependencies": { + "esutils": "^1.1.6", + "isarray": "0.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "requires": { - "@babel/types": "^7.18.6" + "plugins/eslint/node_modules/escodegen": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz", + "integrity": "sha512-2cd7+JUtUEmZVpGmfF9r+uRYXswJAkf85Ce8GvdBa7hSvdjY8hGo+rwC5syAgYzqHpfxNJzLntFjw6879yPbgQ==", + "dev": true, + "dependencies": { + "esprima": "^1.2.2", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.5.0" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" } }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "requires": { - "@babel/types": "^7.16.0" + "plugins/eslint/node_modules/escodegen/node_modules/esprima": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", + "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" } }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "requires": { - "@babel/types": "^7.18.6" + "plugins/eslint/node_modules/escodegen/node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" + "plugins/eslint/node_modules/escodegen/node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "@babel/helper-validator-identifier": { + "plugins/eslint/node_modules/espree": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz", + "integrity": "sha512-HWJpgkL44cbjWiOTC9Pm34RZE57H1g9V4Ln9U14TUtiywFTLMMpMCtmQK5rkjbGBXigQT8bS3r45+Dt5+m0SZg==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/esprima": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz", + "integrity": "sha512-uM6hfS0/8ybNIj8SGRMdidPJy5uhWqWN/GIkyqnMAbCSL44yfFGLuBpRRCgOpBXBZt2OymQuM+IfahkqJq3DWw==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/esutils": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", + "integrity": "sha512-RG1ZkUT7iFJG9LSHr7KDuuMSlujfeTtMNIcInURxKAxhMtwQhI3NrQhz26gZQYlsYZQKzsnwtpKrFKj9K9Qu1A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/fast-levenshtein": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz", + "integrity": "sha512-hYsfI0s4lfQ2rHVFKXwAr/L/ZSbq9TZwgXtZqW7ANcn9o9GKvcbWxOnxx7jykXf/Ezv1V8TvaBEKcGK7DWKX5A==", + "dev": true + }, + "plugins/eslint/node_modules/figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/figures/node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/forever-agent": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "plugins/eslint/node_modules/form-data": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", + "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", + "dev": true, + "optional": true, + "dependencies": { + "async": "~0.9.0", + "combined-stream": "~0.0.4", + "mime": "~1.2.11" + }, + "engines": { + "node": ">= 0.8" + } + }, + "plugins/eslint/node_modules/form-data/node_modules/async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==", + "dev": true, + "optional": true + }, + "plugins/eslint/node_modules/glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==", + "dev": true, + "dependencies": { + "inherits": "2", + "minimatch": "0.3" + }, + "engines": { + "node": "*" + } + }, + "plugins/eslint/node_modules/glob/node_modules/minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA==", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dev": true, + "dependencies": { + "lru-cache": "2", + "sigmund": "~1.0.0" + }, + "engines": { + "node": "*" + } + }, + "plugins/eslint/node_modules/globals": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz", + "integrity": "sha512-IHCTKEGo42ICEkTZBADyl4HX06hVdFF4qdJdqOgaBe5X8RE1/MrvubetsEtGTcwjs46djFq0Gc3+5RgTsc3UoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha512-RTBwDHhNuOx4F0hqzItc/siXCasGfC4DeWcBamclWd+6jWtBaeB/SGbMkGf0eiQoW7ib8JpvOgnUsmgMHI3Mfw==", + "dev": true + }, + "plugins/eslint/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/http-signature": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", + "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", + "dev": true, + "optional": true, + "dependencies": { + "asn1": "0.1.11", + "assert-plus": "^0.1.5", + "ctype": "0.5.3" + }, + "engines": { + "node": ">=0.8" + } + }, + "plugins/eslint/node_modules/inquirer": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz", + "integrity": "sha512-+rksrtdqQ8do7yOsmP5YIgbSdbZYuCIrnfH5vjFYGAr1XgJpMksb3rFZMJ3jiKuUyDVEA4MVDYbkA3ribJn3Tg==", + "dev": true, + "dependencies": { + "ansi-regex": "^1.1.1", + "chalk": "^1.0.0", + "cli-width": "^1.0.1", + "figures": "^1.3.5", + "lodash": "^3.3.1", + "readline2": "^0.1.1", + "rx": "^2.4.3", + "through": "^2.3.6" + } + }, + "plugins/eslint/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "plugins/eslint/node_modules/istanbul": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz", + "integrity": "sha512-8H/jxiee2UqX/mviKkPoKQYMxU2t995FC5PwO4zjWeDPOozjoeKqxEyN62l9o5+UgzvYQbrKgQjjxhGON8FcMg==", + "deprecated": "This module is no longer maintained, try this instead:\n npm i nyc\nVisit https://istanbul.js.org/integrations for other alternatives.", + "dev": true, + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.7.x", + "esprima": "2.5.x", + "fileset": "0.2.x", + "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" + }, + "bin": { + "istanbul": "lib/cli.js" + } + }, + "plugins/eslint/node_modules/istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "plugins/eslint/node_modules/lcov-parse": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.6.tgz", + "integrity": "sha512-chuBQJZiBq28YUM6Yr3tf3h5Lxhb+DvhbxxSNpsHURSXiZXOzp49phiWG2pKHboOehJDujivwNQGRP8mAErMvQ==", + "dev": true + }, + "plugins/eslint/node_modules/levn": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz", + "integrity": "sha512-mvp+NO++YH0B+e8cC/SvJxk6k5Z9Ngd3iXuz7tmT8vZCyQZj/5SI1GkFOiZGGPkm5wWGI9SUrqiAfPq7BJH+0w==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.0", + "type-check": "~0.3.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "plugins/eslint/node_modules/lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==", + "dev": true + }, + "plugins/eslint/node_modules/lodash.clonedeep": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", + "integrity": "sha512-I8MpGh5z+6OixDAAb21teLSZDmqVPjlq02Q7ZFrbn2xnQHYYuJf6on/94SWpF/p0s3p/cEv/53ro4AhDOfCR0g==", + "dev": true, + "dependencies": { + "lodash._baseclone": "^3.0.0", + "lodash._bindcallback": "^3.0.0" + } + }, + "plugins/eslint/node_modules/lodash.isplainobject": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz", + "integrity": "sha512-P4wZnho5curNqeEq/x292Pb57e1v+woR7DJ84DURelKB46lby8aDEGVobSaYtzHdQBWQrJSdxcCwjlGOvvdIyg==", + "dev": true, + "dependencies": { + "lodash._basefor": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.keysin": "^3.0.0" + } + }, + "plugins/eslint/node_modules/lodash.merge": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz", + "integrity": "sha512-ZgGZpRhWLjivGUbjtApZR4HyLv/UAyoYqESVYkK4aLBJVHRrbFpG+GNnE9JPijliME4LkKM0SFI/WyOiBiv1+w==", + "dev": true, + "dependencies": { + "lodash._arraycopy": "^3.0.0", + "lodash._arrayeach": "^3.0.0", + "lodash._createassigner": "^3.0.0", + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0", + "lodash.isplainobject": "^3.0.0", + "lodash.istypedarray": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.keysin": "^3.0.0", + "lodash.toplainobject": "^3.0.0" + } + }, + "plugins/eslint/node_modules/log-driver": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.4.tgz", + "integrity": "sha512-QmyGbAcBbHk8ysCGtT6FQ+LZML6+EeT0NdotCJGu72kNhknXtdso1G/NI0r7j45whFYNTU15XMW+JGOvGX07QQ==", + "dev": true, + "engines": { + "node": ">=0.8.6" + } + }, + "plugins/eslint/node_modules/lolex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.1.0.tgz", + "integrity": "sha512-wGZrF3AlAWxG2j+6NyyttZ/UVxW8o/F+q01IUGuf2PiEIAUG9av/vpBS5TQHTQtzPmPJB4CZWjwyGR4C4aX83w==", + "dev": true + }, + "plugins/eslint/node_modules/lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==", + "dev": true + }, + "plugins/eslint/node_modules/mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", + "dev": true, + "optional": true + }, + "plugins/eslint/node_modules/mime-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz", + "integrity": "sha512-echfutj/t5SoTL4WZpqjA1DCud1XO0WQF3/GJ48YBmc4ZMhCK77QA6Z/w6VTQERLKuJ4drze3kw2TUT8xZXVNw==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "plugins/eslint/node_modules/minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dev": true, + "dependencies": { + "brace-expansion": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "plugins/eslint/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "plugins/eslint/node_modules/mocha": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", + "integrity": "sha512-jNt2iEk9FPmZLzL+sm4FNyOIDYXf2wUU6L4Cc8OIKK/kzgMHKPi4YhTZqG4bW4kQVdIv6wutDybRhXfdnujA1Q==", + "dev": true, + "dependencies": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.11", + "growl": "1.9.2", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0", + "to-iso-string": "0.0.2" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 0.8.x" + } + }, + "plugins/eslint/node_modules/mocha/node_modules/debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha512-X0rGvJcskG1c3TgSCPqHJ0XJgwlcvOC7elJ5Y0hYuKBZoVqWpAMfLOeIh2UI/DCQ5ruodIjvsugZtjUYUw2pUw==", + "dev": true, + "dependencies": { + "ms": "0.7.1" + } + }, + "plugins/eslint/node_modules/mocha/node_modules/escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha512-cQpUid7bdTUnFin8S7BnNdOk+/eDqQmKgCANSyd/jAhrKEvxUvr9VQ8XZzXiOtest8NLfk3FSBZzwvemZNQ6Vg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "plugins/eslint/node_modules/mocha/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", + "dev": true + }, + "plugins/eslint/node_modules/mocha/node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "plugins/eslint/node_modules/mocha/node_modules/ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha512-lRLiIR9fSNpnP6TC4v8+4OU7oStC01esuNowdQ34L+Gk8e5Puoc88IqJ+XAY/B3Mn2ZKis8l8HX90oU8ivzUHg==", + "dev": true + }, + "plugins/eslint/node_modules/mocha/node_modules/supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha512-mS5xsnjTh5b7f2DM6bch6lR582UCOTphzINlZnDsfpIRrwI6r58rb6YSSGsdexkm8qw2bBVO2ID2fnJOTuLiPA==", + "dev": true, + "bin": { + "supports-color": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "plugins/eslint/node_modules/oauth-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", + "dev": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "plugins/eslint/node_modules/object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha512-CdsOUYIh5wIiozhJ3rLQgmUTgcyzFwZZrqhkKhODMoGtPKM+wt0h0CNIoauJWMsS9822EdzPsF/6mb4nLvPN5g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/optionator": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", + "integrity": "sha512-jUr7aBk/kCInAEsl+qxuw4ORpe458atDKXNLhyvPUD4NfnsJsbAViX1b9nb/0rS62lO8cIFd1VoiaXLQ+MybOw==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.2", + "fast-levenshtein": "~1.0.0", + "levn": "~0.2.5", + "prelude-ls": "~1.1.1", + "type-check": "~0.3.1", + "wordwrap": "~0.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "plugins/eslint/node_modules/optionator/node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "plugins/eslint/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "plugins/eslint/node_modules/qs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz", + "integrity": "sha512-tHuOP9TN/1VmDM/ylApGK1QF3PSIP8I6bHDEfoKNQeViREQ/sfu1bAUrA1hoDun8p8Tpm7jcsz47g+3PiGoYdg==", + "dev": true + }, + "plugins/eslint/node_modules/request": { + "version": "2.40.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz", + "integrity": "sha512-waNoGB4Z7bPn+lgqPk7l7hhze4Vd68jKccnwLeS7vr9GMxz0iWQbYTbBNWzfIk87Urx7V44pu29qjF/omej+Fw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "dependencies": { + "forever-agent": "~0.5.0", + "json-stringify-safe": "~5.0.0", + "mime-types": "~1.0.1", + "node-uuid": "~1.4.0", + "qs": "~1.0.0" + }, + "optionalDependencies": { + "aws-sign2": "~0.5.0", + "form-data": "~0.1.0", + "hawk": "1.1.1", + "http-signature": "~0.10.0", + "oauth-sign": "~0.3.0", + "stringstream": "~0.0.4", + "tough-cookie": ">=0.12.0", + "tunnel-agent": "~0.4.0" + } + }, + "plugins/eslint/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, + "plugins/eslint/node_modules/semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "plugins/eslint/node_modules/sinon": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.14.1.tgz", + "integrity": "sha512-cysrMyrriLwSn5Ye82xTCAVVS6Q6XLxlZE3jtPb4IFng2npN3lQWQ5Uyaud6cRpzztbEy2sbJkrDSbIl6OKUCA==", + "dev": true, + "dependencies": { + "formatio": "1.1.1", + "lolex": "1.1.0", + "util": ">=0.10.3 <1" + }, + "engines": { + "node": ">=0.1.103" + } + }, + "plugins/eslint/node_modules/source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "plugins/eslint/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "plugins/eslint/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "plugins/eslint/node_modules/tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", + "dev": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "plugins/eslint/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "plugins/eslint/node_modules/type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha512-5rqszGVwYgBoDkIm2oUtvkfZMQ0vk29iDMU0W2qCa3rG0vPDNczCMT4hV/bLBgLg8k8ri6+u3Zbt+S/14eMzlA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "plugins/eslint/node_modules/underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==", + "dev": true + }, + "plugins/eslint/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.0" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", + "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==" + }, + "@babel/core": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", + "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.0", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + } + }, + "@babel/eslint-parser": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", + "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", + "dev": true, + "requires": { + "eslint-scope": "^5.1.1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.0" + } + }, + "@babel/generator": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", + "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "requires": { + "@babel/types": "^7.19.0", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", + "requires": { + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", + "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", + "requires": { + "@babel/compat-data": "^7.19.0", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", + "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", + "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "requires": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", + "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", + "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" + } + }, + "@babel/helper-replace-supers": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "requires": { + "@babel/types": "^7.16.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" + }, + "@babel/helper-validator-identifier": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" @@ -23208,6 +28890,12 @@ "type-fest": "^0.20.2" } }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -23300,6 +28988,30 @@ } } }, + "@hapi/boom": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", + "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "dev": true, + "requires": { + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/cryptiles": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", + "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x" + } + }, + "@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, "@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -23743,6 +29455,12 @@ "@types/node": "*" } }, + "@types/linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", + "dev": true + }, "@types/lodash": { "version": "4.14.179", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz", @@ -23776,6 +29494,16 @@ "@types/lodash": "*" } }, + "@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "requires": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, "@types/mdast": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", @@ -23943,6 +29671,44 @@ "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, + "@videojs/http-streaming": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.2.tgz", + "integrity": "sha512-K1raSfO/pq5r8iUas3OSYni0kXOj91n8ealIpV02khghzGv9LQ6O3YUqYd/eAhJ1HIrmZWOnrYpK/P+mhUExXQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "3.0.5", + "aes-decrypter": "3.1.3", + "global": "^4.4.0", + "m3u8-parser": "4.7.1", + "mpd-parser": "0.21.1", + "mux.js": "6.0.1", + "video.js": "^6 || ^7" + } + }, + "@videojs/vhs-utils": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz", + "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "global": "^4.4.0", + "url-toolkit": "^2.2.1" + } + }, + "@videojs/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-7J361GiN1tXpm+gd0xz2QWr3xNWBE+rytvo8J3KuggFaLg+U37gZQ2BuPLcnkfGffy2e+ozY70RHC8jt7zjA6Q==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "global": "~4.4.0", + "is-function": "^1.0.1" + } + }, "@vue/compiler-core": { "version": "3.2.38", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.38.tgz", @@ -24473,6 +30239,12 @@ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -24824,6 +30596,12 @@ "@xtuc/long": "4.2.2" } }, + "@xmldom/xmldom": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz", + "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==", + "dev": true + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -24864,6 +30642,41 @@ "dev": true, "requires": {} }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dev": true, + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "adm-zip": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.2.1.tgz", + "integrity": "sha512-J2LiZpRxcLsJm2IwoekNa6COwzEZnMwCJ3vxz0UCw2NYUH2WFi7svuDrVccq5KpBGmzGUgFa0L0FwEmKmu/rzQ==", + "dev": true + }, + "aes-decrypter": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz", + "integrity": "sha512-VkG9g4BbhMBy+N5/XodDeV6F02chEk9IpgRTq/0bS80y4dzy79VH2Gtms02VXomf3HmyRe3yyJYkJ990ns+d6A==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^3.0.5", + "global": "^4.4.0", + "pkcs7": "^1.0.4" + } + }, "agent-base": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", @@ -24886,8 +30699,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true, - "optional": true + "dev": true }, "ansi-colors": { "version": "4.1.1", @@ -25091,6 +30903,12 @@ "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", "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": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "dev": true + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -25190,6 +31008,12 @@ "es-abstract": "^1.19.0" } }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, "asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -25199,6 +31023,26 @@ "safer-buffer": "~2.1.0" } }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, "assert": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", @@ -25235,6 +31079,23 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, + "astw": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", + "integrity": "sha512-E/4z//dvN0lfr8zAx8hXeQ8o3nRoQaL/wqI7fAALEvh/40mnyUxfFB9MwyDHYKVDtS3cp3Pow5s96djZR5lkWw==", + "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": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", + "dev": true + } + } + }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -25761,6 +31622,12 @@ } } }, + "Base64": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz", + "integrity": "sha512-reGEWshDmTDQDsCec/HduOO9Wyj6yMOupMfhIf3ugN1TDlK2NQW4DDJSqNNtp380SNcvRfXtO8HSCQot0d0SMw==", + "dev": true + }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -25797,6 +31664,60 @@ "tweetnacl": "^0.14.3" } }, + "beefy": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/beefy/-/beefy-1.1.0.tgz", + "integrity": "sha512-olZqTbw6gnofdbG98uAKvG6O/AjV6WGuPsKpYF41VQK39sUYvulm86RssD1K/iVNkkSJ8cuYeheJ8Nk2gz16wA==", + "dev": true, + "requires": { + "chokidar": "0.8.1", + "colors": "~0.6.0-1", + "ignorepatterns": "1.0.1", + "mime": "~1.2.9", + "nopt": "~2.1.1", + "open": "0.0.3", + "portfinder": "~0.2.1", + "response-stream": "0.0.0", + "script-injector": "~0.1.0", + "sse-stream": "0.0.4", + "through": "~2.2.0" + }, + "dependencies": { + "chokidar": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-0.8.1.tgz", + "integrity": "sha512-Bl/CteHnM5g3eKGPMkraZQW7Yzk2Gu87eE3jdaMfCNJP79sVa54M5KHStr3WtJl4vVoVSndVDws6IFLTmMa3Lw==", + "dev": true + }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==", + "dev": true + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", + "dev": true + }, + "nopt": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.1.2.tgz", + "integrity": "sha512-x8vXm7BZ2jE1Txrxh/hO74HTuYZQEbo8edoRcANgdZ4+PCV+pbjd/xdummkmjjC7LU5EjPzlu8zEq/oxWylnKA==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "through": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", + "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", + "dev": true + } + } + }, "beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", @@ -25877,6 +31798,12 @@ "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", "dev": true }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, "body": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", @@ -25945,6 +31872,16 @@ } } }, + "boom": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", + "integrity": "sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==", + "dev": true, + "optional": true, + "requires": { + "hoek": "0.9.x" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -25964,12 +31901,518 @@ "fill-range": "^7.0.1" } }, + "brfs": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-0.0.9.tgz", + "integrity": "sha512-5bjo0XG6pPGTFJsS4rtvP1vvwLp3UstdF062l10RKcfG60+izXak0DFcfQwMtBQNGlFm588mM2WvD02hJErVYg==", + "dev": true, + "requires": { + "escodegen": "0.0.17", + "falafel": "~0.1.6", + "through": "~2.2.0" + }, + "dependencies": { + "escodegen": { + "version": "0.0.17", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-0.0.17.tgz", + "integrity": "sha512-muX87X0L2dvVJ4ZPKAJLQlcyg2qhl6ps8Ow8vOAcuoFIrZLtXNMGfjnD19LSTrZ1SBHQsI+tvD8YlsJqHhfXrw==", + "dev": true, + "requires": { + "esprima": "~1.0.2", + "estraverse": "~0.0.4", + "source-map": ">= 0.1.2" + } + }, + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", + "dev": true + }, + "estraverse": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-0.0.4.tgz", + "integrity": "sha512-21DfBCsFJGb3HZr0vEBH1Wk1tGSbbzA8I/xtSSoy/pRtupHv0OgBmObcNGXM3ec6/pOXTOOUYY9/5bfluzz0sw==", + "dev": true + }, + "through": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", + "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", + "dev": true + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "browser-pack": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-3.2.0.tgz", + "integrity": "sha512-BHla5EbbxjNyLMFUMamVjeTY+q1QwHbrYNXlWOkw71QcBqAQF7maJyNh3OI/V0d5YyNdMYD6tiPhJB9ukBo99Q==", + "dev": true, + "requires": { + "combine-source-map": "~0.3.0", + "concat-stream": "~1.4.1", + "defined": "~0.0.0", + "JSONStream": "~0.8.4", + "through2": "~0.5.1", + "umd": "^2.1.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", + "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.9", + "typedarray": "~0.0.5" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", + "integrity": "sha512-zexCrAOTbjkBCXGyozn7hhS3aEaqdrc59mAD2E3dKYzV1vFuEGQ1hEDJN2oQMQFwy4he2zyLqPZV+AlfS8ZWJA==", + "dev": true, + "requires": { + "readable-stream": "~1.0.17", + "xtend": "~3.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + } + } + }, + "xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", + "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": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + } + } + }, "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": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-8.1.3.tgz", + "integrity": "sha512-0KKOkCQXCvP64qm73CtESE92pVnB5MkjA2W/Tmf+S4uPHVY4/SeCwO7wdr4mkke5ySoVyMqsOcMa5zo6uh9c9A==", + "dev": true, + "requires": { + "assert": "~1.3.0", + "browser-pack": "^3.2.0", + "browser-resolve": "^1.3.0", + "browserify-zlib": "~0.1.2", + "buffer": "^3.0.0", + "builtins": "~0.0.3", + "commondir": "0.0.1", + "concat-stream": "~1.4.1", + "console-browserify": "^1.1.0", + "constants-browserify": "~0.0.1", + "crypto-browserify": "^3.0.0", + "deep-equal": "~0.2.1", + "defined": "~0.0.0", + "deps-sort": "^1.3.5", + "domain-browser": "~1.1.0", + "duplexer2": "~0.0.2", + "events": "~1.0.0", + "glob": "^4.0.5", + "http-browserify": "^1.4.0", + "https-browserify": "~0.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^6.2.0", + "isarray": "0.0.1", + "JSONStream": "~0.8.3", + "labeled-stream-splicer": "^1.0.0", + "module-deps": "^3.6.3", + "os-browserify": "~0.1.1", + "parents": "^1.0.1", + "path-browserify": "~0.0.0", + "process": "^0.10.0", + "punycode": "~1.2.3", + "querystring-es3": "~0.2.0", + "readable-stream": "^1.0.33-1", + "resolve": "~0.7.1", + "shallow-copy": "0.0.1", + "shasum": "^1.0.0", + "shell-quote": "~0.0.1", + "stream-browserify": "^1.0.0", + "string_decoder": "~0.10.0", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^1.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "~0.0.0", + "umd": "~2.1.0", + "url": "~0.10.1", + "util": "~0.10.1", + "vm-browserify": "~0.0.1", + "xtend": "^3.0.0" + }, + "dependencies": { + "assert": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.3.0.tgz", + "integrity": "sha512-5aKcpD+XnHpZ7EGxsuo6uoILNh0rvm0Ypa17GlkrF2CNSPhvdgi3ft9XsL2ajdVOI2I3xuGZnHvlXAeqTZYvXg==", + "dev": true, + "requires": { + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", + "dev": true + }, + "buffer": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.2.tgz", + "integrity": "sha512-c3M77NkHJxS0zx/ErxXhDLr1v3y2MDXPeTJPvLNOaIYJ4ymHBUFQ9EXzt9HYuqAJllMoNb/EZ8hIiulnQFAUuQ==", + "dev": true, + "requires": { + "base64-js": "0.0.8", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + } + } + }, + "commondir": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-0.0.1.tgz", + "integrity": "sha512-Ghe1LmLv3G3c0XJYu+c88MCRIPqWQ67qaqKY1KvuN4uPAjfUj+y4hvcpZ2kCPrjpRNyklW4dpAZZ8a7vOh50tg==", + "dev": true + }, + "concat-stream": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", + "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.9", + "typedarray": "~0.0.5" + } + }, + "deep-equal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", + "integrity": "sha512-FXgye2Jr6oEk01S7gmSrHrPEQ1ontR7wwl+nYiZ8h4SXlHVm0DYda74BIPcHz2s2qPz4+375IcAz1vsWLwddgQ==", + "dev": true + }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "dev": true, + "requires": { + "readable-stream": "~1.1.9" + } + }, + "events": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/events/-/events-1.0.2.tgz", + "integrity": "sha512-XK19KwlDJo8XsceooxNDK1pObtcT44+Xte6V/jQc4a+fHq1qEouThyyX2ePmS0hS8RcCulmRxzg+T8jiLKAFFQ==", + "dev": true + }, + "glob": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", + "integrity": "sha512-I0rTWUKSZKxPSIAIaqhSXTM/DiII6wame+rEC3cFA5Lqmr9YmdL7z6Hj9+bdWtTvoY1Su4/OiMLmb37Y7JzvJQ==", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^2.0.1", + "once": "^1.3.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", + "dev": true, + "requires": { + "brace-expansion": "^1.0.0" + } + }, + "process": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", + "integrity": "sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA==", + "dev": true + }, + "punycode": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.2.4.tgz", + "integrity": "sha512-h/vscxLPvI2l7k/0dFUKZ5I5TgMCJ/Pl+J6rw77PDuQM6UApf/GaRVkjv/YSm2k+fbp7Yw8dxsoe29DolT7h7w==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "resolve": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.7.4.tgz", + "integrity": "sha512-zxmAcifDjKxmUbk7chQdKhDSn8ml08g+MYyU37xhEXBp+N81cfbYsm4e0Gn9jtLbAvbR8w8Ox09xqUZtPuCoeA==", + "dev": true + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "requires": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + }, + "dependencies": { + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + } + } + }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "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": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", + "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" + } + }, + "xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", + "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.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "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.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "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" + } + }, + "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 + } + } + }, + "browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==", + "dev": true, + "requires": { + "pako": "~0.2.0" + } + }, "browserslist": { "version": "4.21.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", @@ -26106,12 +32549,24 @@ "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", "dev": true }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, "buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", "dev": true }, + "builtins": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-0.0.7.tgz", + "integrity": "sha512-T8uCGKc0/2aLVt6omt8JxDRBoWEMkku+wFesxnhxnt4NygVZG99zqxo7ciK8eebszceKamGoUiLdkXCgGQyrQw==", + "dev": true + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -26189,34 +32644,6 @@ "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", "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" - } - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -26226,23 +32653,6 @@ "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", @@ -26273,15 +32683,6 @@ "ansi-regex": "^2.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" - } - }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -26348,6 +32749,12 @@ "get-intrinsic": "^1.0.2" } }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", + "dev": true + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -26360,6 +32767,30 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==", + "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": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==", + "dev": true + } + } + }, + "can-autoplay": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/can-autoplay/-/can-autoplay-3.0.2.tgz", + "integrity": "sha512-Ih6wc7yJB4TylS/mLyAW0Dj5Nh3Gftq/g966TcxgvpNCOzlbqTs85srAq7mwIspo4w8gnLCVVGroyCHfh6l9aA==", + "dev": true + }, "caniuse-lite": { "version": "1.0.30001390", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001390.tgz", @@ -26371,6 +32802,15 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, "ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -26504,6 +32944,16 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "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" + } + }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -26706,6 +33156,34 @@ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, + "combine-source-map": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.3.0.tgz", + "integrity": "sha512-HRKa6g9SC1xd6ifto8ay6SxvyHaaQ50/8NO1ZONXx2hsIF9t/52qXa7Eeivaf5KFOSowK7Nm8TkIL/VC4khdBA==", + "dev": true, + "requires": { + "convert-source-map": "~0.3.0", + "inline-source-map": "~0.3.0", + "source-map": "~0.1.31" + }, + "dependencies": { + "convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha512-+4nRk0k3oEpwUB7/CalD7xE2z4VmtEnnq0GO2IPTkrooTrAhEsWvuLF5iWP1dXrwluki/azwXV1ve7gtYuPldg==", + "dev": true + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -26721,6 +33199,12 @@ "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==", "dev": true }, + "commander": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.0.0.tgz", + "integrity": "sha512-qebjpyeaA/nJ4w3EO2cV2++/zEkccPnjWogzA2rff+Lk8ILI75vULeTmyd4wPxWdKwtP3J+G39IXVZadh0UHyw==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -26793,6 +33277,16 @@ } } }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "connect": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", @@ -26828,6 +33322,18 @@ "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": "0.0.1", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-0.0.1.tgz", + "integrity": "sha512-FL+diDS9AKR5BAA2M+GNk8lnH64tRE3zepTG9hucxc7o04LgCRhkQZhF7u/OKHZT8LLRT+sZEi9qFzXUchq9pA==", + "dev": true + }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -26976,6 +33482,51 @@ } } }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "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", @@ -27001,6 +33552,35 @@ "which": "^2.0.1" } }, + "cryptiles": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", + "integrity": "sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==", + "dev": true, + "optional": true, + "requires": { + "boom": "0.4.x" + } + }, + "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", @@ -27037,6 +33617,31 @@ "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=", "dev": true }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==", + "dev": true, + "requires": { + "through": "X.X.X" + } + }, + "ctype": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", + "integrity": "sha512-T6CEkoSV4q50zW3TlTHMbzy1E5+zlnNcY+yb7tWVYlTwPhx9LpnfAkd4wecpWknDyptp4k97LUZeInlf6jdzBg==", + "dev": true, + "optional": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", + "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", @@ -27111,6 +33716,12 @@ } } }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", + "dev": true + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -27249,23 +33860,103 @@ "isobject": "^3.0.1" } }, - "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=" - }, + "defined": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", + "integrity": "sha512-zpqiCT8bODLu3QSmLLic8xJnYWBFjOSu/fBCm189oAiTtPq/PSanNACKZDS7kgSyCJY7P+IcODzlIogBK/9RBg==", + "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=" + }, + "deps-sort": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-1.3.9.tgz", + "integrity": "sha512-aEnmQuu/Hf5h8akL8QshYWzk9MVBg/JYMyNq/Lz68i69nR17tunjP6o/AC6Tn48c8ayzG6aeKs6OoFOtVCtvrQ==", + "dev": true, + "requires": { + "JSONStream": "^1.0.3", + "shasum": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "requires": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, "dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "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", @@ -27289,6 +33980,30 @@ "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" + }, + "dependencies": { + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true + }, + "defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "dev": true + } + } + }, "devtools": { "version": "7.16.16", "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", @@ -27330,6 +34045,16 @@ "integrity": "sha512-myh3hSFp0YWa2GED11PmbLhV4dv9RdO7YUz27XJrbQLnP5bMbZL6dfOOILTHO57yH0kX5GfuOZBsg/4NamfPvQ==", "dev": true }, + "dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", @@ -27348,6 +34073,25 @@ "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", "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.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, "dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -27517,6 +34261,18 @@ "void-elements": "^2.0.0" } }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "domain-browser": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha512-fJ5MoHxe69h3E4/lJtFRhcWwLb04bhIBSfvCEMS1YDH+/9yEZTqBHTSTgch8nCP5tE5k2gdQEjodUqJzy7qJ9Q==", + "dev": true + }, "dset": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz", @@ -27638,6 +34394,29 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.243.tgz", "integrity": "sha512-BgLD2gBX43OSXwlT01oYRRD5NIB4n3okTRxkzEAC6G0SZG4TTlyrWMjbOo0fajCwqwpRtMHXQNMjtRN6qpNtfw==" }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -27716,6 +34495,12 @@ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", "dev": true }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true + }, "errno": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", @@ -27805,9 +34590,9 @@ } }, "es5-ext": { - "version": "0.10.57", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.57.tgz", - "integrity": "sha512-L7cCNoPwTkAp7IBHxrKLsh7NKiVFkcdxlP9vbVw9QUvb7gF0Mz9bEBN0WY9xqdTjGF907EMT/iG013vnbqwu1Q==", + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", "dev": true, "requires": { "es6-iterator": "^2.0.3", @@ -27832,6 +34617,20 @@ "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": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", + "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-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", @@ -27853,6 +34652,28 @@ "es6-promise": "^4.0.3" } }, + "es6-set": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", + "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "es6-iterator": "~2.0.3", + "es6-symbol": "^3.1.3", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + } + } + }, "es6-symbol": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", @@ -27960,6 +34781,18 @@ } } }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==", + "dev": true, + "requires": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, "eslint": { "version": "7.32.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", @@ -28017,224 +34850,1008 @@ "@babel/highlight": "^7.10.4" } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "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-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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 + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "globals": { + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-config-standard": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", + "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "dev": true, + "requires": {} + }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.25.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", + "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.2", + "has": "^1.0.3", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.12.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + } + } + }, + "eslint-plugin-prebid": { + "version": "file:plugins/eslint", + "requires": { + "beefy": "^1.0.0", + "brfs": "0.0.9", + "browserify": "^8.1.3", + "chai": "^1.9.1", + "chalk": "^1.0.0", + "concat-stream": "^1.4.6", + "coveralls": "2.11.2", + "dateformat": "^1.0.8", + "debug": "^2.1.1", + "doctrine": "^0.6.2", + "escape-string-regexp": "^1.0.2", + "escope": "^3.2.0", + "espree": "^2.2.0", + "esprima": "^2.4.1", + "esprima-fb": "^10001.1.0-dev-harmony-fb", + "estraverse": "^4.1.0", + "estraverse-fb": "^1.3.1", + "gh-got": "^1.0.3", + "globals": "^8.2.0", + "inquirer": "^0.8.2", + "is-my-json-valid": "^2.10.0", + "istanbul": "^0.3.5", + "js-yaml": "^3.2.5", + "jsdoc": "^3.3.0-beta1", + "jsonlint": "^1.6.2", + "lodash.clonedeep": "^3.0.1", + "lodash.merge": "^3.3.2", + "lodash.omit": "^3.1.0", + "markdownlint": "^0.0.6", + "minimatch": "^2.0.1", + "mkdirp": "^0.5.0", + "mocha": "^2.1.0", + "mocha-phantomjs": "3.6.0", + "npm-license": "^0.2.3", + "object-assign": "^2.0.0", + "optionator": "^0.5.0", + "path-is-absolute": "^1.0.0", + "path-is-inside": "^1.0.1", + "phantomjs": "1.9.7-15", + "proxyquire": "^1.0.0", + "rewire": "^2.3.4", + "semver": "^4.1.0", + "shelljs": "^0.3.0", + "shelljs-nodecli": "~0.1.0", + "sinon": "1.14.1", + "strip-json-comments": "~1.0.1", + "text-table": "~0.2.0", + "through": "^2.3.6", + "user-home": "^1.0.0", + "xml-escape": "~1.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true + }, + "argparse": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", + "integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==", + "dev": true, + "requires": { + "underscore": "~1.7.0", + "underscore.string": "~2.4.0" + } + }, + "asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", + "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", + "dev": true, + "optional": true + }, + "assertion-error": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.0.tgz", + "integrity": "sha512-g/gZV+G476cnmtYI+Ko9d5khxSoCSoom/EaNmmCfwpOvBXEJ18qwFrxfP1/CsIqk2no1sAKKwxndV0tP7ROOFQ==", + "dev": true + }, + "aws-sign2": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", + "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", + "dev": true, + "optional": true + }, + "chai": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-1.10.0.tgz", + "integrity": "sha512-E3L9M2SeQU1XagJkE9KJyTAXXHKJkJ1EsKkFp0Rl53lYa3mro2PVgYHNiCb2YRa2nUeyg7aqmI1EIcSBayNd5w==", + "dev": true, + "requires": { + "assertion-error": "1.0.0", + "deep-eql": "0.1.3" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "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" + } + }, + "cli-width": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz", + "integrity": "sha512-eMU2akIeEIkCxGXUNmDnJq1KzOIiPnJ+rKqRe6hcxE3vIOPvpMrBYOn/Bl7zNlYJj/zQxXquAnozHUCf9Whnsg==", + "dev": true + }, + "combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", + "dev": true, + "optional": true, + "requires": { + "delayed-stream": "0.0.5" + } + }, + "commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha512-CD452fnk0jQyk3NfnK+KkR/hUPoHt5pVaKHogtyyv3N0U4QfAal9W0/rXLOg/vVZgQKa7jdtXypKs1YAip11uQ==", + "dev": true + }, + "coveralls": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.11.2.tgz", + "integrity": "sha512-+OK2imSCDXSYaOyAxGVUmzDfDtCYLW+gtdDVpjvq99R5Dyry4Puj3EQ/4YnsxNc6RHsuhx3wIkHSBIRaJZY5YQ==", + "dev": true, + "requires": { + "js-yaml": "3.0.1", + "lcov-parse": "0.0.6", + "log-driver": "1.2.4", + "request": "2.40.0" + }, + "dependencies": { + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", + "dev": true + }, + "js-yaml": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.0.1.tgz", + "integrity": "sha512-dgxgLzZS9qLWAQd/wrVG8tOiRSBJq1Ss9gbd7+fdBhcia3efHjLLpPkcUhKOyVACxTEAgnao3RT1kj1otiW42g==", + "dev": true, + "requires": { + "argparse": "~ 0.1.11", + "esprima": "~ 1.0.2" + } + } + } + }, + "dateformat": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha512-5sFRfAAmbHdIts+eKjR9kYJoF0ViCMVX9yqLu5A7S/v+nd077KgCITOMiirmyCBiZpKLDXbBOkYm6tu7rX/TKg==", + "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==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha512-6sEotTRGBFiNcqVoeHwnfopbSpi5NbH1VWJmYCVkmxMmaVTT0bUTrNaGyBwhgP4MZL012W/mkzIn3Da+iDYweg==", + "dev": true, + "requires": { + "type-detect": "0.1.1" + } + }, + "delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", + "dev": true, + "optional": true + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha512-VzVc42hMZbYU9Sx/ltb7KYuQ6pqAw+cbFWVy4XKdkuEL2CFaRLGEnISPs7YdzaUGpi+CpIqvRmu7hPQ4T7EQ5w==", + "dev": true + }, + "doctrine": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz", + "integrity": "sha512-FSGvDB23RFdm/Z2hEINXN1AcBW5I4YBqpGD/lScJV34vuOwrPFyLHN9bwCzLa6lUmqS6ipdp5XlVJRQ6yJ5iSA==", + "dev": true, + "requires": { + "esutils": "^1.1.6", + "isarray": "0.0.1" + } + }, + "escodegen": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz", + "integrity": "sha512-2cd7+JUtUEmZVpGmfF9r+uRYXswJAkf85Ce8GvdBa7hSvdjY8hGo+rwC5syAgYzqHpfxNJzLntFjw6879yPbgQ==", + "dev": true, + "requires": { + "esprima": "^1.2.2", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.5.0", + "source-map": "~0.2.0" + }, + "dependencies": { + "esprima": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", + "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "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 + } + } + }, + "espree": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz", + "integrity": "sha512-HWJpgkL44cbjWiOTC9Pm34RZE57H1g9V4Ln9U14TUtiywFTLMMpMCtmQK5rkjbGBXigQT8bS3r45+Dt5+m0SZg==", + "dev": true + }, + "esprima": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz", + "integrity": "sha512-uM6hfS0/8ybNIj8SGRMdidPJy5uhWqWN/GIkyqnMAbCSL44yfFGLuBpRRCgOpBXBZt2OymQuM+IfahkqJq3DWw==", + "dev": true + }, + "esutils": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", + "integrity": "sha512-RG1ZkUT7iFJG9LSHr7KDuuMSlujfeTtMNIcInURxKAxhMtwQhI3NrQhz26gZQYlsYZQKzsnwtpKrFKj9K9Qu1A==", + "dev": true + }, + "fast-levenshtein": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz", + "integrity": "sha512-hYsfI0s4lfQ2rHVFKXwAr/L/ZSbq9TZwgXtZqW7ANcn9o9GKvcbWxOnxx7jykXf/Ezv1V8TvaBEKcGK7DWKX5A==", + "dev": true + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + } + } + }, + "forever-agent": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==", + "dev": true + }, + "form-data": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", + "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", + "dev": true, + "optional": true, + "requires": { + "async": "~0.9.0", + "combined-stream": "~0.0.4", + "mime": "~1.2.11" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==", + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==", + "dev": true, + "requires": { + "inherits": "2", + "minimatch": "0.3" + }, + "dependencies": { + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA==", + "dev": true, + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + } + } + }, + "globals": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz", + "integrity": "sha512-IHCTKEGo42ICEkTZBADyl4HX06hVdFF4qdJdqOgaBe5X8RE1/MrvubetsEtGTcwjs46djFq0Gc3+5RgTsc3UoQ==", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha512-RTBwDHhNuOx4F0hqzItc/siXCasGfC4DeWcBamclWd+6jWtBaeB/SGbMkGf0eiQoW7ib8JpvOgnUsmgMHI3Mfw==", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true + }, + "http-signature": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", + "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", + "dev": true, + "optional": true, + "requires": { + "asn1": "0.1.11", + "assert-plus": "^0.1.5", + "ctype": "0.5.3" + } + }, + "inquirer": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz", + "integrity": "sha512-+rksrtdqQ8do7yOsmP5YIgbSdbZYuCIrnfH5vjFYGAr1XgJpMksb3rFZMJ3jiKuUyDVEA4MVDYbkA3ribJn3Tg==", + "dev": true, + "requires": { + "ansi-regex": "^1.1.1", + "chalk": "^1.0.0", + "cli-width": "^1.0.1", + "figures": "^1.3.5", + "lodash": "^3.3.1", + "readline2": "^0.1.1", + "rx": "^2.4.3", + "through": "^2.3.6" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "istanbul": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz", + "integrity": "sha512-8H/jxiee2UqX/mviKkPoKQYMxU2t995FC5PwO4zjWeDPOozjoeKqxEyN62l9o5+UgzvYQbrKgQjjxhGON8FcMg==", + "dev": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.7.x", + "esprima": "2.5.x", + "fileset": "0.2.x", + "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": { + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "lcov-parse": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.6.tgz", + "integrity": "sha512-chuBQJZiBq28YUM6Yr3tf3h5Lxhb+DvhbxxSNpsHURSXiZXOzp49phiWG2pKHboOehJDujivwNQGRP8mAErMvQ==", + "dev": true + }, + "levn": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz", + "integrity": "sha512-mvp+NO++YH0B+e8cC/SvJxk6k5Z9Ngd3iXuz7tmT8vZCyQZj/5SI1GkFOiZGGPkm5wWGI9SUrqiAfPq7BJH+0w==", "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" + "prelude-ls": "~1.1.0", + "type-check": "~0.3.1" } }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==", + "dev": true + }, + "lodash.clonedeep": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", + "integrity": "sha512-I8MpGh5z+6OixDAAb21teLSZDmqVPjlq02Q7ZFrbn2xnQHYYuJf6on/94SWpF/p0s3p/cEv/53ro4AhDOfCR0g==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "lodash._baseclone": "^3.0.0", + "lodash._bindcallback": "^3.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "lodash.isplainobject": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz", + "integrity": "sha512-P4wZnho5curNqeEq/x292Pb57e1v+woR7DJ84DURelKB46lby8aDEGVobSaYtzHdQBWQrJSdxcCwjlGOvvdIyg==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "lodash._basefor": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.keysin": "^3.0.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==", + "lodash.merge": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz", + "integrity": "sha512-ZgGZpRhWLjivGUbjtApZR4HyLv/UAyoYqESVYkK4aLBJVHRrbFpG+GNnE9JPijliME4LkKM0SFI/WyOiBiv1+w==", "dev": true, "requires": { - "color-name": "~1.1.4" + "lodash._arraycopy": "^3.0.0", + "lodash._arrayeach": "^3.0.0", + "lodash._createassigner": "^3.0.0", + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0", + "lodash.isplainobject": "^3.0.0", + "lodash.istypedarray": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.keysin": "^3.0.0", + "lodash.toplainobject": "^3.0.0" } }, - "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==", + "log-driver": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.4.tgz", + "integrity": "sha512-QmyGbAcBbHk8ysCGtT6FQ+LZML6+EeT0NdotCJGu72kNhknXtdso1G/NI0r7j45whFYNTU15XMW+JGOvGX07QQ==", "dev": true }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "lolex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.1.0.tgz", + "integrity": "sha512-wGZrF3AlAWxG2j+6NyyttZ/UVxW8o/F+q01IUGuf2PiEIAUG9av/vpBS5TQHTQtzPmPJB4CZWjwyGR4C4aX83w==", "dev": true }, - "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==", + "dev": true + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", + "dev": true, + "optional": true + }, + "mime-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz", + "integrity": "sha512-echfutj/t5SoTL4WZpqjA1DCud1XO0WQF3/GJ48YBmc4ZMhCK77QA6Z/w6VTQERLKuJ4drze3kw2TUT8xZXVNw==", + "dev": true + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", "dev": true, "requires": { - "type-fest": "^0.20.2" + "brace-expansion": "^1.0.0" } }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "minimist": "^1.2.6" } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "mocha": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", + "integrity": "sha512-jNt2iEk9FPmZLzL+sm4FNyOIDYXf2wUU6L4Cc8OIKK/kzgMHKPi4YhTZqG4bW4kQVdIv6wutDybRhXfdnujA1Q==", + "dev": true, + "requires": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.11", + "growl": "1.9.2", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0", + "to-iso-string": "0.0.2" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha512-X0rGvJcskG1c3TgSCPqHJ0XJgwlcvOC7elJ5Y0hYuKBZoVqWpAMfLOeIh2UI/DCQ5ruodIjvsugZtjUYUw2pUw==", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha512-cQpUid7bdTUnFin8S7BnNdOk+/eDqQmKgCANSyd/jAhrKEvxUvr9VQ8XZzXiOtest8NLfk3FSBZzwvemZNQ6Vg==", + "dev": true + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha512-lRLiIR9fSNpnP6TC4v8+4OU7oStC01esuNowdQ34L+Gk8e5Puoc88IqJ+XAY/B3Mn2ZKis8l8HX90oU8ivzUHg==", + "dev": true + }, + "supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha512-mS5xsnjTh5b7f2DM6bch6lR582UCOTphzINlZnDsfpIRrwI6r58rb6YSSGsdexkm8qw2bBVO2ID2fnJOTuLiPA==", + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "oauth-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", + "dev": true, + "optional": true + }, + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha512-CdsOUYIh5wIiozhJ3rLQgmUTgcyzFwZZrqhkKhODMoGtPKM+wt0h0CNIoauJWMsS9822EdzPsF/6mb4nLvPN5g==", + "dev": true + }, + "optionator": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", + "integrity": "sha512-jUr7aBk/kCInAEsl+qxuw4ORpe458atDKXNLhyvPUD4NfnsJsbAViX1b9nb/0rS62lO8cIFd1VoiaXLQ+MybOw==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "deep-is": "~0.1.2", + "fast-levenshtein": "~1.0.0", + "levn": "~0.2.5", + "prelude-ls": "~1.1.1", + "type-check": "~0.3.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "dev": true + } } }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "dev": true - } - } - }, - "eslint-config-standard": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", - "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", - "dev": true, - "requires": {} - }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + }, + "qs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz", + "integrity": "sha512-tHuOP9TN/1VmDM/ylApGK1QF3PSIP8I6bHDEfoKNQeViREQ/sfu1bAUrA1hoDun8p8Tpm7jcsz47g+3PiGoYdg==", + "dev": true + }, + "request": { + "version": "2.40.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz", + "integrity": "sha512-waNoGB4Z7bPn+lgqPk7l7hhze4Vd68jKccnwLeS7vr9GMxz0iWQbYTbBNWzfIk87Urx7V44pu29qjF/omej+Fw==", "dev": true, "requires": { - "ms": "^2.1.1" + "aws-sign2": "~0.5.0", + "forever-agent": "~0.5.0", + "form-data": "~0.1.0", + "hawk": "1.1.1", + "http-signature": "~0.10.0", + "json-stringify-safe": "~5.0.0", + "mime-types": "~1.0.1", + "node-uuid": "~1.4.0", + "oauth-sign": "~0.3.0", + "qs": "~1.0.0", + "stringstream": "~0.0.4", + "tough-cookie": ">=0.12.0", + "tunnel-agent": "~0.4.0" } - } - } - }, - "eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", + "dev": true + }, + "sinon": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.14.1.tgz", + "integrity": "sha512-cysrMyrriLwSn5Ye82xTCAVVS6Q6XLxlZE3jtPb4IFng2npN3lQWQ5Uyaud6cRpzztbEy2sbJkrDSbIl6OKUCA==", "dev": true, "requires": { - "ms": "^2.1.1" + "formatio": "1.1.1", + "lolex": "1.1.0", + "util": ">=0.10.3 <1" } - } - } - }, - "eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", - "dev": true, - "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - } - }, - "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", - "dev": true, - "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", - "has": "^1.0.3", - "is-core-module": "^2.8.0", - "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", "dev": true, + "optional": true, "requires": { - "ms": "2.0.0" + "amdefine": ">=0.0.4" } }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { - "esutils": "^2.0.2" + "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": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + } } }, - "ms": { + "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true - } - } - }, - "eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, - "requires": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "dependencies": { - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha512-5rqszGVwYgBoDkIm2oUtvkfZMQ0vk29iDMU0W2qCa3rG0vPDNczCMT4hV/bLBgLg8k8ri6+u3Zbt+S/14eMzlA==", + "dev": true + }, + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==", "dev": true + }, + "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" + } } } }, - "eslint-plugin-prebid": { - "version": "file:plugins/eslint" - }, "eslint-plugin-promise": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz", @@ -28307,6 +35924,12 @@ "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", "dev": true }, + "esprima-fb": { + "version": "10001.1.0-dev-harmony-fb", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-10001.1.0-dev-harmony-fb.tgz", + "integrity": "sha512-z2dx3A/ZGNamsDjJS4FZPXnpoRCEkQXqouKBCOaJifyx4HkEVoSQ3YWFX18Scut1Aq9gnctzLWcWJgKkL0xNQw==", + "dev": true + }, "esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", @@ -28347,6 +35970,13 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, + "estraverse-fb": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.2.tgz", + "integrity": "sha512-wp3lfRrWy5EQD9TqesuYM1SKVP4ERT0cUatb4e8Vznf4K5IOpREhuyXZxGj3a9s9mvX5vGZKNHA4R9D4kp9Q9A==", + "dev": true, + "requires": {} + }, "estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -28409,6 +36039,16 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "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" + } + }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -28814,6 +36454,23 @@ "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", "dev": true }, + "falafel": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-0.1.6.tgz", + "integrity": "sha512-r1s3VwKzm6PB35MZmnfZoF6NTgSKRxf8How2lBsrDq81OsYXb/2fR8ysfURHCTlFpqJDQVA88iB70wFrFRYDsA==", + "dev": true, + "requires": { + "esprima": "~1.0.2" + }, + "dependencies": { + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", + "dev": true + } + } + }, "fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", @@ -28925,6 +36582,50 @@ } } }, + "fileset": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", + "integrity": "sha512-aK3PFyHSwWsBJCarRxMRIXSGamfroi9ehG8f4e5A2n5nSlEVHe8y44jNTIN4+HdZSpK3FNV0EdihH1iDWTdnGg==", + "dev": true, + "requires": { + "glob": "5.x", + "minimatch": "2.x" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", + "dev": true, + "requires": { + "brace-expansion": "^1.0.0" + } + } + } + }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA==", + "dev": true, + "requires": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -29113,6 +36814,23 @@ "mime-types": "^2.1.12" } }, + "formatio": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", + "integrity": "sha512-cPh7is6k3d8tIUh+pnXXuAbD/uhSXGgqLPw0UrYpv5lfdJ+MMMSjx40JNpqP7Top9Nt25YomWEiRmkHbOvkCaA==", + "dev": true, + "requires": { + "samsam": "~1.1" + }, + "dependencies": { + "samsam": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.3.tgz", + "integrity": "sha512-t9rCPskf50hZ53eH8Z+cSWD4LfJBac+8vSSuzi1Y2HzygyXxtAl0BaR3hr6iI6A+nFQbkmJNC/brQLNEeVnrmg==", + "dev": true + } + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -29292,6 +37010,24 @@ "globule": "^1.0.0" } }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dev": true, + "requires": { + "is-property": "^1.0.2" + } + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", + "dev": true, + "requires": { + "is-property": "^1.0.0" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -29331,6 +37067,12 @@ "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", "dev": true }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", + "dev": true + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -29365,6 +37107,68 @@ "assert-plus": "^1.0.0" } }, + "gh-got": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-1.1.0.tgz", + "integrity": "sha512-jo4rP5ugI6fZGjS0vmvHlM8P7EBA39p8to4r2i+LqYXxeg4M8qnPXiKaetDfH0YLXkO9Hfsa2mKIjMsGJwcdGQ==", + "dev": true, + "requires": { + "got": "^3.2.0", + "object-assign": "^2.0.0" + }, + "dependencies": { + "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" + } + }, + "got": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/got/-/got-3.3.1.tgz", + "integrity": "sha512-7chPlc0pWHjvq7B6dEEXz4GphoDupOvBSSl6AwRsAJX7GPTZ+bturaZiIigX4Dp6KrAP67nvzuKkNc0SLA0DKg==", + "dev": true, + "requires": { + "duplexify": "^3.2.0", + "infinity-agent": "^2.0.0", + "is-redirect": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "nested-error-stacks": "^1.0.0", + "object-assign": "^3.0.0", + "prepend-http": "^1.0.0", + "read-all-stream": "^3.0.0", + "timed-out": "^2.0.0" + }, + "dependencies": { + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", + "dev": true + } + } + }, + "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 + }, + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha512-CdsOUYIh5wIiozhJ3rLQgmUTgcyzFwZZrqhkKhODMoGtPKM+wt0h0CNIoauJWMsS9822EdzPsF/6mb4nLvPN5g==", + "dev": true + } + } + }, "git-up": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/git-up/-/git-up-6.0.0.tgz", @@ -29390,6 +37194,18 @@ "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==", "dev": true }, + "github-url-from-git": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-url-from-git/-/github-url-from-git-1.5.0.tgz", + "integrity": "sha512-WWOec4aRI7YAykQ9+BHmzjyNlkfJFG8QLXnDTsLz/kZefq7qkzdfo4p6fkYYMIq1aj+gZcQs/1HQhQh3DPPxlQ==", + "dev": true + }, + "github-url-from-username-repo": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/github-url-from-username-repo/-/github-url-from-username-repo-1.0.2.tgz", + "integrity": "sha512-Tj8CQqRoFVTglGdQ8FQmfq8gOOoOYZX7tnOKP8jq8Hdz2OTDhxvtlkLAbrqMYZ7X/YdaYQoUG1IBWxISBfqZ+Q==", + "dev": true + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -29629,6 +37445,16 @@ } } }, + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", @@ -29936,28 +37762,6 @@ "number-is-nan": "^1.0.0" } }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "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", @@ -29967,23 +37771,6 @@ "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", @@ -30031,15 +37818,6 @@ "ansi-regex": "^2.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" - } - }, "which-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", @@ -30552,6 +38330,12 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -30915,17 +38699,6 @@ "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", @@ -31097,6 +38870,12 @@ "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", "dev": true }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha512-kaNz5OTAYYmt646Hkqw50/qyxP2vFnTVu5AQ1Zmk22Kk5+4Qx6BpO8+u7IKsML5fOsFk0ZT0AcCJNYwcvaLBvw==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -31164,6 +38943,46 @@ } } }, + "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": { + "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" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "hast-util-is-element": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz", @@ -31207,6 +39026,19 @@ "integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==", "dev": true }, + "hawk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", + "integrity": "sha512-am8sVA2bCJIw8fuuVcKvmmNnGFUGW8spTkVtj2fXTEZVkfN42bwFZFtDem57eFi+NSxurJB8EQ7Jd3uCHLn8Vw==", + "dev": true, + "optional": true, + "requires": { + "boom": "0.4.x", + "cryptiles": "0.2.x", + "hoek": "0.9.x", + "sntp": "0.2.x" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -31219,6 +39051,24 @@ "integrity": "sha512-ig1eqDzJaB0pqEvlPVIpSSyMaO92bH1N2rJpLMN/nX396wTpDA4Eq0uK+7I/2XG17pFaaKE0kjV/XPeGt7Evjw==", "dev": true }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoek": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==", + "dev": true, + "optional": true + }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -31250,12 +39100,158 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "html-select": { + "version": "2.3.24", + "resolved": "https://registry.npmjs.org/html-select/-/html-select-2.3.24.tgz", + "integrity": "sha512-kQ+YZoVQ8Aux6bUqMVc0iufcZOv03+xYZ4J5v2beT5wkNrW/e2roZ8pnU4LunVOVBGFkbodFKR0TvuMkTdyrJQ==", + "dev": true, + "requires": { + "cssauron": "^1.1.0", + "duplexer2": "~0.0.2", + "inherits": "^2.0.1", + "minimist": "~0.0.8", + "readable-stream": "^1.0.27-1", + "split": "~0.3.0", + "stream-splicer": "^1.2.0", + "through2": "^1.0.0" + }, + "dependencies": { + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "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": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "requires": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, + "html-tokenize": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-1.2.5.tgz", + "integrity": "sha512-7sCme3w9Hiv/kfL6sO6ePTGAV5fY6P7WDZyOs0zfXXU8vsS1ps1CQfGe0J1yuAdcCnOJ9h66RLYX/e9Cife8yw==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "minimist": "~0.0.8", + "readable-stream": "~1.0.27-1", + "through2": "~0.4.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", + "dev": true + }, + "object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", + "integrity": "sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==", + "dev": true, + "requires": { + "readable-stream": "~1.0.17", + "xtend": "~2.1.1" + } + }, + "xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", + "dev": true, + "requires": { + "object-keys": "~0.4.0" + } + } + } + }, "html-void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==", "dev": true }, + "http-browserify": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz", + "integrity": "sha512-Irf/LJXmE3cBzU1eaR4+NEX6bmVLqt1wkmDiA7kBwH7zmb0D8kBAXsDmQ88hhj/qv9iEZKlyGx/hrMcFi8sOHw==", + "dev": true, + "requires": { + "Base64": "~0.2.0", + "inherits": "~2.0.1" + } + }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -31312,6 +39308,12 @@ "resolve-alpn": "^1.0.0" } }, + "https-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", + "integrity": "sha512-EjDQFbgJr1vDD/175UJeSX3ncQ3+RUnCL5NkthQGHvF4VNHlzTy8ifJfTqz47qiPRqaFH58+CbuG3x51WuB1XQ==", + "dev": true + }, "https-proxy-agent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", @@ -31342,6 +39344,12 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "ignorepatterns": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignorepatterns/-/ignorepatterns-1.0.1.tgz", + "integrity": "sha512-9bm+Wivwyocr88go3y04hpX3qdFs6EgsxrjjpcI9C2GAqxcWYVMJaS9h9KL8ftJk1xP/8NzPxfHk6K1X7p0CRQ==", + "dev": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -31366,6 +39374,33 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==", + "dev": true + }, + "individual": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz", + "integrity": "sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g==", + "dev": true + }, + "infinity-agent": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz", + "integrity": "sha512-CnfUJe5o2S9aAQWXGMhDZI4UL39MAJV3guOTfHHIdos4tuVHkl1j/J+1XLQn+CLIvqcpgQR/p+xXYXzcrhCe5w==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -31387,6 +39422,26 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "inline-source-map": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.3.1.tgz", + "integrity": "sha512-RNlldBXZ7BBcVm3HjXIXiwKxih1lnuKbzeLBRDSB/qaqk8/g4JEZBjxpBQMhqEthQyGv7ycu8r/8PKGgBdIqrA==", + "dev": true, + "requires": { + "source-map": "~0.3.0" + }, + "dependencies": { + "source-map": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz", + "integrity": "sha512-jz8leTIGS8+qJywWiO9mKza0hJxexdeIYXhDHw9avTQcXSNAGk3hiiRMpmI2Qf9dOrZDrDpgH9VNefzuacWC9A==", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, "inquirer": { "version": "8.1.5", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", @@ -31454,6 +39509,127 @@ } } }, + "insert-module-globals": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-6.6.3.tgz", + "integrity": "sha512-ryk8hTKUZCc300SPOOwx30WhE5oRUssPDVlIoO8vtoMNBy5HGeesVRl3HF7ra4ll42T0IdnwD9XR9svh6+RRhg==", + "dev": true, + "requires": { + "combine-source-map": "~0.6.1", + "concat-stream": "~1.4.1", + "is-buffer": "^1.1.0", + "JSONStream": "^1.0.3", + "lexical-scope": "^1.2.0", + "process": "~0.11.0", + "through2": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "combine-source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.6.1.tgz", + "integrity": "sha512-XKRNtuZRlVDTuSGKsfZpXYz80y0XDbYS4a+FzafTgmYHy/ckruFBx7Nd6WaQnFHVI3O6IseWVdXUvZutMpjSkQ==", + "dev": true, + "requires": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.5.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.4.2" + } + }, + "concat-stream": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", + "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.9", + "typedarray": "~0.0.5" + } + }, + "convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", + "dev": true + }, + "inline-source-map": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.5.0.tgz", + "integrity": "sha512-2WtHG0qX9OH9TVcxsLVfq3Tzr+qtL6PtWgoh0XAAKe4KkdA/57Q+OGJuRJHA4mZ2OZnkJ/ZAaXf9krLB12/nIg==", + "dev": true, + "requires": { + "source-map": "~0.4.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 + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha512-Y8nIfcb1s/7DcobUz1yOO1GSp7gyL+D9zLHDehT7iRESqGSxjJ448Sg7rvfgsRJCnKLdSl11uGf0s9X80cH0/A==", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "requires": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, "internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -31671,6 +39847,12 @@ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, + "is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, "is-generator-function": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", @@ -31701,6 +39883,25 @@ "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", "dev": true }, + "is-my-ip-valid": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", + "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", + "dev": true + }, + "is-my-json-valid": { + "version": "2.20.6", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", + "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", + "dev": true, + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^5.0.0", + "xtend": "^4.0.0" + } + }, "is-nan": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", @@ -31758,6 +39959,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", + "dev": true + }, "is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -31776,6 +39983,18 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "dev": true + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==", + "dev": true + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -32105,6 +40324,30 @@ "textextensions": "^3.2.0" } }, + "jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha512-mkk3vzUHFjzKjpCXeu+IjXeZD+QOTjUUdubgmHtHTDwvAO2ZTkMTTVrapts5CWz3JvJryh/4KWZpjeZrCepZ3A==", + "dev": true, + "requires": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "dependencies": { + "commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha512-0fLycpl1UMTGX257hRsu/arL/cUbcvQM4zMKwvLvzXtfdezIV4yotPS2dYtknF+NmEfWSoCEF6+hj9XLm/6hEw==", + "dev": true + }, + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==", + "dev": true + } + } + }, "jake": { "version": "10.8.5", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", @@ -32371,6 +40614,12 @@ "supports-color": "^8.0.0" } }, + "jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -32394,12 +40643,64 @@ } } }, + "js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "requires": { + "xmlcreate": "^2.0.4" + } + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, + "jsdoc": { + "version": "3.6.11", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.11.tgz", + "integrity": "sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==", + "dev": true, + "requires": { + "@babel/parser": "^7.9.4", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "taffydb": "2.6.2", + "underscore": "~1.13.2" + }, + "dependencies": { + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + } + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -32423,6 +40724,15 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, + "json-parse-helpfulerror": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", + "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==", + "dev": true, + "requires": { + "jju": "^1.1.0" + } + }, "json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -32435,6 +40745,15 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json-stable-stringify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", + "integrity": "sha512-nKtD/Qxm7tWdZqJoldEC7fF0S41v0mWbeaXG3637stOWfyGxTgWTYE2wtfKmjzpvxv2MA2xzxsXOIiwUpkX6Qw==", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, "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", @@ -32462,6 +40781,44 @@ "universalify": "^2.0.0" } }, + "jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true + }, + "jsonlint": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.3.tgz", + "integrity": "sha512-jMVTMzP+7gU/IyC6hvKyWpUU8tmTkK5b3BPNuMI9U8Sit+YAWLlZwB6Y6YrdCxfg2kNz05p3XY3Bmm4m26Nv3A==", + "dev": true, + "requires": { + "JSV": "^4.0.x", + "nomnom": "^1.5.x" + } + }, + "jsonparse": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz", + "integrity": "sha512-fw7Q/8gFR8iSekUi9I+HqWIap6mywuoe7hQIg3buTVjuZgALKj4HAmm0X6f+TaL4c9NJbvyFQdaI2ppr5p6dnQ==", + "dev": true + }, + "jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true + }, + "JSONStream": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz", + "integrity": "sha512-l0NN3IcqrZfZBJp7JWDJIHsnPV7yzJWqsYxQzL8Fwdx1BmEMjLuvtYkv+P9pbvpyfP75/f4MeDZhWNU4is32uA==", + "dev": true, + "requires": { + "jsonparse": "0.0.5", + "through": ">=2.2.7 <3" + } + }, "jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -32474,6 +40831,12 @@ "verror": "1.10.0" } }, + "JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha512-ZJ6wx9xaKJ3yFUhq5/sk82PJMuUyLk277I8mQeyDgCTjGdjWJIvPfaU5LIXaMuaN2UO1X3kZH4+lgphublZUHw==", + "dev": true + }, "just-clone": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", @@ -32830,6 +41193,18 @@ "webpack-merge": "^4.1.5" } }, + "kew": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.1.7.tgz", + "integrity": "sha512-TQRJfHoVm4f2exuRqjcpURhzGcC4GEIPyiLquo4mBfz0JgsVg19VeyTmKp6RKSOIhHQ6F4SgEhsnUlBduGV9Yw==", + "dev": true + }, + "keycode": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.1.tgz", + "integrity": "sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==", + "dev": true + }, "keyv": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.1.1.tgz", @@ -32845,6 +41220,15 @@ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true }, + "klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, "kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -32867,6 +41251,25 @@ "integrity": "sha512-01TBSOqlHmLfcQhHseugGHLxPtU03OyZWaLDWt5MfzCkijG6xWFvAQPhKVn0cR2MMjYvBP9keQ8A3+rQEhLO5g==", "dev": true }, + "labeled-stream-splicer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-1.0.2.tgz", + "integrity": "sha512-3KBjPRnXrYC5h2jEf/d6hO7Lcl+38QzRVTOyHA2sFzZVMYwsUFuejlrOMwAjmz13hVBr9ruDS1RwE4YEz8P58w==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "isarray": "~0.0.1", + "stream-splicer": "^1.1.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + } + } + }, "last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", @@ -32920,6 +41323,15 @@ "type-check": "~0.4.0" } }, + "lexical-scope": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", + "integrity": "sha512-ntJ8IcBCuKwudML7vAuT/L0aIMU0+9vO25K4CjLPYgzf1NZ0bAhJJBZrvkO+oUGgKcbdkH8UZdRsaEg+wULLRw==", + "dev": true, + "requires": { + "astw": "^2.0.0" + } + }, "liftoff": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", @@ -32980,6 +41392,15 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, "listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -33000,6 +41421,45 @@ "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": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "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" + }, + "dependencies": { + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + } + } + }, "loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -33022,12 +41482,87 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash._arraycopy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", + "integrity": "sha512-RHShTDnPKP7aWxlvXKiDT6IX2jCs6YZLCtNhOru/OX2Q/tzX295vVBK5oX1ECtN+2r86S0Ogy8ykP1sgCZAN0A==", + "dev": true + }, + "lodash._arrayeach": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", + "integrity": "sha512-Mn7HidOVcl3mkQtbPsuKR0Fj0N6Q6DQB77CtYncZcJc0bx5qv2q4Gl6a0LC1AN+GSxpnBDNnK3CKEm9XNA4zqQ==", + "dev": true + }, + "lodash._arraymap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz", + "integrity": "sha512-IhRssF2bzQoFQ2Q5H1O52HuJY+OtcHDZekEhaMJ6RkUF+gpLlAsizSRsKp3Ho555ANRk69DFp5b4LOlym4S0bw==", + "dev": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "lodash._baseclone": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", + "integrity": "sha512-1K0dntf2dFQ5my0WoGKkduewR6+pTNaqX03kvs45y7G5bzl4B3kTR4hDfJIc2aCQDeLyQHhS280tc814m1QC1Q==", + "dev": true, + "requires": { + "lodash._arraycopy": "^3.0.0", + "lodash._arrayeach": "^3.0.0", + "lodash._baseassign": "^3.0.0", + "lodash._basefor": "^3.0.0", + "lodash.isarray": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, "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._basedifference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz", + "integrity": "sha512-4BcJlOv36b3v+kHdJWcgsDi96ns8neNLuDtbzzjW3+eh3XhFVmFPH2tu6GJK2e5eRYMQ8izHU35iAyNjRyDtCQ==", + "dev": true, + "requires": { + "lodash._baseindexof": "^3.0.0", + "lodash._cacheindexof": "^3.0.0", + "lodash._createcache": "^3.0.0" + } + }, + "lodash._baseflatten": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz", + "integrity": "sha512-fESngZd+X4k+GbTxdMutf8ohQa0s3sJEHIcwtu4/LsIQ2JTDzdRxDCMQjW+ezzwRitLmHnacVVmosCbxifefbw==", + "dev": true, + "requires": { + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash._basefor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", + "integrity": "sha512-6bc3b8grkpMgDcVJv9JYZAk/mHgcqMljzm7OsbmcE2FGUMmmLQTPHlh/dFqR8LA0GQ7z4K67JSotVKu5058v1A==", + "dev": true + }, + "lodash._baseindexof": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", + "integrity": "sha512-bSYo8Pc/f0qAkr8fPJydpJjtrHiSynYfYBjtANIgXv5xEf1WlTC63dIDlgu0s9dmTvzRu1+JJTxcIAHe+sH0FQ==", + "dev": true + }, "lodash._basetostring": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", @@ -33040,6 +41575,38 @@ "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", "dev": true }, + "lodash._bindcallback": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==", + "dev": true + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", + "integrity": "sha512-S8dUjWr7SUT/X6TBIQ/OYoCHo1Stu1ZRy6uMUSKqzFnZp5G5RyQizSm6kvxD2Ewyy6AVfMg4AToeZzKfF99T5w==", + "dev": true + }, + "lodash._createassigner": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", + "integrity": "sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==", + "dev": true, + "requires": { + "lodash._bindcallback": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash.restparam": "^3.0.0" + } + }, + "lodash._createcache": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", + "integrity": "sha512-ev5SP+iFpZOugyab/DEUQxUeZP5qyciVTlgQ1f4Vlw7VUcCD8fVnyIqVUEIaoFH9zjAqdgi69KiofzvVmda/ZQ==", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0" + } + }, "lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", @@ -33052,6 +41619,22 @@ "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", "dev": true }, + "lodash._pickbyarray": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz", + "integrity": "sha512-tHzBIfgugzI7HV0y8MJS1z/ryWDh8NyD6AV+so9vlplRnhD4qBuwoyDt7g241ad3F43YDFghCN+R3iaFd4Azvw==", + "dev": true + }, + "lodash._pickbycallback": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz", + "integrity": "sha512-DVP27YmN0lB+j/Tgd/+gtxfmW/XihgWpQpHptBuwyp2fD9zEBRwwcnw6Qej16LUV8LRFuTqyoc0i6ON97d/C5w==", + "dev": true, + "requires": { + "lodash._basefor": "^3.0.0", + "lodash.keysin": "^3.0.0" + } + }, "lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", @@ -33147,12 +41730,61 @@ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", "dev": true }, + "lodash.istypedarray": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz", + "integrity": "sha512-lGWJ6N8AA3KSv+ZZxlTdn4f6A7kMfpJboeyvbFdE7IU9YAgweODqmOgdUHOA+c6lVWeVLysdaxciFXi+foVsWw==", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash.keysin": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", + "integrity": "sha512-YDB/5xkL3fBKFMDaC+cfGV00pbiJ6XoJIfRmBhv7aR6wWtbCW6IzkiWnTfkiHTF6ALD7ff83dAtB3OEaSoyQPg==", + "dev": true, + "requires": { + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==", + "dev": true + }, "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.omit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-3.1.0.tgz", + "integrity": "sha512-vC3fSzZDmPlwk+kCGYMQyUpPeRBgmOK/WrhmjlWVUjEch35gQR3iRbCV9rL7KgMHVeVhnq7A+TRrPvzvg67y9w==", + "dev": true, + "requires": { + "lodash._arraymap": "^3.0.0", + "lodash._basedifference": "^3.0.0", + "lodash._baseflatten": "^3.0.0", + "lodash._bindcallback": "^3.0.0", + "lodash._pickbyarray": "^3.0.0", + "lodash._pickbycallback": "^3.0.0", + "lodash.keysin": "^3.0.0", + "lodash.restparam": "^3.0.0" + } + }, "lodash.pickby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", @@ -33190,6 +41822,16 @@ "lodash._reinterpolate": "^3.0.0" } }, + "lodash.toplainobject": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz", + "integrity": "sha512-wMI0Ju1bvSmnBS3EcRRH/3zDnZOPpDtMtNDzbbNMKuTrEpALsf+sPyMeogmv63Y11qZQO7H1xFzohIEGRMjPYA==", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash.keysin": "^3.0.0" + } + }, "lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", @@ -33269,6 +41911,16 @@ "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": "sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, "loupe": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", @@ -33302,6 +41954,17 @@ "es5-ext": "~0.10.2" } }, + "m3u8-parser": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.7.1.tgz", + "integrity": "sha512-pbrQwiMiq+MmI9bl7UjtPT3AK603PV9bogNlr83uC+X9IoxqL5E4k7kU7fMQ0dpRgxgeSMygqUa0IMLQNXLBNA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^3.0.5", + "global": "^4.4.0" + } + }, "magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -33344,6 +42007,12 @@ "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": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true + }, "map-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", @@ -33359,12 +42028,85 @@ "object-visit": "^1.0.0" } }, + "markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "requires": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + } + } + }, + "markdown-it-anchor": { + "version": "8.6.5", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.5.tgz", + "integrity": "sha512-PI1qEHHkTNWT+X6Ip9w+paonfIQ+QZP9sCeMYi47oqhH+EsW8CrJ8J7CzV19QVOj6il8ATGbK2nTECj22ZHGvQ==", + "dev": true, + "requires": {} + }, "markdown-table": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.2.tgz", "integrity": "sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==", "dev": true }, + "markdownlint": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.0.6.tgz", + "integrity": "sha512-2jxomIcTY+HWnrMWv7Q/T93d7yp4RXNGkoQXWq5II1TgyQj5pFDoB7HZSCX57ATk9zZTb1++jwXR3uHn6AKmew==", + "dev": true, + "requires": { + "markdown-it": "^4.2.2" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "linkify-it": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz", + "integrity": "sha512-eGHwtlABkp1NOJSiKUNqBf3SYAS5jPHtvRXPAgNaQwTqmkTahjtiLH9NtxdR5IOPhNvwNMN/diswSfZKzUkhGg==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "markdown-it": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz", + "integrity": "sha512-Rl8dHHeLuAh3E72OPY0tY7CLvlxgHiLhlshIYswAAabAg4YDBLa6e/LTgNkkxBO2K61ESzoquPQFMw/iMrT1PA==", + "dev": true, + "requires": { + "argparse": "~1.0.2", + "entities": "~1.1.1", + "linkify-it": "~1.2.0", + "mdurl": "~1.0.0", + "uc.micro": "^1.0.0" + } + } + } + }, + "marked": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz", + "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==", + "dev": true + }, "marky": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.4.tgz", @@ -33406,6 +42148,17 @@ } } }, + "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-definitions": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", @@ -33672,6 +42425,66 @@ "readable-stream": "^2.0.1" } }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", + "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": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "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": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "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": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + } + } + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -34112,6 +42925,24 @@ } } }, + "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.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, "mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -34143,6 +42974,27 @@ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", "dev": true }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "requires": { + "dom-walk": "^0.1.0" + } + }, + "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": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -34181,12 +43033,11 @@ "dev": true }, "mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", + "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", "dev": true, "requires": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", @@ -34376,6 +43227,12 @@ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", @@ -34405,6 +43262,190 @@ } } }, + "mocha-phantomjs": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/mocha-phantomjs/-/mocha-phantomjs-3.6.0.tgz", + "integrity": "sha512-siI6m2uw3Xyjruz9eEP8JTVHOtnOxdmnEqXM0IrOt3Nbw4oPJw6u8Q6MG6hqnbH9fJ3i60F3bYlmSEbgwuNsQw==", + "dev": true, + "requires": { + "commander": "~2.0.0", + "mocha": "~1.20.1" + }, + "dependencies": { + "diff": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.7.tgz", + "integrity": "sha512-0bTLzyr1S59cPsgAD/lR+ivvHTbgPb+k/mUR6WGqma1J6QDU+kUegI8uQFuH/cMUNK7JGN3Tk1Y5Jf2MO85WrA==", + "dev": true + }, + "glob": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", + "integrity": "sha512-WPaLsMHD1lYEqAmIQI6VOJSPwuBdGShDWnj1yUo0vQqEO809R8W3LM9OVU13CnnDhyv/EiNwOtxEW74SmrzS6w==", + "dev": true, + "requires": { + "graceful-fs": "~2.0.0", + "inherits": "2", + "minimatch": "~0.2.11" + } + }, + "graceful-fs": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", + "integrity": "sha512-hcj/NTUWv+C3MbqrVb9F+aH6lvTwEHJdx2foBxlrVq5h6zE8Bfu4pv4CAAqbDcZrw/9Ak5lsRXlY9Ao8/F0Tuw==", + "dev": true + }, + "growl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz", + "integrity": "sha512-VWv7s1EI41AG2LiCr7uAuxWikLDN1SQOuEUc37d/P34NAIIYgkvWYngNw0d9d9iCrDFL0SYCE9UQpxhIjjtuLg==", + "dev": true + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==", + "dev": true + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha512-zZ+Jy8lVWlvqqeM8iZB7w7KmQkoJn8djM585z88rywrEbzoqawVa9FR5p2hwD+y74nfuKOjmNvi9gtWJNLqHvA==", + "dev": true, + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + }, + "mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", + "dev": true + }, + "mocha": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.20.1.tgz", + "integrity": "sha512-25Nq3BuIYCy80uEix+hBlZcr/gnLzpcYqfsaPAxZm2qbMFmed8I3nP8N05KagK4BTkGYUvsRJ47istvRqFO8fw==", + "dev": true, + "requires": { + "commander": "2.0.0", + "debug": "*", + "diff": "1.0.7", + "glob": "3.2.3", + "growl": "1.7.x", + "jade": "0.26.3", + "mkdirp": "0.3.5" + } + } + } + }, + "module-deps": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-3.9.1.tgz", + "integrity": "sha512-EbWWlSGaCVidEsLsSzkY6l/jm0IcGDSQ8tGwtjM8joTrxqxP0om02Px9Np8D7FMZ/vZFdsOGbio+WqkKQxYuTA==", + "dev": true, + "requires": { + "browser-resolve": "^1.7.0", + "concat-stream": "~1.4.5", + "defined": "^1.0.0", + "detective": "^4.0.0", + "duplexer2": "0.0.2", + "inherits": "^2.0.1", + "JSONStream": "^1.0.3", + "parents": "^1.0.0", + "readable-stream": "^1.1.13", + "resolve": "^1.1.3", + "stream-combiner2": "~1.0.0", + "subarg": "^1.0.0", + "through2": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", + "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.9", + "typedarray": "~0.0.5" + } + }, + "defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "dev": true + }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "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": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "requires": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha512-pEk4ECWQXV6z2zjhRZUongnLJNUeGQJ3w6OQ5ctGwD+i5o93qjRQUk2Rt6VdNeu3sEP0AB4LcfvdebpxBRVr4g==", + "dev": true + }, "morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -34441,6 +43482,18 @@ } } }, + "mpd-parser": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.21.1.tgz", + "integrity": "sha512-BxlSXWbKE1n7eyEPBnTEkrzhS3PdmkkKdM1pgKbPnPOH0WFZIc0sPOWi7m0Uo3Wd2a4Or8Qf4ZbS7+ASqQ49fw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^3.0.5", + "@xmldom/xmldom": "^0.7.2", + "global": "^4.4.0" + } + }, "mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -34514,6 +43567,16 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "mux.js": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-6.0.1.tgz", + "integrity": "sha512-22CHb59rH8pWGcPGW5Og7JngJ9s+z4XuSlYvnxhLuc58cA1WqGDQPzuG8I+sPm1/p0CdgpzVTaKW408k5DNn8w==", + "dev": true, + "requires": { + "@babel/runtime": "^7.11.2", + "global": "^4.4.0" + } + }, "nan": { "version": "2.15.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", @@ -34555,6 +43618,13 @@ } } }, + "natives": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", + "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", + "dev": true, + "optional": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -34578,6 +43648,15 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "nested-error-stacks": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", + "integrity": "sha512-o32anp9JA7oezPOFSfG2BBXSdHepOm5FpJvwxHWDtfJ3Bg3xdi68S6ijPlEOfUg6quxZWyvJM+8fHk1yMDKspA==", + "dev": true, + "requires": { + "inherits": "~2.0.1" + } + }, "next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -34653,6 +43732,53 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==", + "dev": true + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha512-5s0JxqhDx9/rksG2BTMVN1enjWSvPidpoSgViZU4ZXULyTe+7jxcCRLB6f42Z0l1xYJpleCBtSyY6Lwg3uu5CQ==", + "dev": true, + "requires": { + "chalk": "~0.4.0", + "underscore": "~1.6.0" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha512-3iF4FIKdxaVYT3JqQuY3Wat/T2t7TRbbQ94Fu50ZUCbLy4TFbTzr90NOHQodQkNqmeEGCw8WbeP78WNi6SKYUA==", + "dev": true + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha512-sQfYDlfv2DGVtjdoQqxS0cEZDroyG8h6TamA6rvxwlrU5BaSLDx9xhatBYl2pxZ7gmpNaPFVwBtdGdu5rQ+tYQ==", + "dev": true, + "requires": { + "ansi-styles": "~1.0.0", + "has-color": "~0.1.0", + "strip-ansi": "~0.1.0" + } + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha512-behete+3uqxecWlDAm5lmskaSaISA+ThQ4oNNBDTBJt0x2ppR6IPqfZNuj6BLaLJ/Sji4TPZlcRyOis8wXQTLg==", + "dev": true + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ==", + "dev": true + } + } + }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -34662,6 +43788,12 @@ "abbrev": "1" } }, + "nopt-usage": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/nopt-usage/-/nopt-usage-0.1.0.tgz", + "integrity": "sha512-Tg2sISrWBbSsCRqpEMmdxn3KZfacrd0N2NYpZQIq0MHxGHMjwzYlxeB9pVIom/g7CBK28atDUQsTlOfG0wOsNA==", + "dev": true + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -34703,6 +43835,39 @@ "once": "^1.3.2" } }, + "npm-license": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/npm-license/-/npm-license-0.2.3.tgz", + "integrity": "sha512-Sm6zqTVReBGe1C5A3Vr7pqYFmawM3oF/MKhhk0LRAOZPEOygr96KkiJ5P0ZQMDP3F7HRW6zyy7gxIIos+6foww==", + "dev": true, + "requires": { + "mkdirp": "~0.5.0", + "nopt": "~3.0.1", + "nopt-usage": "^0.1.0", + "package-license": "~0.1.1", + "pkginfo": "^0.3.0", + "read-installed": "~3.1.3", + "treeify": "~1.0.1", + "underscore": "~1.4.4" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "underscore": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==", + "dev": true + } + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -34720,6 +43885,63 @@ } } }, + "npmconf": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/npmconf/-/npmconf-0.0.24.tgz", + "integrity": "sha512-LX0bX+RmuBuEITg26i7+dx+d9cfYU+giB7eOiSkT5IwvuAzzIx02u4GXwSC3jsQMDMb/kXC57R8tybRSVYfbWw==", + "dev": true, + "requires": { + "config-chain": "~1.1.1", + "inherits": "~1.0.0", + "ini": "~1.1.0", + "mkdirp": "~0.3.3", + "nopt": "2", + "once": "~1.1.1", + "osenv": "0.0.3", + "semver": "~1.1.0" + }, + "dependencies": { + "inherits": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha512-Al67oatbRSo3RV5hRqIoln6Y5yMVbJSIn4jEJNL7VCImzq/kLr7vvb6sFRJXqr8rpHc/2kJOM+y0sPKN47VdzA==", + "dev": true + }, + "ini": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.1.0.tgz", + "integrity": "sha512-B6L/jfyFRcG2dqKiHggWnfby52Iy07iabE4F6srQAr/OmVKBRE5uU+B5MQ+nQ7NiYnjz93gENh1GhqHzpDgHgA==", + "dev": true + }, + "mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", + "dev": true + }, + "nopt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz", + "integrity": "sha512-gIOTA/uJuhPwFqp+spY7VQ1satbnGlD+iQVZxI18K6hs8Evq4sX81Ml7BB5byP/LsbR2yBVtmvdEmhi7evJ6Aw==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "once": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/once/-/once-1.1.1.tgz", + "integrity": "sha512-frdJr++QKEg4+JylTX+NNLgSoO6M2pDNYOOXe4WGIYKKBADBI9nU3oa06y4D4FpAJ3obAsjExeBOnscYJB9Blw==", + "dev": true + }, + "semver": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-1.1.4.tgz", + "integrity": "sha512-9causpLEkYDrfTz7cprleLz9dnlb0oKsKRHl33K92wJmXLhVc2dGlrQGJT/sjtLOAyuoQZl+ClI77+lnvzPSKg==", + "dev": true + } + } + }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -34937,6 +44159,12 @@ "mimic-fn": "^2.1.0" } }, + "open": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/open/-/open-0.0.3.tgz", + "integrity": "sha512-Vm6nsJHcKV8kdOtHESAFAymOOf1VlKrttpwTqtLxvxRDIh8PSw4lWq5qk88QkAvNwnkv/1dNi2lvedhmam/ggw==", + "dev": true + }, "opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -34960,6 +44188,23 @@ } } }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", + "dev": true, + "requires": { + "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "dev": true + } + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -35055,6 +44300,12 @@ "readable-stream": "^2.0.1" } }, + "os-browserify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz", + "integrity": "sha512-aZicJZccvxWOZ0Bja2eAch2L8RIJWBuRYmM8Gwl/JjNtRltH0Itcz4eH/ESyuIWfse8cc93ZCf0XrzhXK2HEDA==", + "dev": true + }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -35076,6 +44327,12 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "osenv": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.0.3.tgz", + "integrity": "sha512-VBk1bfdaO4gh3OWO8LBuDY2alp0buL8YzQ6t13xyc8PQPrnUg5AgQvINQx3UkS4dom8UGCL597q4Y2+M4TPvmw==", + "dev": true + }, "p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -35118,6 +44375,18 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, + "package-license": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/package-license/-/package-license-0.1.2.tgz", + "integrity": "sha512-Q5zmx+M9ZJneMpYS6MlYL77gqeMYWuyErXMnQ/83WCztmYQD7Z0U9XGLvX9OKFFXwRj2NzdzlM0y9Jzcww2O1Q==", + "dev": true + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -35127,6 +44396,28 @@ "callsites": "^3.0.0" } }, + "parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==", + "dev": true, + "requires": { + "path-platform": "~0.11.15" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, "parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", @@ -35200,6 +44491,12 @@ "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", @@ -35218,6 +44515,12 @@ "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": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -35229,6 +44532,12 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==", + "dev": true + }, "path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", @@ -35249,6 +44558,25 @@ "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": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + } + } + }, "pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -35264,6 +44592,19 @@ "through": "~2.3" } }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "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" + } + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -35276,6 +44617,184 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "phantomjs": { + "version": "1.9.7-15", + "resolved": "https://registry.npmjs.org/phantomjs/-/phantomjs-1.9.7-15.tgz", + "integrity": "sha512-s4PSN1L0iVwgv9ZkrSKcfojyPAtwGWhXxjn2p1P/ljuw3cx+FW3hKP00x247mIYbKeKSMylOd4euDQOMpUIAsg==", + "dev": true, + "requires": { + "adm-zip": "0.2.1", + "kew": "~0.1.7", + "mkdirp": "0.3.5", + "ncp": "0.4.2", + "npmconf": "0.0.24", + "progress": "^1.1.5", + "request": "2.36.0", + "request-progress": "^0.3.1", + "rimraf": "~2.2.2", + "which": "~1.0.5" + }, + "dependencies": { + "asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", + "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", + "dev": true, + "optional": true + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==", + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", + "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", + "dev": true, + "optional": true + }, + "combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", + "dev": true, + "optional": true, + "requires": { + "delayed-stream": "0.0.5" + } + }, + "delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", + "dev": true, + "optional": true + }, + "forever-agent": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==", + "dev": true + }, + "form-data": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", + "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", + "dev": true, + "optional": true, + "requires": { + "async": "~0.9.0", + "combined-stream": "~0.0.4", + "mime": "~1.2.11" + } + }, + "hawk": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.0.0.tgz", + "integrity": "sha512-Sg+VzrI7TjUomO0rjD6UXawsj50ykn5sB/xKNW/IenxzRVyw/wt9A2FLzYpGL/r0QG5hyXY8nLx/2m8UutoDcg==", + "dev": true, + "optional": true, + "requires": { + "boom": "0.4.x", + "cryptiles": "0.2.x", + "hoek": "0.9.x", + "sntp": "0.2.x" + } + }, + "http-signature": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", + "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", + "dev": true, + "optional": true, + "requires": { + "asn1": "0.1.11", + "assert-plus": "^0.1.5", + "ctype": "0.5.3" + } + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", + "dev": true + }, + "mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", + "dev": true + }, + "oauth-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", + "dev": true, + "optional": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", + "dev": true + }, + "qs": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", + "integrity": "sha512-kN+yNdAf29Jgp+AYHUmC7X4QdJPR8czuMWLNLc0aRxkQ7tB3vJQEONKKT9ou/rW7EbqVec11srC9q9BiVbcnHA==", + "dev": true + }, + "request": { + "version": "2.36.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.36.0.tgz", + "integrity": "sha512-iVii/ruMH9i8k++HYYPqi+nb1Pbgz7UOTGbFEiyhl7uDN8PhyFV2lGJa8XLIUS5tyt5scERcLkwqvCNF84Vv2Q==", + "dev": true, + "requires": { + "aws-sign2": "~0.5.0", + "forever-agent": "~0.5.0", + "form-data": "~0.1.0", + "hawk": "~1.0.0", + "http-signature": "~0.10.0", + "json-stringify-safe": "~5.0.0", + "mime": "~1.2.9", + "node-uuid": "~1.4.0", + "oauth-sign": "~0.3.0", + "qs": "~0.6.0", + "tough-cookie": ">=0.12.0", + "tunnel-agent": "~0.4.0" + } + }, + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", + "dev": true + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", + "dev": true, + "optional": true + }, + "which": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", + "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", + "dev": true + } + } + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -35308,6 +44827,15 @@ "pinkie": "^2.0.0" } }, + "pkcs7": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz", + "integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5" + } + }, "pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -35368,6 +44896,12 @@ } } }, + "pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha512-yO5feByMzAp96LtP58wvPKSbaKAi/1C4kV9XpTctr6EepnP6F33RBNOiVrdz9BrPA98U2BMFsTNHo44TWcbQ2A==", + "dev": true + }, "plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", @@ -35391,6 +44925,23 @@ } } }, + "portfinder": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-0.2.1.tgz", + "integrity": "sha512-U7dHe7mfMMP5cIwbqBHh/likunxAEiBsQLiThUWjyeRK6/C3um2uk+VGiekUW8q3h+s793gdNfagCM3aaXMeOg==", + "dev": true, + "requires": { + "mkdirp": "0.0.x" + }, + "dependencies": { + "mkdirp": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.0.7.tgz", + "integrity": "sha512-r4Ml2CH2Kl4B0+Lwq1SVru0vjMxdtR+UEb938WTQcsnU+EJz8dUV/HY0LTZh466nUSljia9cvqW3LZLWs3l8LQ==", + "dev": true + } + } + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -35415,6 +44966,12 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", + "dev": true + }, "pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", @@ -35461,6 +45018,12 @@ "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": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -35479,6 +45042,12 @@ "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==", "dev": true }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "protocols": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz", @@ -35500,6 +45069,25 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, + "proxyquire": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-1.8.0.tgz", + "integrity": "sha512-mZZq4F50qaBkngvlf9paNfaSb5gtJ0mFPnBjda4NxCpXpMAaVfSLguRr9y2KXF6koOSBf4AanD2inuEQw3aCcA==", + "dev": true, + "requires": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.0", + "resolve": "~1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + } + } + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -35527,6 +45115,28 @@ "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.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -35661,6 +45271,12 @@ "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": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "dev": true + }, "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -35682,6 +45298,16 @@ "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", @@ -35704,6 +45330,103 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "read-all-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", + "integrity": "sha512-DI1drPHbmBcUDWrJ7ull/F2Qb8HkwBncVx8/RpKYFSIACYaVRQReISYPdZz/mt1y1+qMCOrfReTopERmaxtP6w==", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0", + "readable-stream": "^2.0.0" + } + }, + "read-installed": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-3.1.5.tgz", + "integrity": "sha512-XxD5VDz32T6rLCFfYElTif8/lkqcs9y51Gs2r30rAfT7LUGzJWaXLrwvn6fXkDsTzGcPr7Pj8CggOxwTxl/ozQ==", + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "graceful-fs": "2 || 3", + "read-package-json": "1", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "dependencies": { + "graceful-fs": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", + "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", + "dev": true, + "optional": true, + "requires": { + "natives": "^1.1.3" + } + }, + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", + "dev": true + } + } + }, + "read-package-json": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-1.3.3.tgz", + "integrity": "sha512-9bayCl9cbXy3AL0qXhLQ0vliEgpzUVeLegSOrde3ujTHy2W18UsJiMUXEWkjbBB4ZnJzZPVuo2vAW62j4gY7gg==", + "dev": true, + "requires": { + "glob": "^5.0.3", + "graceful-fs": "2 || 3", + "json-parse-helpfulerror": "^1.0.2", + "normalize-package-data": "^1.0.0" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", + "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", + "dev": true, + "optional": true, + "requires": { + "natives": "^1.1.3" + } + }, + "normalize-package-data": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-1.0.3.tgz", + "integrity": "sha512-pyPVJAzFiaioifPIsJBEoKJ9YcPHz7UhckZ7wqhBztLLCu6NozkIDrN+frzrCwjXtfunXfaMWIDtcDhnbO8fWA==", + "dev": true, + "requires": { + "github-url-from-git": "^1.3.0", + "github-url-from-username-repo": "^1.0.0", + "semver": "2 || 3 || 4" + } + }, + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", + "dev": true + } + } + }, "read-pkg": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", @@ -35845,6 +45568,41 @@ } } }, + "readable-wrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/readable-wrap/-/readable-wrap-1.0.0.tgz", + "integrity": "sha512-/8n0Mr10S+HGKFygQ42Z40JIXwafPH3A72pwmlNClThgsImV5LJJiCue5Je1asxwY082sYxq/+kTxH6nTn0w3g==", + "dev": true, + "requires": { + "readable-stream": "^1.1.13-1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + } + } + }, "readdir-glob": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", @@ -35854,6 +45612,18 @@ "minimatch": "^3.0.4" } }, + "readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -35863,6 +45633,39 @@ "picomatch": "^2.2.1" } }, + "readline2": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz", + "integrity": "sha512-qs8GGG+hLGMaDOGjd+mDglDoYcHDkjIY7z5RU0/ApsGT0qypyrWskNeemUqD+UxIXiZoMYT5aLwGp4ehoyZhIg==", + "dev": true, + "requires": { + "mute-stream": "0.0.4", + "strip-ansi": "^2.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", + "dev": true + }, + "mute-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz", + "integrity": "sha512-amvrY4m/7oZamehMoFi1tbwU/kXbVvRTGM2S7F+PZi3n51Jx+9AcSQ3EQsag3tR+hS2higfgOP/Kl8kri/X52A==", + "dev": true + }, + "strip-ansi": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", + "integrity": "sha512-2h8q2CP3EeOhDJ+jd932PRMpa3/pOJFGoF22J1U/DNbEK2gSW2DqeF46VjCXsSQXhC+k/l8/gaaRBQKL6hUPfQ==", + "dev": true, + "requires": { + "ansi-regex": "^1.0.0" + } + } + } + }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -35892,6 +45695,16 @@ } } }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -36191,6 +46004,15 @@ } } }, + "request-progress": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-0.3.1.tgz", + "integrity": "sha512-+IAgzH8yWAEgHjOOQzYEqRm0BpNlE6xFgsziGMiTxxMhrkBcCOe9bNWH7bDR+XtHToUMgCZlDgLqjk6cAP/+Ig==", + "dev": true, + "requires": { + "throttleit": "~0.0.2" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -36209,6 +46031,15 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, + "requizzle": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", + "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -36256,6 +46087,12 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "response-stream": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/response-stream/-/response-stream-0.0.0.tgz", + "integrity": "sha512-tWH3QWqkXv7AgYRXidIhPKO1SqPix2E0gM3x/vxf60LHQHWNS8AVrB3RnYexPAoo5dOc0bGzDlUgtsBvV3CWLA==", + "dev": true + }, "responselike": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", @@ -36298,12 +46135,36 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, + "rewire": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/rewire/-/rewire-2.5.2.tgz", + "integrity": "sha512-9wOlgRHTOzUv5dQO2XD2qWob+7yi/QXh7SSwLJW5wMAkAdkYuaCtcPuLAXUTllK0MjSvtpxUqAWMuSrrdt9VNw==", + "dev": true + }, "rfdc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", "dev": true }, + "rfile": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rfile/-/rfile-1.0.0.tgz", + "integrity": "sha512-aNeTpY8g6DYmqPvakau22B0SipQTskO8FtYXzn8qg4X4bN9ExIH8VAhq/L9w7N8HvESYeSSwk3e4GmW+rLLAxQ==", + "dev": true, + "requires": { + "callsite": "~1.0.0", + "resolve": "~0.3.0" + }, + "dependencies": { + "resolve": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.3.1.tgz", + "integrity": "sha512-mxx/I/wLjxtryDBtrrb0ZNzaYERVWaHpJ0W0Arm8N4l8b+jiX/U5yKcsj0zQpF9UuKN1uz80EUTOudON6OPuaQ==", + "dev": true + } + } + }, "rgb2hex": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.5.tgz", @@ -36319,12 +46180,68 @@ "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" + } + }, + "ruglify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ruglify/-/ruglify-1.0.0.tgz", + "integrity": "sha512-XfRj1YJdm/gnZNvmpQ5L+2YGRHglDGMPgJRbitgCxC3GzKVQF/t+ij1aNcNg2AnEXGtLHJDwoSWrAq3TUm0EVg==", + "dev": true, + "requires": { + "rfile": "~1.0", + "uglify-js": "~2.2" + }, + "dependencies": { + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "uglify-js": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", + "integrity": "sha512-viLk+/8G0zm2aKt1JJAVcz5J/5ytdiNaIsKgrre3yvSUjwVG6ZUujGH7E2TiPigZUwLYCe7eaIUEP2Zka2VJPA==", + "dev": true, + "requires": { + "optimist": "~0.3.5", + "source-map": "~0.1.7" + } + } + } + }, "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 }, + "rust-result": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz", + "integrity": "sha512-6cJzSBU+J/RJCF063onnQf0cDUOHs9uZI1oroSGnHOph+CQTIJ5Pp2hK5kEQq1+7yE/EEWfulSNXAQ2jikPthA==", + "dev": true, + "requires": { + "individual": "^2.0.0" + } + }, + "rx": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz", + "integrity": "sha512-u5qvfulb7NXoY/+OE28920WEgFi6aiDjf5iF9rA2f9tBXejLgTLd0WxkclvIQWjFFHfNJlb7pSTsrjgiDh+Uug==", + "dev": true + }, "rxjs": { "version": "7.5.5", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", @@ -36414,6 +46331,17 @@ } } }, + "script-injector": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/script-injector/-/script-injector-0.1.7.tgz", + "integrity": "sha512-0iW1D9UKsOPNUVBHvR76KePNS5TamEBN38bT5k7BqsXItsyV5oJTZbVsvOF3YS2xJ7GB7pszmgfDFJbIgHmrDQ==", + "dev": true, + "requires": { + "duplexer": "~0.1.1", + "through": "~2.3.4", + "trumpet": "~1.6.3" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -36623,6 +46551,32 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "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" + } + }, + "shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==", + "dev": true + }, + "shasum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "integrity": "sha512-UTzHm/+AzKfO9RgPgRpDIuMSNie1ubXRaljjlhFMNGYoG7z+rm9AHLPMf70R7887xboDH9Q+5YQbWKObFHEAtw==", + "dev": true, + "requires": { + "json-stable-stringify": "~0.0.0", + "sha.js": "~2.4.4" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -36638,6 +46592,35 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "shell-quote": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-0.0.1.tgz", + "integrity": "sha512-uEWz7wa9vnCi9w4mvKZMgbHFk3DCKjLQlZcy0tJxUH4NwZjRrPPHXAYIEt2TmJs600Dcgj0Z3fZLZKVPVdGNbQ==", + "dev": true + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha512-Ny0KN4dyT8ZSCE0frtcbAJGoM/HTArpyPkeli1/00aYfm0sbD/Gk/4x7N2DP9QKGpBsiQH7n6rpm1L79RtviEQ==", + "dev": true + }, + "shelljs-nodecli": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shelljs-nodecli/-/shelljs-nodecli-0.1.1.tgz", + "integrity": "sha512-/e+APCWKKW9A8YMHKgDzhWQ21zPuDLjn6ATBczxbp6uUeiCSwvw95ynKAjMsRd1yrd5dlCkMKJoc/Lpwrt2w+A==", + "dev": true, + "requires": { + "shelljs": "~0.2" + }, + "dependencies": { + "shelljs": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz", + "integrity": "sha512-LQiM15qPbSyzHDFfI4v7EVhjBXG5PUAKWVBnVMBXwdlQSHZtzKYeKGzDHBIqpenPrCsPWqBSOF5o7oSvSfX+CA==", + "dev": true + } + } + }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -36649,6 +46632,12 @@ "object-inspect": "^1.9.0" } }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", + "dev": true + }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -36747,6 +46736,12 @@ } } }, + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", + "dev": true + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -36922,6 +46917,16 @@ } } }, + "sntp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", + "integrity": "sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==", + "dev": true, + "optional": true, + "requires": { + "hoek": "0.9.x" + } + }, "socket.io": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", @@ -37087,6 +47092,23 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sse-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/sse-stream/-/sse-stream-0.0.4.tgz", + "integrity": "sha512-rnDUubW7a4CZAB5D0r2OtFU/zvY05MoNGHMX6deAYK0wWaizrNcHzimf+Nk5y0sqntGAPpWEnIopWrrAf2TBVg==", + "dev": true, + "requires": { + "through": "~2.2.7" + }, + "dependencies": { + "through": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", + "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", + "dev": true + } + } + }, "sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", @@ -37210,6 +47232,42 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "stream-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-1.0.0.tgz", + "integrity": "sha512-e+V5xc4LlkOiRr64kZTUdb11exsbpSnwb9uwmXaHeDXCpfHg7vaefMJOxi21Pe74ZOqjZ87blBcqqpNAM4Ku0g==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^1.0.27-1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + } + } + }, "stream-buffers": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", @@ -37225,6 +47283,81 @@ "duplexer": "~0.1.1" } }, + "stream-combiner2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.0.2.tgz", + "integrity": "sha512-7DO1SfBVnyIyo9ytUjSyVojT5bp1ZY6h3pj7HUs6PwcRSd/r8mBOHbRwYC7nbHRakKzMKyNp5HWJRv4GgVherA==", + "dev": true, + "requires": { + "duplexer2": "~0.0.2", + "through2": "~0.5.1" + }, + "dependencies": { + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "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": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", + "integrity": "sha512-zexCrAOTbjkBCXGyozn7hhS3aEaqdrc59mAD2E3dKYzV1vFuEGQ1hEDJN2oQMQFwy4he2zyLqPZV+AlfS8ZWJA==", + "dev": true, + "requires": { + "readable-stream": "~1.0.17", + "xtend": "~3.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + } + } + }, + "xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", + "dev": true + } + } + }, "stream-exhaust": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", @@ -37237,6 +47370,56 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, + "stream-splicer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-1.3.2.tgz", + "integrity": "sha512-nmUMEbdm/sZYqe9dZs7mqJvTYpunsDbIWI5FiBCMc/hMVd6vwzy+ITmo7C3gcLYqrn+uQ1w+EJwooWvJ997JAA==", + "dev": true, + "requires": { + "indexof": "0.0.1", + "inherits": "^2.0.1", + "isarray": "~0.0.1", + "readable-stream": "^1.1.13-1", + "readable-wrap": "^1.0.0", + "through2": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "requires": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, "streamroller": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.4.tgz", @@ -37312,6 +47495,13 @@ "character-entities-legacy": "^3.0.0" } }, + "stringstream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "dev": true, + "optional": true + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -37339,12 +47529,30 @@ "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": "sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", "dev": true }, + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", + "dev": true, + "requires": { + "minimist": "^1.1.0" + } + }, "suffix": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", @@ -37375,6 +47583,15 @@ "es6-symbol": "^3.1.1" } }, + "syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "dev": true, + "requires": { + "acorn-node": "^1.2.0" + } + }, "table": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", @@ -37408,6 +47625,12 @@ } } }, + "taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", + "dev": true + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -37596,6 +47819,12 @@ "integrity": "sha512-mk82dS8eRABNbeVJrEiN5/UMSCliINAuz8mkUwH4SwslkNP//gbEzlWNS5au0z5Dpx40SQxzqZevZkn+WYJ9Dw==", "dev": true }, + "throttleit": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", + "integrity": "sha512-HtlTFeyYs1elDM2txiIGsdXHaq8kffVaZH/QEBRbo95zQqzlsBx5ELKhkPOZVad9OK9oxzwx6UrQN8Vfh/+yag==", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -37652,6 +47881,21 @@ "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", "dev": true }, + "timed-out": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", + "integrity": "sha512-pqqJOi1rF5zNs/ps4vmbE4SFCrM4iR7LW+GHAsHqO/EumqbIWceioevYLM5xZRgQSH6gFgL9J/uB7EcJhQ9niQ==", + "dev": true + }, + "timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==", + "dev": true, + "requires": { + "process": "~0.11.0" + } + }, "timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", @@ -37716,6 +47960,12 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, + "to-iso-string": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", + "integrity": "sha512-oeHLgfWA7d0CPQa6h0+i5DAJZISz5un0d5SHPkw+Untclcvzv9T+AC3CvGXlZJdOlIbxbTfyyzlqCXc5hjpXYg==", + "dev": true + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -37825,12 +48075,24 @@ "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", "dev": true }, + "treeify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.0.1.tgz", + "integrity": "sha512-i3MKN4nGEOuVAcd7s5MtAc2+QBExwcaRT/6/CzUSYVYwzM58bJ3H3wwCPu2PEAGjVPHjfIC/MPaXsxPGUk07cg==", + "dev": true + }, "trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", "dev": true }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==", + "dev": true + }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -37843,6 +48105,65 @@ "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", "dev": true }, + "trumpet": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/trumpet/-/trumpet-1.6.6.tgz", + "integrity": "sha512-A4cn/zuq0AsxS5M8cD+7GUoIhOoK2qkcpFUwlpHnNOsTPzCq7FITZV9lg95ydupJcQRi/kFQzGIn7oN3kNp10w==", + "dev": true, + "requires": { + "duplexer2": "~0.0.2", + "html-select": "^2.3.5", + "html-tokenize": "^1.1.1", + "inherits": "^2.0.0", + "readable-stream": "^1.0.27-1", + "through2": "^1.0.0" + }, + "dependencies": { + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "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": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "requires": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, "tsconfig-paths": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz", @@ -37872,6 +48193,12 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -37929,13 +48256,6 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, - "typescript": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", - "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", - "dev": true, - "peer": true - }, "typescript-compare": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", @@ -37963,6 +48283,12 @@ "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", "dev": true }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, "uglify-js": { "version": "3.15.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz", @@ -37970,6 +48296,77 @@ "dev": true, "optional": true }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", + "dev": true + }, + "umd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/umd/-/umd-2.1.0.tgz", + "integrity": "sha512-mEAJeceExHnblcAwN3BQtDPYOrTy4ALeBh6nQ9KW0cUCd0UU714jAfil2jvq09b67IizwJIiTVFOjE+/52Dyvw==", + "dev": true, + "requires": { + "rfile": "~1.0.0", + "ruglify": "~1.0.0", + "through": "~2.3.4", + "uglify-js": "~2.4.0" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", + "dev": true + }, + "source-map": { + "version": "0.1.34", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz", + "integrity": "sha512-yfCwDj0vR9RTwt3pEzglgb3ZgmcXHt6DjG3bjJvzPwTL+5zDQ2MhmSzAcTy0GTiQuCiriSWXvWM1/NhKdXuoQA==", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "uglify-js": { + "version": "2.4.24", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz", + "integrity": "sha512-tktIjwackfZLd893KGJmXc1hrRHH1vH9Po3xFh1XBjjeGAnN02xJ3SuoA+n1L29/ZaCA18KzCFlckS+vfPugiA==", + "dev": true, + "requires": { + "async": "~0.2.6", + "source-map": "0.1.34", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.5.4" + } + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", + "dev": true + }, + "yargs": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz", + "integrity": "sha512-5j382E4xQSs71p/xZQsU1PtRA2HXPAjX0E0DkoGLxwNASMOKX6A9doV1NrZmj85u2Pjquz402qonBzz/yLPbPA==", + "dev": true, + "requires": { + "camelcase": "^1.0.2", + "decamelize": "^1.0.0", + "window-size": "0.1.0", + "wordwrap": "0.0.2" + } + } + } + }, "unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", @@ -37998,6 +48395,18 @@ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, + "underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "underscore.string": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", + "integrity": "sha512-yxkabuCaIBnzfIvX3kBxQqCs0ar/bfJwDnFEHJUm/ZrRVhT3IItdRF5cZjARLzEnyQYtIUhsZ2LG2j3HidFOFQ==", + "dev": true + }, "undertaker": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", @@ -38291,12 +48700,24 @@ "requires-port": "^1.0.0" } }, + "url-toolkit": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.5.tgz", + "integrity": "sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg==", + "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 }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha512-aggiKfEEubv3UwRNqTzLInZpAOmKzwdHqEBmW/hBA/mt99eg+b4VrX6i+IRLxU8+WJYfa33rGwRseg4eElUgsQ==", + "dev": true + }, "util": { "version": "0.12.4", "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", @@ -38317,6 +48738,12 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", + "dev": true + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -38483,6 +48910,87 @@ "vfile-message": "^3.0.0" } }, + "video.js": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.20.2.tgz", + "integrity": "sha512-hdvAHKAyaL6bCDkeu0pPtFYKi1EDaOUovm7FN1xqBDolUxgH8FKy1WIgTS+Ouuaw7R54SCTcSeXjZEizhy9ouQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@videojs/http-streaming": "2.14.2", + "@videojs/vhs-utils": "^3.0.4", + "@videojs/xhr": "2.6.0", + "aes-decrypter": "3.1.3", + "global": "^4.4.0", + "keycode": "^2.2.0", + "m3u8-parser": "4.7.1", + "mpd-parser": "0.21.1", + "mux.js": "6.0.1", + "safe-json-parse": "4.0.0", + "videojs-font": "3.2.0", + "videojs-vtt.js": "^0.15.3" + }, + "dependencies": { + "safe-json-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz", + "integrity": "sha512-RjZPPHugjK0TOzFrLZ8inw44s9bKox99/0AZW9o/BEQVrJfhI+fIHMErnPyRa89/yRXUUr93q+tiN6zhoVV4wQ==", + "dev": true, + "requires": { + "rust-result": "^1.0.0" + } + } + } + }, + "videojs-contrib-ads": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/videojs-contrib-ads/-/videojs-contrib-ads-6.9.0.tgz", + "integrity": "sha512-nzKz+jhCGMTYffSNVYrmp9p70s05v6jUMOY3Z7DpVk3iFrWK4Zi/BIkokDWrMoHpKjdmCdKzfJVBT+CrUj6Spw==", + "dev": true, + "requires": { + "global": "^4.3.2", + "video.js": "^6 || ^7" + } + }, + "videojs-font": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.2.0.tgz", + "integrity": "sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA==", + "dev": true + }, + "videojs-ima": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/videojs-ima/-/videojs-ima-1.11.0.tgz", + "integrity": "sha512-ZRoWuGyJ75zamwZgpr0i/gZ6q7Evda/Q6R46gpW88WN7u0ORU7apw/lM1MSG4c3YDXW8LDENgzMAvMZUdifWhg==", + "dev": true, + "requires": { + "@hapi/cryptiles": "^5.1.0", + "can-autoplay": "^3.0.0", + "extend": ">=3.0.2", + "lodash": ">=4.17.19", + "lodash.template": ">=4.5.0", + "videojs-contrib-ads": "^6.6.5" + } + }, + "videojs-playlist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/videojs-playlist/-/videojs-playlist-5.0.0.tgz", + "integrity": "sha512-TM9bytwKqkE05wdWPEKDpkwMGhS/VgMCIsEuNxmX1J1JO9zaTIl4Wm3egf5j1dhIw19oWrqGUV/nK0YNIelCpA==", + "dev": true, + "requires": { + "global": "^4.3.2", + "video.js": "^6 || ^7" + } + }, + "videojs-vtt.js": { + "version": "0.15.4", + "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.4.tgz", + "integrity": "sha512-r6IhM325fcLb1D6pgsMkTQT1PpFdUdYZa1iqk7wJEu+QlibBwATPfPc9Bg8Jiym0GE5yP1AG2rMLu+QMVWkYtA==", + "dev": true, + "requires": { + "global": "^4.3.1" + } + }, "vinyl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", @@ -38577,6 +49085,15 @@ "source-map": "^0.5.1" } }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha512-NyZNR3WDah+NPkjh/YmhuWSsT4a0mF0BJYgUmvrJ70zxjTXh5Y2Asobxlh0Nfs0PCFB5FVpRJft7NozAWFMwLQ==", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, "void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -38999,6 +49516,12 @@ "is-typed-array": "^1.1.7" } }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", + "dev": true + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -39087,6 +49610,18 @@ "dev": true, "requires": {} }, + "xml-escape": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz", + "integrity": "sha512-gCT82WbwOT9SBI/94j5i0tqHpjHIP/0kP11BS8s2wcBtdcFsDNLS9sLvA+C55fD3hpGhgnE/r7hfeBFkiMATjw==", + "dev": true + }, + "xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index a463546efa1..c5f1b1861a0 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,10 @@ "through2": "^4.0.2", "url": "^0.11.0", "url-parse": "^1.0.5", + "video.js": "^7.17.0", + "videojs-contrib-ads": "^6.9.0", + "videojs-ima": "^1.11.0", + "videojs-playlist": "^5.0.0", "webdriverio": "^7.6.1", "webpack": "^5.70.0", "webpack-bundle-analyzer": "^4.5.0", diff --git a/src/events.js b/src/events.js index e675ffef7a9..8e6117c3abf 100644 --- a/src/events.js +++ b/src/events.js @@ -133,6 +133,10 @@ const _public = (function () { return _handlers; }; + _public.addEvents = function (events) { + allEvents = allEvents.concat(events); + } + /** * This method can return a copy of all the events fired * @return {Array} array of events fired @@ -152,4 +156,4 @@ const _public = (function () { utils._setEventEmitter(_public.emit.bind(_public)); -export const {on, off, get, getEvents, emit} = _public; +export const {on, off, get, getEvents, emit, addEvents} = _public; diff --git a/src/prebid.js b/src/prebid.js index a0981cd387a..0378f8c27ed 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -485,86 +485,99 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) { logInfo('Invoking $$PREBID_GLOBAL$$.renderAd', arguments); logMessage('Calling renderAd with adId :' + id); - if (doc && id) { - try { - // lookup ad by ad Id - const bid = auctionManager.findBidByAdId(id); - - if (bid) { - let shouldRender = true; - if (bid && bid.status === CONSTANTS.BID_STATUS.RENDERED) { - logWarn(`Ad id ${bid.adId} has been rendered before`); - events.emit(STALE_RENDER, bid); - if (deepAccess(config.getConfig('auctionOptions'), 'suppressStaleRender')) { - shouldRender = false; - } - } - - if (shouldRender) { - // replace macros according to openRTB with price paid = bid.cpm - bid.ad = replaceAuctionPrice(bid.ad, bid.originalCpm || bid.cpm); - bid.adUrl = replaceAuctionPrice(bid.adUrl, bid.originalCpm || bid.cpm); - // replacing clickthrough if submitted - if (options && options.clickThrough) { - const {clickThrough} = options; - bid.ad = replaceClickThrough(bid.ad, clickThrough); - bid.adUrl = replaceClickThrough(bid.adUrl, clickThrough); - } - - // save winning bids - auctionManager.addWinningBid(bid); - - // emit 'bid won' event here - events.emit(BID_WON, bid); - - const {height, width, ad, mediaType, adUrl, renderer} = bid; - - const creativeComment = document.createComment(`Creative ${bid.creativeId} served by ${bid.bidder} Prebid.js Header Bidding`); - insertElement(creativeComment, doc, 'html'); - - if (isRendererRequired(renderer)) { - executeRenderer(renderer, bid, doc); - reinjectNodeIfRemoved(creativeComment, doc, 'html'); - emitAdRenderSucceeded({ doc, bid, id }); - } else if ((doc === document && !inIframe()) || mediaType === 'video') { - const message = `Error trying to write ad. Ad render call ad id ${id} was prevented from writing to the main document.`; - emitAdRenderFail({reason: PREVENT_WRITING_ON_MAIN_DOCUMENT, message, bid, id}); - } else if (ad) { - doc.write(ad); - doc.close(); - setRenderSize(doc, width, height); - reinjectNodeIfRemoved(creativeComment, doc, 'html'); - callBurl(bid); - emitAdRenderSucceeded({ doc, bid, id }); - } else if (adUrl) { - const iframe = createInvisibleIframe(); - iframe.height = height; - iframe.width = width; - iframe.style.display = 'inline'; - iframe.style.overflow = 'hidden'; - iframe.src = adUrl; - - insertElement(iframe, doc, 'body'); - setRenderSize(doc, width, height); - reinjectNodeIfRemoved(creativeComment, doc, 'html'); - callBurl(bid); - emitAdRenderSucceeded({ doc, bid, id }); - } else { - const message = `Error trying to write ad. No ad for bid response id: ${id}`; - emitAdRenderFail({reason: NO_AD, message, bid, id}); - } - } - } else { - const message = `Error trying to write ad. Cannot find ad by given id : ${id}`; - emitAdRenderFail({ reason: CANNOT_FIND_AD, message, id }); + if (!id) { + const message = `Error trying to write ad Id :${id} to the page. Missing adId`; + emitAdRenderFail({ reason: MISSING_DOC_OR_ADID, message, id }); + return; + } + + try { + // lookup ad by ad Id + const bid = auctionManager.findBidByAdId(id); + if (!bid) { + const message = `Error trying to write ad. Cannot find ad by given id : ${id}`; + emitAdRenderFail({ reason: CANNOT_FIND_AD, message, id }); + return; + } + + if (bid.status === CONSTANTS.BID_STATUS.RENDERED) { + logWarn(`Ad id ${bid.adId} has been rendered before`); + events.emit(STALE_RENDER, bid); + if (deepAccess(config.getConfig('auctionOptions'), 'suppressStaleRender')) { + return; } - } catch (e) { - const message = `Error trying to write ad Id :${id} to the page:${e.message}`; - emitAdRenderFail({ reason: EXCEPTION, message, id }); } - } else { - const message = `Error trying to write ad Id :${id} to the page. Missing document or adId`; - emitAdRenderFail({ reason: MISSING_DOC_OR_ADID, message, id }); + + // replace macros according to openRTB with price paid = bid.cpm + bid.ad = replaceAuctionPrice(bid.ad, bid.originalCpm || bid.cpm); + bid.adUrl = replaceAuctionPrice(bid.adUrl, bid.originalCpm || bid.cpm); + // replacing clickthrough if submitted + if (options && options.clickThrough) { + const {clickThrough} = options; + bid.ad = replaceClickThrough(bid.ad, clickThrough); + bid.adUrl = replaceClickThrough(bid.adUrl, clickThrough); + } + + // save winning bids + auctionManager.addWinningBid(bid); + + // emit 'bid won' event here + events.emit(BID_WON, bid); + + const {height, width, ad, mediaType, adUrl, renderer} = bid; + + // video module + const adUnitCode = bid.adUnitCode; + const adUnit = $$PREBID_GLOBAL$$.adUnits.filter(adUnit => adUnit.code === adUnitCode); + const videoModule = $$PREBID_GLOBAL$$.videoModule; + if (adUnit.video && videoModule) { + videoModule.renderBid(adUnit.video.divId, bid); + return; + } + + if (!doc) { + const message = `Error trying to write ad Id :${id} to the page. Missing document`; + emitAdRenderFail({ reason: MISSING_DOC_OR_ADID, message, id }); + return; + } + + const creativeComment = document.createComment(`Creative ${bid.creativeId} served by ${bid.bidder} Prebid.js Header Bidding`); + insertElement(creativeComment, doc, 'html'); + + if (isRendererRequired(renderer)) { + executeRenderer(renderer, bid, doc); + reinjectNodeIfRemoved(creativeComment, doc, 'html'); + emitAdRenderSucceeded({ doc, bid, id }); + } else if ((doc === document && !inIframe()) || mediaType === 'video') { + const message = `Error trying to write ad. Ad render call ad id ${id} was prevented from writing to the main document.`; + emitAdRenderFail({reason: PREVENT_WRITING_ON_MAIN_DOCUMENT, message, bid, id}); + } else if (ad) { + doc.write(ad); + doc.close(); + setRenderSize(doc, width, height); + reinjectNodeIfRemoved(creativeComment, doc, 'html'); + callBurl(bid); + emitAdRenderSucceeded({ doc, bid, id }); + } else if (adUrl) { + const iframe = createInvisibleIframe(); + iframe.height = height; + iframe.width = width; + iframe.style.display = 'inline'; + iframe.style.overflow = 'hidden'; + iframe.src = adUrl; + + insertElement(iframe, doc, 'body'); + setRenderSize(doc, width, height); + reinjectNodeIfRemoved(creativeComment, doc, 'html'); + callBurl(bid); + emitAdRenderSucceeded({ doc, bid, id }); + } else { + const message = `Error trying to write ad. No ad for bid response id: ${id}`; + emitAdRenderFail({reason: NO_AD, message, bid, id}); + } + } catch (e) { + const message = `Error trying to write ad Id :${id} to the page:${e.message}`; + emitAdRenderFail({ reason: EXCEPTION, message, id }); } }); diff --git a/test/spec/modules/videoModule/coreVideo_spec.js b/test/spec/modules/videoModule/coreVideo_spec.js new file mode 100644 index 00000000000..17c6e3811e0 --- /dev/null +++ b/test/spec/modules/videoModule/coreVideo_spec.js @@ -0,0 +1,98 @@ +import { expect } from 'chai'; +import { VideoCore } from 'modules/videoModule/coreVideo.js'; + +describe('Video Core', function () { + const mockSubmodule = { + getOrtbVideo: sinon.spy(), + getOrtbContent: sinon.spy(), + setAdTagUrl: sinon.spy(), + onEvent: sinon.spy(), + offEvent: sinon.spy(), + }; + + const otherSubmodule = { + getOrtbVideo: () => {}, + getOrtbContent: () => {}, + setAdTagUrl: () => {}, + onEvent: () => {}, + offEvent: () => {}, + }; + + const testId = 'test_id'; + const testVendorCode = 0; + const otherId = 'other_id'; + const otherVendorCode = 1; + + const parentModuleMock = { + registerSubmodule: sinon.spy(), + getSubmodule: sinon.spy(id => { + if (id === testId) { + return mockSubmodule; + } else if (id === otherId) { + return otherSubmodule; + } + }) + }; + + const videoCore = VideoCore(parentModuleMock); + + videoCore.registerProvider({ + vendorCode: testVendorCode, + divId: testId + }); + + videoCore.registerProvider({ + vendorCode: otherVendorCode, + divId: otherId + }); + + describe('registerProvider', function () { + it('should delegate the registration to the Parent Module', function () { + expect(parentModuleMock.registerSubmodule.calledTwice).to.be.true; + expect(parentModuleMock.registerSubmodule.args[0][0]).to.be.equal(testId); + expect(parentModuleMock.registerSubmodule.args[1][0]).to.be.equal(otherId); + expect(parentModuleMock.registerSubmodule.args[0][1]).to.be.equal(testVendorCode); + expect(parentModuleMock.registerSubmodule.args[1][1]).to.be.equal(otherVendorCode); + }); + }); + + describe('getOrtbVideo', function () { + it('delegates to the submodule of the right divId', function () { + videoCore.getOrtbVideo(testId); + videoCore.getOrtbVideo(otherId); + expect(mockSubmodule.getOrtbVideo.calledOnce).to.be.true; + }); + }); + + describe('getOrtbContent', function () { + it('delegates to the submodule of the right divId', function () { + videoCore.getOrtbContent(testId); + videoCore.getOrtbContent(otherId); + expect(mockSubmodule.getOrtbContent.calledOnce).to.be.true; + }); + }); + + describe('setAdTagUrl', function () { + it('delegates to the submodule of the right divId', function () { + videoCore.setAdTagUrl('', testId); + videoCore.setAdTagUrl('', otherId); + expect(mockSubmodule.setAdTagUrl.calledOnce).to.be.true; + }); + }); + + describe('onEvents', function () { + it('delegates to the submodule of the right divId', function () { + videoCore.onEvents(['event'], () => {}, testId); + videoCore.onEvents(['event'], () => {}, otherId); + expect(mockSubmodule.onEvent.calledOnce).to.be.true; + }); + }); + + describe('offEvents', function () { + it('delegates to the submodule of the right divId', function () { + videoCore.offEvents(['event'], () => {}, testId); + videoCore.offEvents(['event'], () => {}, otherId); + expect(mockSubmodule.offEvent.calledOnce).to.be.true; + }); + }); +}); diff --git a/test/spec/modules/videoModule/pbVideo_spec.js b/test/spec/modules/videoModule/pbVideo_spec.js new file mode 100644 index 00000000000..cfd34ebd706 --- /dev/null +++ b/test/spec/modules/videoModule/pbVideo_spec.js @@ -0,0 +1,362 @@ +import { expect } from 'chai'; +import { PbVideo } from 'modules/videoModule'; +import CONSTANTS from 'src/constants.json'; + +let ortbVideoMock; +let ortbContentMock; +let videoCoreMock; +let getConfigMock; +let requestBidsMock; +let pbGlobalMock; +let pbEventsMock; +let videoEventsMock; +let gamSubmoduleMock; +let gamSubmoduleFactoryMock; +let videoImpressionVerifierFactoryMock; +let videoImpressionVerifierMock; + +function resetTestVars() { + ortbVideoMock = {}; + ortbContentMock = {}; + videoCoreMock = { + registerProvider: sinon.spy(), + onEvents: sinon.spy(), + getOrtbVideo: () => ortbVideoMock, + getOrtbContent: () => ortbContentMock, + setAdTagUrl: sinon.spy() + }; + getConfigMock = () => {}; + requestBidsMock = { + before: sinon.spy() + }; + pbGlobalMock = { + requestBids: requestBidsMock, + getHighestCpmBids: sinon.spy(), + getBidResponsesForAdUnitCode: sinon.spy(), + setConfig: sinon.spy(), + getConfig: () => ({}), + markWinningBidAsUsed: sinon.spy() + }; + pbEventsMock = { + emit: sinon.spy(), + on: sinon.spy() + }; + videoEventsMock = []; + gamSubmoduleMock = { + getAdTagUrl: sinon.spy() + }; + + gamSubmoduleFactoryMock = sinon.spy(() => gamSubmoduleMock); + + videoImpressionVerifierMock = { + trackBid: sinon.spy(), + getBidIdentifiers: sinon.spy() + }; + + videoImpressionVerifierFactoryMock = () => videoImpressionVerifierMock; +} + +let pbVideoFactory = (videoCore, getConfig, pbGlobal, pbEvents, videoEvents, gamSubmoduleFactory, videoImpressionVerifierFactory) => { + const pbVideo = PbVideo( + videoCore || videoCoreMock, + getConfig || getConfigMock, + pbGlobal || pbGlobalMock, + pbEvents || pbEventsMock, + videoEvents || videoEventsMock, + gamSubmoduleFactory || gamSubmoduleFactoryMock, + videoImpressionVerifierFactory || videoImpressionVerifierFactoryMock + ); + pbVideo.init(); + return pbVideo; +} + +describe('Prebid Video', function () { + beforeEach(() => resetTestVars()); + + describe('Setting video to config', function () { + let providers = [{ divId: 'div1' }, { divId: 'div2' }]; + let getConfigCallback; + let getConfig = (propertyName, callback) => { + if (propertyName === 'video') { + getConfigCallback = callback; + } + }; + + beforeEach(() => { + pbVideoFactory(null, getConfig); + getConfigCallback({ video: { providers } }); + }); + + it('Should register providers', function () { + expect(videoCoreMock.registerProvider.calledTwice).to.be.true; + }); + + it('Should register events', function () { + expect(videoCoreMock.onEvents.calledTwice).to.be.true; + const onEventsSpy = videoCoreMock.onEvents; + expect(onEventsSpy.getCall(0).args[2]).to.be.equal('div1'); + expect(onEventsSpy.getCall(1).args[2]).to.be.equal('div2'); + }); + + describe('Event triggering', function () { + it('Should emit events off of Prebid\'s Events', function () { + let eventHandler; + const videoCore = Object.assign({}, videoCoreMock, { + onEvents: (events, eventHandler_) => eventHandler = eventHandler_ + }); + pbVideoFactory(videoCore, getConfig); + getConfigCallback({ video: { providers } }); + const expectedType = 'test_event'; + const expectedPayload = {'test': 'data'}; + eventHandler(expectedType, expectedPayload); + expect(pbEventsMock.emit.calledOnce).to.be.true; + expect(pbEventsMock.emit.getCall(0).args[0]).to.be.equal('video' + expectedType.replace(/^./, expectedType[0].toUpperCase())); + expect(pbEventsMock.emit.getCall(0).args[1]).to.be.equal(expectedPayload); + }); + }); + + describe('Ad Server configuration', function() { + const test_vendor_code = 5; + const test_params = { test: 'params' }; + providers[0].adServer = { vendorCode: test_vendor_code, params: test_params }; + + it('should instantiate the GAM Submodule', function () { + expect(gamSubmoduleFactoryMock.calledOnce).to.be.true; + }); + }); + }); + + describe('Ad unit Enrichment', function () { + it('registers before:bidRequest hook', function () { + pbVideoFactory(); + expect(requestBidsMock.before.calledOnce).to.be.true; + }); + + it('requests oRtb params and writes them to ad unit and config', function() { + const getOrtbVideoSpy = videoCoreMock.getOrtbVideo = sinon.spy(() => ({ + test: 'videoTestValue' + })); + const getOrtbContentSpy = videoCoreMock.getOrtbContent = sinon.spy(() => ({ + test: 'contentTestValue' + })); + + let beforeBidRequestCallback; + const requestBids = { + before: callback_ => beforeBidRequestCallback = callback_ + }; + + pbVideoFactory(null, null, Object.assign({}, pbGlobalMock, { requestBids })); + expect(beforeBidRequestCallback).to.not.be.undefined; + const nextFn = sinon.spy(); + const adUnits = [{ + code: 'ad1', + mediaTypes: { + video: {} + }, + video: { divId: 'divId' } + }]; + beforeBidRequestCallback(nextFn, { adUnits }); + expect(getOrtbVideoSpy.calledOnce).to.be.true; + expect(getOrtbContentSpy.calledOnce).to.be.true; + const adUnit = adUnits[0]; + expect(adUnit.mediaTypes.video).to.have.property('test', 'videoTestValue'); + expect(nextFn.calledOnce).to.be.true; + expect(nextFn.getCall(0).args[0].ortb2).to.be.deep.equal({ site: { content: { test: 'contentTestValue' } } }); + }); + }); + + describe('Ad tag injection', function () { + let auctionEndCallback; + let providers = [{ divId: 'div1', adServer: {} }, { divId: 'div2' }]; + let getConfig = (propertyName, callbackFn) => { + if (propertyName === 'video') { + if (callbackFn) { + callbackFn({ video: { providers } }); + } else { + return { providers }; + } + } + }; + + const pbEvents = { + emit: () => {}, + on: (event, callback) => { + if (event === CONSTANTS.EVENTS.AUCTION_END) { + auctionEndCallback = callback + } + }, + off: () => {} + }; + + const expectedVendorCode = 5; + const expectedAdTag = 'test_tag'; + const expectedAdUnitCode = 'expectedAdUnitcode'; + const expectedDivId = 'expectedDivId'; + const expectedAdUnit = { + code: expectedAdUnitCode, + video: { + divId: expectedDivId, + adServer: { + vendorCode: expectedVendorCode, + baseAdTagUrl: expectedAdTag + } + } + }; + const auctionResults = { adUnits: [ expectedAdUnit, {} ] }; + + beforeEach(() => { + gamSubmoduleMock.getAdTagUrl.resetHistory(); + videoCoreMock.setAdTagUrl.resetHistory(); + }); + + let beforeBidRequestCallback; + const requestBids = { + before: callback_ => beforeBidRequestCallback = callback_ + }; + + it('should request ad tag url from adServer when configured to use adServer', function () { + const expectedVastUrl = 'expectedVastUrl'; + const expectedVastXml = 'expectedVastXml'; + const pbGlobal = Object.assign({}, pbGlobalMock, { + requestBids, + getHighestCpmBids: () => [{ + vastUrl: expectedVastUrl, + vastXml: expectedVastXml + }, {}, {}, {}] + }); + pbVideoFactory(null, getConfig, pbGlobal, pbEvents); + + beforeBidRequestCallback(() => {}, {}); + auctionEndCallback(auctionResults); + expect(gamSubmoduleMock.getAdTagUrl.calledOnce).to.be.true; + expect(gamSubmoduleMock.getAdTagUrl.getCall(0).args[0]).is.equal(expectedAdUnit); + expect(gamSubmoduleMock.getAdTagUrl.getCall(0).args[1]).is.equal(expectedAdTag); + }); + + it('should load ad tag when ad server returns ad tag', function () { + const expectedAdTag = 'resulting ad tag'; + const gamSubmoduleFactory = () => ({ + getAdTagUrl: () => expectedAdTag + }); + const expectedVastUrl = 'expectedVastUrl'; + const expectedVastXml = 'expectedVastXml'; + const pbGlobal = Object.assign({}, pbGlobalMock, { + requestBids, + getHighestCpmBids: () => [{ + vastUrl: expectedVastUrl, + vastXml: expectedVastXml + }, {}, {}, {}] + }); + pbVideoFactory(null, getConfig, pbGlobal, pbEvents, null, gamSubmoduleFactory); + beforeBidRequestCallback(() => {}, {}); + auctionEndCallback(auctionResults); + expect(videoCoreMock.setAdTagUrl.calledOnce).to.be.true; + expect(videoCoreMock.setAdTagUrl.args[0][0]).to.be.equal(expectedAdTag); + expect(videoCoreMock.setAdTagUrl.args[0][1]).to.be.equal(expectedDivId); + expect(videoCoreMock.setAdTagUrl.args[0][2]).to.have.property('adUnitCode', expectedAdUnitCode); + }); + + it('should load ad tag from highest bid when ad server is not configured', function () { + const expectedVastUrl = 'expectedVastUrl'; + const expectedVastXml = 'expectedVastXml'; + const pbGlobal = Object.assign({}, pbGlobalMock, { + requestBids, + getHighestCpmBids: () => [{ + vastUrl: expectedVastUrl, + vastXml: expectedVastXml + }, {}, {}, {}] + }); + const expectedAdUnit = { + code: expectedAdUnitCode, + video: { divId: expectedDivId } + }; + const auctionResults = { adUnits: [ expectedAdUnit, {} ] }; + + pbVideoFactory(null, () => ({ providers: [] }), pbGlobal, pbEvents); + beforeBidRequestCallback(() => {}, {}); + auctionEndCallback(auctionResults); + expect(videoCoreMock.setAdTagUrl.calledOnce).to.be.true; + expect(videoCoreMock.setAdTagUrl.args[0][0]).to.be.equal(expectedVastUrl); + expect(videoCoreMock.setAdTagUrl.args[0][1]).to.be.equal(expectedDivId); + expect(videoCoreMock.setAdTagUrl.args[0][2]).to.have.property('adUnitCode', expectedAdUnitCode); + expect(videoCoreMock.setAdTagUrl.args[0][2]).to.have.property('adXml', expectedVastXml); + }); + }); + + describe('Ad tracking', function () { + const expectedAdEventPayload = { adEventPayloadMarker: 'marker' }; + const expectedBid = { bidMarker: 'marker' }; + let bidAdjustmentCb; + let adImpressionCb; + let adErrorCb; + + const pbEvents = { + on: (event, callback) => { + if (event === CONSTANTS.EVENTS.BID_ADJUSTMENT) { + bidAdjustmentCb = callback; + } else if (event === 'videoAdImpression') { + adImpressionCb = callback; + } else if (event === 'videoAdError') { + adErrorCb = callback; + } + }, + emit: sinon.spy() + }; + + it('should ask Impression Verifier to track bid on Bid Adjustment', function () { + pbVideoFactory(null, null, null, pbEvents); + bidAdjustmentCb(); + expect(videoImpressionVerifierMock.trackBid.calledOnce).to.be.true; + }); + + it('should trigger video bid impression when the bid matched', function () { + pbEvents.emit.resetHistory(); + const pbGlobal = Object.assign({}, pbGlobalMock, { getBidResponsesForAdUnitCode: () => ({ bids: [expectedBid] }) }); + const videoImpressionVerifier = Object.assign({}, videoImpressionVerifierMock, { getBidIdentifiers: () => ({}) }); + pbVideoFactory(null, null, pbGlobal, pbEvents, null, null, () => videoImpressionVerifier); + adImpressionCb(expectedAdEventPayload); + + expect(pbEvents.emit.calledOnce).to.be.true; + expect(pbEvents.emit.getCall(0).args[0]).to.be.equal('videoBidImpression'); + const payload = pbEvents.emit.getCall(0).args[1]; + expect(payload.bid).to.be.equal(expectedBid); + expect(payload.adEvent).to.be.equal(expectedAdEventPayload); + expect(pbGlobal.markWinningBidAsUsed.calledOnce).to.be.true; + }); + + it('should trigger video bid error when the bid matched', function () { + pbEvents.emit.resetHistory(); + const pbGlobal = Object.assign({}, pbGlobalMock, { getBidResponsesForAdUnitCode: () => ({ bids: [expectedBid] }) }); + const videoImpressionVerifier = Object.assign({}, videoImpressionVerifierMock, { getBidIdentifiers: () => ({}) }); + pbVideoFactory(null, null, pbGlobal, pbEvents, null, null, () => videoImpressionVerifier); + adErrorCb(expectedAdEventPayload); + + expect(pbEvents.emit.calledOnce).to.be.true; + expect(pbEvents.emit.getCall(0).args[0]).to.be.equal('videoBidError'); + const payload = pbEvents.emit.getCall(0).args[1]; + expect(payload.bid).to.be.equal(expectedBid); + expect(payload.adEvent).to.be.equal(expectedAdEventPayload); + expect(pbGlobal.markWinningBidAsUsed.calledOnce).to.be.true; + }); + + it('should not trigger a bid impression when the bid did not match', function () { + pbEvents.emit.resetHistory(); + const pbGlobal = Object.assign({}, pbGlobalMock, { getBidResponsesForAdUnitCode: () => ({ bids: [expectedBid] }) }); + const videoImpressionVerifier = Object.assign({}, videoImpressionVerifierMock, { getBidIdentifiers: () => ({ auctionId: 'id' }) }); + pbVideoFactory(null, null, pbGlobal, pbEvents, null, null, () => videoImpressionVerifier); + adImpressionCb(expectedAdEventPayload); + + expect(pbEvents.emit.called).to.be.false; + }); + + it('should not trigger a bid error when the bid did not match', function () { + pbEvents.emit.resetHistory(); + const pbGlobal = Object.assign({}, pbGlobalMock, { getBidResponsesForAdUnitCode: () => ({ bids: [expectedBid] }) }); + const videoImpressionVerifier = Object.assign({}, videoImpressionVerifierMock, { getBidIdentifiers: () => ({ auctionId: 'id' }) }); + pbVideoFactory(null, null, pbGlobal, pbEvents, null, null, () => videoImpressionVerifier); + adErrorCb(expectedAdEventPayload); + + expect(pbEvents.emit.called).to.be.false; + }); + }); +}); diff --git a/test/spec/modules/videoModule/shared/parentModule_spec.js b/test/spec/modules/videoModule/shared/parentModule_spec.js new file mode 100644 index 00000000000..1e8e7fda380 --- /dev/null +++ b/test/spec/modules/videoModule/shared/parentModule_spec.js @@ -0,0 +1,73 @@ +import { SubmoduleBuilder, ParentModule } from 'libraries/video/shared/parentModule.js'; +import { expect } from 'chai'; + +describe('Parent Module', function() { + const idForMock = 0; + const vendorCodeForMock = 'a'; + const unrecognizedId = 999; + const unrecognizedVendorCode = 'zzz'; + const mockSubmodule = { test: 'test' }; + const mockSubmoduleBuilder = { + build: vendorCode => { + if (vendorCode === vendorCodeForMock) { + return mockSubmodule; + } else { + throw new Error('flawed'); + } + } + }; + const parentModule = ParentModule(mockSubmoduleBuilder); + + describe('Register Submodule', function () { + it('should throw when the builder fails to build', function () { + expect(() => parentModule.registerSubmodule(unrecognizedId, unrecognizedVendorCode)).to.throw('flawed'); + }); + }); + + describe('Get Submodule', function () { + it('should return registered submodules', function () { + parentModule.registerSubmodule(idForMock, vendorCodeForMock); + const submodule = parentModule.getSubmodule(idForMock); + expect(submodule).to.be.equal(mockSubmodule); + }); + + it('should return undefined when submodule is not registered', function () { + const submodule = parentModule.getSubmodule(unrecognizedId); + expect(submodule).to.be.undefined; + }); + }) +}); + +describe('Submodule Builder', function () { + const vendorCode1 = 1; + const vendorCode2 = 2; + const submodule1 = {}; + const initSpy = sinon.spy(); + const submodule2 = { init: initSpy }; + const submoduleFactory1 = () => submodule1; + const submoduleFactory2 = () => submodule2; + const submoduleFactory1Spy = sinon.spy(submoduleFactory1); + + const vendorDirectory = {}; + vendorDirectory[vendorCode1] = submoduleFactory1Spy; + vendorDirectory[vendorCode2] = submoduleFactory2; + + const submoduleBuilder = SubmoduleBuilder(vendorDirectory); + + it('should call submodule factory when vendor code is supported', function () { + const submodule = submoduleBuilder.build(vendorCode1); + expect(submoduleFactory1Spy.calledOnce).to.be.true; + expect(submodule).to.be.equal(submodule1); + }); + + it('should instantiate the submodule, when supported', function () { + const submodule = submoduleBuilder.build(vendorCode2); + expect(initSpy.calledOnce).to.be.true; + expect(submodule).to.be.equal(submodule2); + }); + + it('should throw when vendor code is not recognized', function () { + const unrecognizedVendorCode = 999; + expect(() => submoduleBuilder.build(unrecognizedVendorCode)).to.throw('Unrecognized submodule vendor code: ' + unrecognizedVendorCode); + }); +}); diff --git a/test/spec/modules/videoModule/shared/state_spec.js b/test/spec/modules/videoModule/shared/state_spec.js new file mode 100644 index 00000000000..94f3cb73411 --- /dev/null +++ b/test/spec/modules/videoModule/shared/state_spec.js @@ -0,0 +1,26 @@ +import stateFactory from 'libraries/video/shared/state.js'; +import { expect } from 'chai'; + +describe('State', function () { + let state = stateFactory(); + beforeEach(() => { + state.clearState(); + }); + + it('should update state', function () { + state.updateState({ 'test': 'a' }); + expect(state.getState()).to.have.property('test', 'a'); + state.updateState({ 'test': 'b' }); + expect(state.getState()).to.have.property('test', 'b'); + state.updateState({ 'test_2': 'c' }); + expect(state.getState()).to.have.property('test', 'b'); + expect(state.getState()).to.have.property('test_2', 'c'); + }); + + it('should clear state', function () { + state.updateState({ 'test': 'a' }); + state.clearState(); + expect(state.getState()).to.not.have.property('test', 'a'); + expect(state.getState()).to.be.empty; + }); +}); diff --git a/test/spec/modules/videoModule/shared/vastXmlBuilder_spec.js b/test/spec/modules/videoModule/shared/vastXmlBuilder_spec.js new file mode 100644 index 00000000000..2c67b898a53 --- /dev/null +++ b/test/spec/modules/videoModule/shared/vastXmlBuilder_spec.js @@ -0,0 +1,103 @@ +import { buildVastWrapper, getVastNode, getAdNode, getWrapperNode, getAdSystemNode, + getAdTagUriNode, getErrorNode, getImpressionNode } from 'libraries/video/shared/vastXmlBuilder.js'; +import { expect } from 'chai'; + +describe('buildVastWrapper', function () { + it('should include impression and error nodes when requested', function () { + const vastXml = buildVastWrapper( + 'adId123', + 'http://wwww.testUrl.com/redirectUrl.xml', + 'http://wwww.testUrl.com/impression.jpg', + 'impressionId123', + 'http://wwww.testUrl.com/error.jpg' + ); + expect(vastXml).to.be.equal(`Prebid org`); + }); + + it('should omit error nodes when excluded', function () { + const vastXml = buildVastWrapper( + 'adId123', + 'http://wwww.testUrl.com/redirectUrl.xml', + 'http://wwww.testUrl.com/impression.jpg', + 'impressionId123', + ); + expect(vastXml).to.be.equal(`Prebid org`); + }); + + it('should omit impression nodes when excluded', function () { + const vastXml = buildVastWrapper( + 'adId123', + 'http://wwww.testUrl.com/redirectUrl.xml', + ); + expect(vastXml).to.be.equal(`Prebid org`); + }); +}); + +describe('getVastNode', function () { + it('should return well formed Vast node', function () { + const vastNode = getVastNode('body', '4.0'); + expect(vastNode).to.be.equal('body'); + }); + + it('should omit version when missing', function() { + const vastNode = getVastNode('body'); + expect(vastNode).to.be.equal('body'); + }); +}); + +describe('getAdNode', function () { + it('should return well formed Ad node', function () { + const adNode = getAdNode('body', 'adId123'); + expect(adNode).to.be.equal('body'); + }); + + it('should omit id when missing', function() { + const adNode = getAdNode('body'); + expect(adNode).to.be.equal('body'); + }); +}); + +describe('getWrapperNode', function () { + it('should return well formed Wrapper node', function () { + const wrapperNode = getWrapperNode('body'); + expect(wrapperNode).to.be.equal('body'); + }); +}); + +describe('getAdSystemNode', function () { + it('should return well formed AdSystem node', function () { + const adSystemNode = getAdSystemNode('testSysName', '5.0'); + expect(adSystemNode).to.be.equal('testSysName'); + }); + + it('should omit version when missing', function() { + const adSystemNode = getAdSystemNode('testSysName'); + expect(adSystemNode).to.be.equal('testSysName'); + }); +}); + +describe('getAdTagUriNode', function () { + it('should return well formed ad tag URI node', function () { + const adTagNode = getAdTagUriNode('http://wwww.testUrl.com/ad.xml'); + expect(adTagNode).to.be.equal(''); + }); +}); + +describe('getImpressionNode', function () { + it('should return well formed Impression node', function () { + const impressionNode = getImpressionNode('http://wwww.testUrl.com/adImpression.jpg', 'impresionId123'); + expect(impressionNode).to.be.equal(''); + }); + + it('should omit id when missing', function() { + const impressionNode = getImpressionNode('http://wwww.testUrl.com/adImpression.jpg'); + expect(impressionNode).to.be.equal(''); + }); +}); + +describe('getErrorNode', function () { + it('should return well formed Error node', function () { + const errorNode = getErrorNode('http://wwww.testUrl.com/adError.jpg'); + expect(errorNode).to.be.equal(''); + }); +}); diff --git a/test/spec/modules/videoModule/shared/vastXmlEditor_spec.js b/test/spec/modules/videoModule/shared/vastXmlEditor_spec.js new file mode 100644 index 00000000000..2304b2f2833 --- /dev/null +++ b/test/spec/modules/videoModule/shared/vastXmlEditor_spec.js @@ -0,0 +1,209 @@ +import { vastXmlEditorFactory } from 'libraries/video/shared/vastXmlEditor.js'; +import { expect } from 'chai'; + +describe('Vast XML Editor', function () { + const adWrapperXml = ` + + + + Prebid org + + + + +`; + + const inlineXml = ` + + + + Prebid org + Random Title + + + +`; + + const inLineWithWrapper = ` + + + + Prebid org + + + + + + Prebid org + Random Title + + + +`; + + const vastXmlEditor = vastXmlEditorFactory(); + const expectedImpressionUrl = 'https://test.impression.com/ping.gif'; + const expectedImpressionId = 'test-impression-id'; + const expectedErrorUrl = 'https://test.error.com/ping.gif'; + + it('should add Impression Nodes to the Ad Wrapper', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(adWrapperXml, null, expectedImpressionUrl, expectedImpressionId); + const expectedXml = ` + + + Prebid org + + + +`; + expect(vastXml).to.equal(expectedXml); + }); + + it('should add Impression Nodes to the InLine', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(inlineXml, null, expectedImpressionUrl, expectedImpressionId); + const expectedXml = ` + + + Prebid org + Random Title + + +`; + expect(vastXml).to.equal(expectedXml); + }); + + it('should add Impression Nodes to the Ad Wrapper and Inline', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(inLineWithWrapper, null, expectedImpressionUrl, expectedImpressionId); + const expectedXml = ` + + + Prebid org + + + + + + Prebid org + Random Title + + +`; + expect(vastXml).to.equal(expectedXml); + }); + + it('should add Error Nodes to the Ad Wrapper', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(adWrapperXml, null, null, null, expectedErrorUrl); + const expectedXml = ` + + + Prebid org + + + +`; + expect(vastXml).to.equal(expectedXml); + }); + + it('should add Error Nodes to the InLine', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(inlineXml, null, null, null, expectedErrorUrl); + const expectedXml = ` + + + Prebid org + Random Title + + +`; + expect(vastXml).to.equal(expectedXml); + }); + + it('should add Error Nodes to the Ad Wrapper and Inline', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(inLineWithWrapper, null, null, null, expectedErrorUrl); + const expectedXml = ` + + + Prebid org + + + + + + Prebid org + Random Title + + +`; + expect(vastXml).to.equal(expectedXml); + }); + + it('should add Impression Nodes and Error Nodes to the Ad Wrapper', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(adWrapperXml, null, expectedImpressionUrl, expectedImpressionId, expectedErrorUrl); + const expectedXml = ` + + + Prebid org + + + +`; + expect(vastXml).to.equal(expectedXml); + }); + + it('should add Impression Nodes and Error Nodes to the InLine', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(inlineXml, null, expectedImpressionUrl, expectedImpressionId, expectedErrorUrl); + const expectedXml = ` + + + Prebid org + Random Title + + +`; + expect(vastXml).to.equal(expectedXml); + }); + + it('should add Impression Nodes and Error Nodes to the Ad Wrapper and Inline', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(inLineWithWrapper, null, expectedImpressionUrl, expectedImpressionId, expectedErrorUrl); + const expectedXml = ` + + + Prebid org + + + + + + Prebid org + Random Title + + +`; + expect(vastXml).to.equal(expectedXml); + }); + + it('should override the ad id in inline', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(inlineXml, 'adIdOverride'); + const expectedXml = ` + + + Prebid org + Random Title + + +`; + expect(vastXml).to.equal(expectedXml); + }); + + it('should override the ad id in the Ad Wrapper', function () { + const vastXml = vastXmlEditor.getVastXmlWithTracking(adWrapperXml, 'adIdOverride'); + const expectedXml = ` + + + Prebid org + + + +`; + expect(vastXml).to.equal(expectedXml); + }); +}); diff --git a/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js b/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js new file mode 100644 index 00000000000..399c115b820 --- /dev/null +++ b/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js @@ -0,0 +1,846 @@ +import { + JWPlayerProvider, + adStateFactory, + timeStateFactory, + callbackStorageFactory, + utils +} from 'modules/jwplayerVideoProvider'; + +import { + PROTOCOLS, API_FRAMEWORKS, VIDEO_MIME_TYPE, PLAYBACK_METHODS, PLACEMENT, VPAID_MIME_TYPE +} from 'libraries/video/constants/ortb.js'; + +import { + SETUP_COMPLETE, SETUP_FAILED, PLAY, AD_IMPRESSION, videoEvents +} from 'libraries/video/constants/events.js'; + +import { PLAYBACK_MODE } from 'libraries/video/constants/enums.js'; + +function getPlayerMock() { + return makePlayerFactoryMock({ + getState: function () {}, + setup: function () {}, + getViewable: function () {}, + getPercentViewable: function () {}, + getMute: function () {}, + getVolume: function () {}, + getConfig: function () {}, + getHeight: function () {}, + getWidth: function () {}, + getFullscreen: function () {}, + getPlaylistItem: function () {}, + playAd: function () {}, + on: function () {}, + off: function () {}, + remove: function () {}, + getAudioTracks: function () {}, + getCurrentAudioTrack: function () {}, + getPlugin: function () {}, + getFloating: function () {} + })(); +} + +function makePlayerFactoryMock(playerMock_) { + const playerFactory = function () { + return playerMock_; + } + playerFactory.version = '8.21.0'; + return playerFactory; +} + +function getUtilsMock() { + return { + getJwConfig: function () {}, + getSupportedMediaTypes: function () {}, + getStartDelay: function () {}, + getPlacement: function () {}, + getPlaybackMethod: function () {}, + isOmidSupported: function () {}, + getSkipParams: function () {}, + getJwEvent: event => event, + getIsoLanguageCode: function () {}, + getSegments: function () {}, + getContentDatum: function () {} + }; +} + +const sharedUtils = { videoEvents }; + +describe('JWPlayerProvider', function () { + describe('init', function () { + let config; + let adState; + let timeState; + let callbackStorage; + let utilsMock; + + beforeEach(() => { + config = {}; + adState = adStateFactory(); + timeState = timeStateFactory(); + callbackStorage = callbackStorageFactory(); + utilsMock = getUtilsMock(); + }); + + it('should trigger failure when jwplayer is missing', function () { + const provider = JWPlayerProvider(config, null, adState, timeState, callbackStorage, utilsMock, sharedUtils); + const setupFailed = sinon.spy(); + provider.onEvent(SETUP_FAILED, setupFailed, {}); + provider.init(); + expect(setupFailed.calledOnce).to.be.true; + const payload = setupFailed.args[0][1]; + expect(payload.errorCode).to.be.equal(-1); + }); + + it('should trigger failure when jwplayer version is under min supported version', function () { + let jwplayerMock = () => {}; + jwplayerMock.version = '8.20.0'; + const provider = JWPlayerProvider(config, jwplayerMock, adState, timeState, callbackStorage, utilsMock, sharedUtils); + const setupFailed = sinon.spy(); + provider.onEvent(SETUP_FAILED, setupFailed, {}); + provider.init(); + expect(setupFailed.calledOnce).to.be.true; + const payload = setupFailed.args[0][1]; + expect(payload.errorCode).to.be.equal(-2); + }); + + it('should instantiate the player when uninstantied', function () { + const player = getPlayerMock(); + config.playerConfig = {}; + const setupSpy = player.setup = sinon.spy(); + const provider = JWPlayerProvider(config, makePlayerFactoryMock(player), adState, timeState, callbackStorage, utilsMock, sharedUtils); + provider.init(); + expect(setupSpy.calledOnce).to.be.true; + }); + + it('should trigger setup complete when player is already instantied', function () { + const player = getPlayerMock(); + player.getState = () => 'idle'; + const provider = JWPlayerProvider(config, makePlayerFactoryMock(player), adState, timeState, callbackStorage, utilsMock, sharedUtils); + const setupComplete = sinon.spy(); + provider.onEvent(SETUP_COMPLETE, setupComplete, {}); + provider.init(); + expect(setupComplete.calledOnce).to.be.true; + }); + + it('should not reinstantiate player', function () { + const player = getPlayerMock(); + player.getState = () => 'idle'; + const setupSpy = player.setup = sinon.spy(); + const provider = JWPlayerProvider(config, makePlayerFactoryMock(player), adState, timeState, callbackStorage, utilsMock, sharedUtils); + provider.init(); + expect(setupSpy.called).to.be.false; + }); + }); + + describe('getId', function () { + it('should return configured div id', function () { + const provider = JWPlayerProvider({ divId: 'test_id' }, undefined, undefined, undefined, undefined, undefined, sharedUtils); + expect(provider.getId()).to.be.equal('test_id'); + }); + }); + + describe('getOrtbVideo', function () { + it('should populate oRTB Video params', function () { + const test_media_type = VIDEO_MIME_TYPE.MP4; + const test_height = 100; + const test_width = 200; + const test_start_delay = 5; + const test_placement = PLACEMENT.ARTICLE; + const test_battr = 'battr'; + const test_playback_method = PLAYBACK_METHODS.CLICK_TO_PLAY; + const test_skip = 0; + + const config = {}; + const player = getPlayerMock(); + const utils = getUtilsMock(); + + player.getConfig = () => ({ + advertising: { + battr: test_battr + } + }); + player.getHeight = () => test_height; + player.getWidth = () => test_width; + player.getFullscreen = () => true; // + + utils.getSupportedMediaTypes = () => [test_media_type]; + utils.getStartDelay = () => test_start_delay; + utils.getPlacement = () => test_placement; + utils.getPlaybackMethod = () => test_playback_method; + utils.isOmidSupported = () => true; // + utils.getSkipParams = () => ({ skip: test_skip }); + + const provider = JWPlayerProvider(config, makePlayerFactoryMock(player), adStateFactory(), {}, {}, utils, sharedUtils); + provider.init(); + let video = provider.getOrtbVideo(); + + expect(video.mimes).to.include(VIDEO_MIME_TYPE.MP4); + expect(video.protocols).to.include.members([ + PROTOCOLS.VAST_2_0, + PROTOCOLS.VAST_3_0, + PROTOCOLS.VAST_4_0, + PROTOCOLS.VAST_2_0_WRAPPER, + PROTOCOLS.VAST_3_0_WRAPPER, + PROTOCOLS.VAST_4_0_WRAPPER + ]); + expect(video.h).to.equal(test_height); + expect(video.w).to.equal(test_width); + expect(video.startdelay).to.equal(test_start_delay); + expect(video.placement).to.equal(test_placement); + expect(video.battr).to.equal(test_battr); + expect(video.maxextended).to.equal(-1); + expect(video.boxingallowed).to.equal(1); + expect(video.playbackmethod).to.include(test_playback_method); + expect(video.playbackend).to.equal(1); + expect(video.api).to.have.length(2); + expect(video.api).to.include.members([API_FRAMEWORKS.VPAID_2_0, API_FRAMEWORKS.OMID_1_0]); // + expect(video.skip).to.equal(test_skip); + expect(video.pos).to.equal(7); // + + player.getFullscreen = () => false; + utils.isOmidSupported = () => false; + + video = provider.getOrtbVideo(); + expect(video).to.not.have.property('pos'); + expect(video.api).to.have.length(1); + expect(video.api).to.include(API_FRAMEWORKS.VPAID_2_0); + expect(video.api).to.not.include(API_FRAMEWORKS.OMID_1_0); + }); + }); + + describe('getOrtbContent', function () { + it('should populate oRTB Content params', function () { + const test_item = { + mediaid: 'id', + file: 'file', + title: 'title', + iabCategories: 'iabCategories', + tags: 'keywords', + }; + const test_duration = 30; + let test_playback_mode = PLAYBACK_MODE.VOD;// + + const player = getPlayerMock(); + player.getPlaylistItem = () => test_item; + const utils = getUtilsMock(); + + const timeState = { + getState: () => ({ + duration: test_duration, + playbackMode: test_playback_mode + }) + } + + const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeState, {}, utils, sharedUtils); + provider.init(); + + let content = provider.getOrtbContent(); + expect(content.id).to.be.equal('jw_' + test_item.mediaid); + expect(content.url).to.be.equal(test_item.file); + expect(content.title).to.be.equal(test_item.title); + expect(content.cat).to.be.equal(test_item.iabCategories); + expect(content.keywords).to.be.equal(test_item.tags); + expect(content.len).to.be.equal(test_duration); + expect(content.livestream).to.be.equal(0);// + + test_playback_mode = PLAYBACK_MODE.LIVE; + + content = provider.getOrtbContent(); + expect(content.livestream).to.be.equal(1); + + test_playback_mode = PLAYBACK_MODE.DVR; + + content = provider.getOrtbContent(); + expect(content.livestream).to.be.equal(1); + }); + }); + + describe('setAdTagUrl', function () { + it('should call playAd', function () { + const player = getPlayerMock(); + const playAdSpy = player.playAd = sinon.spy(); + const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), {}, {}, {}, {}, sharedUtils); + provider.init(); + provider.setAdTagUrl('tag'); + expect(playAdSpy.called).to.be.true; + const argument = playAdSpy.args[0][0]; + expect(argument).to.be.equal('tag'); + }); + }); + + describe('events', function () { + it('should register event listener on player', function () { + const player = getPlayerMock(); + const onSpy = player.on = sinon.spy(); + const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), getUtilsMock(), sharedUtils); + provider.init(); + const callback = () => {}; + provider.onEvent(PLAY, callback, {}); + expect(onSpy.calledOnce).to.be.true; + const eventName = onSpy.args[0][0]; + expect(eventName).to.be.equal('play'); + }); + + it('should remove event listener on player', function () { + const player = getPlayerMock(); + const offSpy = player.off = sinon.spy(); + const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), utils, sharedUtils); + provider.init(); + const callback = () => {}; + provider.onEvent(AD_IMPRESSION, callback, {}); + provider.offEvent(AD_IMPRESSION, callback); + expect(offSpy.calledOnce).to.be.true; + const eventName = offSpy.args[0][0]; + expect(eventName).to.be.equal('adViewableImpression'); + }); + }); + + describe('destroy', function () { + it('should remove and null the player', function () { + const player = getPlayerMock(); + const removeSpy = player.remove = sinon.spy(); + player.remove = removeSpy; + const provider = JWPlayerProvider({}, makePlayerFactoryMock(player), adStateFactory(), timeStateFactory(), callbackStorageFactory(), getUtilsMock(), sharedUtils); + provider.init(); + provider.destroy(); + provider.destroy(); + expect(removeSpy.calledOnce).to.be.true; + }); + }); +}); + +describe('adStateFactory', function () { + let adState = adStateFactory(); + + beforeEach(() => { + adState.clearState(); + }); + + it('should update state for ad events', function () { + const tag = 'tag'; + const adPosition = 'adPosition'; + const timeLoading = 'timeLoading'; + const id = 'id'; + const description = 'description'; + const adsystem = 'adsystem'; + const adtitle = 'adtitle'; + const advertiserId = 'advertiserId'; + const advertiser = 'advertiser'; + const dealId = 'dealId'; + const linear = 'linear'; + const vastversion = 'vastversion'; + const mediaFile = 'mediaFile'; + const adId = 'adId'; + const universalAdId = 'universalAdId'; + const creativeAdId = 'creativeAdId'; + const creativetype = 'creativetype'; + const clickThroughUrl = 'clickThroughUrl'; + const witem = 'witem'; + const wcount = 'wcount'; + const podcount = 'podcount'; + const sequence = 'sequence'; + + adState.updateForEvent({ + tag, + adPosition, + timeLoading, + id, + description, + adsystem, + adtitle, + advertiserId, + advertiser, + dealId, + linear, + vastversion, + mediaFile, + adId, + universalAdId, + creativeAdId, + creativetype, + clickThroughUrl, + witem, + wcount, + podcount, + sequence + }); + + const state = adState.getState(); + expect(state.adTagUrl).to.equal(tag); + expect(state.offset).to.equal(adPosition); + expect(state.loadTime).to.equal(timeLoading); + expect(state.vastAdId).to.equal(id); + expect(state.adDescription).to.equal(description); + expect(state.adServer).to.equal(adsystem); + expect(state.adTitle).to.equal(adtitle); + expect(state.advertiserId).to.equal(advertiserId); + expect(state.dealId).to.equal(dealId); + expect(state.linear).to.equal(linear); + expect(state.vastVersion).to.equal(vastversion); + expect(state.creativeUrl).to.equal(mediaFile); + expect(state.adId).to.equal(adId); + expect(state.universalAdId).to.equal(universalAdId); + expect(state.creativeId).to.equal(creativeAdId); + expect(state.creativeType).to.equal(creativetype); + expect(state.redirectUrl).to.equal(clickThroughUrl); + expect(state).to.have.property('adPlacementType'); + expect(state.adPlacementType).to.be.undefined; + expect(state.waterfallIndex).to.equal(witem); + expect(state.waterfallCount).to.equal(wcount); + expect(state.adPodCount).to.equal(podcount); + expect(state.adPodIndex).to.equal(sequence); + }); + + it('should convert placement to oRTB value', function () { + adState.updateForEvent({ + placement: 'instream' + }); + + let state = adState.getState(); + expect(state.adPlacementType).to.be.equal(PLACEMENT.INSTREAM); + + adState.updateForEvent({ + placement: 'banner' + }); + + state = adState.getState(); + expect(state.adPlacementType).to.be.equal(PLACEMENT.BANNER); + + adState.updateForEvent({ + placement: 'article' + }); + + state = adState.getState(); + expect(state.adPlacementType).to.be.equal(PLACEMENT.ARTICLE); + + adState.updateForEvent({ + placement: 'feed' + }); + + state = adState.getState(); + expect(state.adPlacementType).to.be.equal(PLACEMENT.FEED); + + adState.updateForEvent({ + placement: 'interstitial' + }); + + state = adState.getState(); + expect(state.adPlacementType).to.be.equal(PLACEMENT.INTERSTITIAL); + + adState.updateForEvent({ + placement: 'slider' + }); + + state = adState.getState(); + expect(state.adPlacementType).to.be.equal(PLACEMENT.SLIDER); + + adState.updateForEvent({ + placement: 'floating' + }); + + state = adState.getState(); + expect(state.adPlacementType).to.be.equal(PLACEMENT.FLOATING); + }); +}); + +describe('timeStateFactory', function () { + let timeState = timeStateFactory(); + + beforeEach(() => { + timeState.clearState(); + }); + + it('should update state for VOD time event', function() { + const position = 5; + const test_duration = 30; + + timeState.updateForEvent({ + position, + duration: test_duration + }); + + const { time, duration, playbackMode } = timeState.getState(); + expect(time).to.be.equal(position); + expect(duration).to.be.equal(test_duration); + expect(playbackMode).to.be.equal(PLAYBACK_MODE.VOD); + }); + + it('should update state for LIVE time events', function() { + const position = 0; + const test_duration = 0; + + timeState.updateForEvent({ + position, + duration: test_duration + }); + + const { time, duration, playbackMode } = timeState.getState(); + expect(time).to.be.equal(position); + expect(duration).to.be.equal(test_duration); + expect(playbackMode).to.be.equal(PLAYBACK_MODE.LIVE); + }); + + it('should update state for DVR time events', function() { + const position = -5; + const test_duration = -30; + + timeState.updateForEvent({ + position, + duration: test_duration + }); + + const { time, duration, playbackMode } = timeState.getState(); + expect(time).to.be.equal(position); + expect(duration).to.be.equal(test_duration); + expect(playbackMode).to.be.equal(PLAYBACK_MODE.DVR); + }); +}); + +describe('callbackStorageFactory', function () { + let callbackStorage = callbackStorageFactory(); + + beforeEach(() => { + callbackStorage.clearStorage(); + }); + + it('should store callbacks', function () { + const callback1 = () => 'callback1'; + const eventHandler1 = () => 'eventHandler1'; + callbackStorage.storeCallback('event', eventHandler1, callback1); + + const callback2 = () => 'callback2'; + const eventHandler2 = () => 'eventHandler2'; + callbackStorage.storeCallback('event', eventHandler2, callback2); + + const callback3 = () => 'callback3'; + + expect(callbackStorage.getCallback('event', callback1)).to.be.equal(eventHandler1); + expect(callbackStorage.getCallback('event', callback2)).to.be.equal(eventHandler2); + expect(callbackStorage.getCallback('event', callback3)).to.be.undefined; + }); + + it('should remove callbacks after retrieval', function () { + const callback1 = () => 'callback1'; + const eventHandler1 = () => 'eventHandler1'; + callbackStorage.storeCallback('event', eventHandler1, callback1); + + expect(callbackStorage.getCallback('event', callback1)).to.be.equal(eventHandler1); + expect(callbackStorage.getCallback('event', callback1)).to.be.undefined; + }); + + it('should clear callbacks', function () { + const callback1 = () => 'callback1'; + const eventHandler1 = () => 'eventHandler1'; + callbackStorage.storeCallback('event', eventHandler1, callback1); + + callbackStorage.clearStorage(); + expect(callbackStorage.getCallback('event', callback1)).to.be.undefined; + }); +}); + +describe('utils', function () { + describe('getJwConfig', function () { + const getJwConfig = utils.getJwConfig; + it('should return undefined when no config is provided', function () { + let jwConfig = getJwConfig(); + expect(jwConfig).to.be.undefined; + + jwConfig = getJwConfig(null); + expect(jwConfig).to.be.undefined; + }); + + it('should set vendor config params to top level', function () { + let jwConfig = getJwConfig({ + params: { + vendorConfig: { + 'test': 'a', + 'test_2': 'b' + } + } + }); + expect(jwConfig.test).to.be.equal('a'); + expect(jwConfig.test_2).to.be.equal('b'); + }); + + it('should convert video module params', function () { + let jwConfig = getJwConfig({ + mute: true, + autoStart: true, + licenseKey: 'key' + }); + + expect(jwConfig.mute).to.be.true; + expect(jwConfig.autostart).to.be.true; + expect(jwConfig.key).to.be.equal('key'); + }); + + it('should apply video module params only when absent from vendor config', function () { + let jwConfig = getJwConfig({ + mute: true, + autoStart: true, + licenseKey: 'key', + params: { + vendorConfig: { + mute: false, + autostart: false, + key: 'other_key' + } + } + }); + + expect(jwConfig.mute).to.be.false; + expect(jwConfig.autostart).to.be.false; + expect(jwConfig.key).to.be.equal('other_key'); + }); + + it('should not convert undefined properties', function () { + let jwConfig = getJwConfig({ + params: { + vendorConfig: { + test: 'a' + } + } + }); + + expect(jwConfig).to.not.have.property('mute'); + expect(jwConfig).to.not.have.property('autostart'); + expect(jwConfig).to.not.have.property('key'); + }); + + it('should exclude fallback ad block when setupAds is explicitly disabled', function () { + let jwConfig = getJwConfig({ + setupAds: false, + params: { + + vendorConfig: {} + } + }); + + expect(jwConfig).to.not.have.property('advertising'); + }); + + it('should set advertising block when setupAds is allowed', function () { + let jwConfig = getJwConfig({ + params: { + vendorConfig: { + advertising: { + tag: 'test_tag' + } + } + } + }); + + expect(jwConfig).to.have.property('advertising'); + expect(jwConfig.advertising).to.have.property('tag', 'test_tag'); + }); + + it('should fallback to vast plugin', function () { + let jwConfig = getJwConfig({}); + + expect(jwConfig).to.have.property('advertising'); + expect(jwConfig.advertising).to.have.property('client', 'vast'); + }); + }); + describe('getSkipParams', function () { + const getSkipParams = utils.getSkipParams; + + it('should return an empty object when skip is not configured', function () { + let skipParams = getSkipParams({}); + expect(skipParams).to.be.empty; + }); + + it('should set skip to false when explicitly configured', function () { + let skipParams = getSkipParams({ + skipoffset: -1 + }); + expect(skipParams.skip).to.be.equal(0); + expect(skipParams.skipmin).to.be.undefined; + expect(skipParams.skipafter).to.be.undefined; + }); + + it('should be skippable when skip offset is set', function () { + const skipOffset = 3; + let skipParams = getSkipParams({ + skipoffset: skipOffset + }); + expect(skipParams.skip).to.be.equal(1); + expect(skipParams.skipmin).to.be.equal(skipOffset + 2); + expect(skipParams.skipafter).to.be.equal(skipOffset); + }); + }); + + describe('getSupportedMediaTypes', function () { + const getSupportedMediaTypes = utils.getSupportedMediaTypes; + + it('should always support VPAID', function () { + let supportedMediaTypes = getSupportedMediaTypes([]); + expect(supportedMediaTypes).to.include(VPAID_MIME_TYPE); + + supportedMediaTypes = getSupportedMediaTypes([VIDEO_MIME_TYPE.MP4]); + expect(supportedMediaTypes).to.include(VPAID_MIME_TYPE); + }); + }); + + describe('getPlacement', function () { + const getPlacement = utils.getPlacement; + + it('should be INSTREAM when not configured for outstream', function () { + let adConfig = {}; + let placement = getPlacement(adConfig); + expect(placement).to.be.equal(PLACEMENT.INSTREAM); + + adConfig = { outstream: false }; + placement = getPlacement(adConfig); + expect(placement).to.be.equal(PLACEMENT.INSTREAM); + }); + + it('should be FLOATING when player is floating', function () { + const player = getPlayerMock(); + player.getFloating = () => true; + const placement = getPlacement({outstream: true}, player); + expect(placement).to.be.equal(PLACEMENT.FLOATING); + }); + + it('should be the value defined in the ad config', function () { + const player = getPlayerMock(); + player.getFloating = () => false; + + let placement = getPlacement({placement: 'banner', outstream: true}, player); + expect(placement).to.be.equal(PLACEMENT.BANNER); + + placement = getPlacement({placement: 'article', outstream: true}, player); + expect(placement).to.be.equal(PLACEMENT.ARTICLE); + + placement = getPlacement({placement: 'feed', outstream: true}, player); + expect(placement).to.be.equal(PLACEMENT.FEED); + + placement = getPlacement({placement: 'interstitial', outstream: true}, player); + expect(placement).to.be.equal(PLACEMENT.INTERSTITIAL); + + placement = getPlacement({placement: 'slider', outstream: true}, player); + expect(placement).to.be.equal(PLACEMENT.SLIDER); + }); + + it('should be undefined when undetermined', function () { + const placement = getPlacement({ outstream: true }, getPlayerMock()); + expect(placement).to.be.undefined; + }); + }); + + describe('getPlaybackMethod', function() { + const getPlaybackMethod = utils.getPlaybackMethod; + + it('should return autoplay with sound', function() { + const playbackMethod = getPlaybackMethod({ + autoplay: true, + mute: false + }); + expect(playbackMethod).to.equal(PLAYBACK_METHODS.AUTOPLAY); + }); + + it('should return autoplay muted', function() { + const playbackMethod = getPlaybackMethod({ + autoplay: true, + mute: true + }); + expect(playbackMethod).to.equal(PLAYBACK_METHODS.AUTOPLAY_MUTED); + }); + + it('should treat autoplayAdsMuted as mute', function () { + const playbackMethod = getPlaybackMethod({ + autoplay: true, + autoplayAdsMuted: true + }); + expect(playbackMethod).to.equal(PLAYBACK_METHODS.AUTOPLAY_MUTED); + }); + + it('should return click to play', function() { + let playbackMethod = getPlaybackMethod({ autoplay: false }); + expect(playbackMethod).to.equal(PLAYBACK_METHODS.CLICK_TO_PLAY); + + playbackMethod = getPlaybackMethod({ + autoplay: false, + autoplayAdsMuted: true + }); + expect(playbackMethod).to.equal(PLAYBACK_METHODS.CLICK_TO_PLAY); + + playbackMethod = getPlaybackMethod({ + autoplay: false, + mute: true + }); + expect(playbackMethod).to.equal(PLAYBACK_METHODS.CLICK_TO_PLAY); + }); + }); + + describe('isOmidSupported', function () { + const isOmidSupported = utils.isOmidSupported; + const initialOmidSessionClient = window.OmidSessionClient; + afterEach(() => { + window.OmidSessionClient = initialOmidSessionClient; + }); + + it('should be true when Omid is loaded and client is VAST', function () { + window.OmidSessionClient = {}; + expect(isOmidSupported('vast')).to.be.true; + }); + + it('should be false when Omid is not present', function () { + expect(isOmidSupported('vast')).to.be.false; + }); + + it('should be false when client is not Vast', function () { + window.OmidSessionClient = {}; + expect(isOmidSupported('googima')).to.be.false; + expect(isOmidSupported('freewheel')).to.be.false; + expect(isOmidSupported('googimadai')).to.be.false; + expect(isOmidSupported('')).to.be.false; + expect(isOmidSupported(null)).to.be.false; + expect(isOmidSupported()).to.be.false; + }); + }); + + describe('getIsoLanguageCode', function () { + const sampleAudioTracks = [{language: 'ht'}, {language: 'fr'}, {language: 'es'}, {language: 'pt'}]; + + it('should return undefined when audio tracks are unavailable', function () { + const player = getPlayerMock(); + let languageCode = utils.getIsoLanguageCode(player); + expect(languageCode).to.be.undefined; + player.getAudioTracks = () => []; + languageCode = utils.getIsoLanguageCode(player); + expect(languageCode).to.be.undefined; + }); + + it('should return the first audio track language code if the getCurrentAudioTrack returns undefined', function () { + const player = getPlayerMock(); + player.getAudioTracks = () => sampleAudioTracks; + let languageCode = utils.getIsoLanguageCode(player); + expect(languageCode).to.be.equal('ht'); + }); + + it('should return the first audio track language code if the getCurrentAudioTrack returns null', function () { + const player = getPlayerMock(); + player.getAudioTracks = () => sampleAudioTracks; + player.getCurrentAudioTrack = () => null; + let languageCode = utils.getIsoLanguageCode(player); + expect(languageCode).to.be.equal('ht'); + }); + + it('should return the first audio track language code if the getCurrentAudioTrack returns -1', function () { + const player = getPlayerMock(); + player.getAudioTracks = () => sampleAudioTracks; + player.getCurrentAudioTrack = () => -1; + const languageCode = utils.getIsoLanguageCode(player); + expect(languageCode).to.be.equal('ht'); + }); + + it('should return the right audio track language code', function () { + const player = getPlayerMock(); + player.getAudioTracks = () => sampleAudioTracks; + player.getCurrentAudioTrack = () => 2; + const languageCode = utils.getIsoLanguageCode(player); + expect(languageCode).to.be.equal('es'); + }); + }); +}); diff --git a/test/spec/modules/videoModule/submodules/videojsVideoProvider_spec.js b/test/spec/modules/videoModule/submodules/videojsVideoProvider_spec.js new file mode 100644 index 00000000000..a7379ccbab2 --- /dev/null +++ b/test/spec/modules/videoModule/submodules/videojsVideoProvider_spec.js @@ -0,0 +1,391 @@ +// Using require style imports for fine grained control of import time +import { + SETUP_COMPLETE, SETUP_FAILED +} from 'libraries/video/constants/events.js'; + +const {VideojsProvider, utils} = require('modules/videojsVideoProvider'); + +const { + PROTOCOLS, API_FRAMEWORKS, VIDEO_MIME_TYPE, PLAYBACK_METHODS, PLACEMENT, VPAID_MIME_TYPE, AD_POSITION +} = require('libraries/video/constants/ortb.js'); + +const videojs = require('video.js').default; +require('videojs-playlist').default; +require('videojs-ima').default; +require('videojs-contrib-ads').default; + +describe('videojsProvider', function () { + let config; + let adState; + let timeState; + let callbackStorage; + + describe('init', function () { + beforeEach(() => { + config = {}; + document.body.innerHTML = ''; + }); + + it('should trigger failure when videojs is missing', function () { + const provider = VideojsProvider(config, null, adState, timeState, callbackStorage, utils); + const setupFailed = sinon.spy(); + provider.onEvent(SETUP_FAILED, setupFailed, {}); + provider.init(); + expect(setupFailed.calledOnce).to.be.true; + const payload = setupFailed.args[0][1]; + expect(payload.errorCode).to.be.equal(-1); + }); + + it('should trigger failure when videojs version is under min supported version', function () { + const provider = VideojsProvider(config, {...videojs, VERSION: '0.0.0'}, adState, timeState, callbackStorage, utils); + const setupFailed = sinon.spy(); + provider.onEvent(SETUP_FAILED, setupFailed, {}); + provider.init(); + expect(setupFailed.calledOnce).to.be.true; + const payload = setupFailed.args[0][1]; + expect(payload.errorCode).to.be.equal(-2); + }); + + it('should trigger failure when the div is not found', function () { + config.divId = 'fake-div' + const provider = VideojsProvider(config, videojs, adState, timeState, callbackStorage, utils); + const setupFailed = sinon.spy(); + provider.onEvent(SETUP_FAILED, setupFailed, {}); + provider.init(); + expect(setupFailed.calledOnce).to.be.true; + const payload = setupFailed.args[0][1]; + expect(payload.errorCode).to.be.equal(-3); + }); + + it('should instantiate the player when uninstantied', function () { + config.playerConfig = {testAttr: true}; + config.divId = 'test-div' + const div = document.createElement('div'); + div.setAttribute('id', 'test-div'); + document.body.appendChild(div); + + const mockVideojs = sinon.spy(); + const provider = VideojsProvider(config, mockVideojs, adState, timeState, callbackStorage, utils); + provider.init(); + expect(mockVideojs.calledOnce).to.be.true + }); + + it('should not reinstantiate the player', function () { + const div = document.createElement('div'); + div.setAttribute('id', 'test-div'); + document.body.appendChild(div); + const player = videojs(div, {}) + config.playerConfig = {}; + config.divId = 'test-div' + const provider = VideojsProvider(config, videojs, adState, timeState, callbackStorage, utils); + provider.init(); + expect(videojs.getPlayer('test-div')).to.be.equal(player) + videojs.getPlayer('test-div').dispose() + }); + + it('should trigger setup complete when player is already insantiated', function () { + const div = document.createElement('div'); + div.setAttribute('id', 'test-div'); + document.body.appendChild(div); + videojs(div, {}) + config.playerConfig = {}; + config.divId = 'test-div' + const provider = VideojsProvider(config, videojs, adState, timeState, callbackStorage, utils); + const setupComplete = sinon.spy(); + provider.onEvent(SETUP_COMPLETE, setupComplete, {}); + provider.init(); + expect(setupComplete.called).to.be.true; + videojs.getPlayer('test-div').dispose() + }); + }); + + describe('getId', function () { + it('should return configured div id', function () { + const provider = VideojsProvider({ divId: 'test_id' }); + expect(provider.getId()).to.be.equal('test_id'); + }); + }); + + describe('getOrtbParams', function () { + beforeEach(() => { + config = {divId: 'test'}; + // initialize videojs element + document.body.innerHTML = ` + `; + }); + + afterEach(() => { + const testPlayer = videojs('test'); + if (testPlayer && !testPlayer.isDisposed()) { + testPlayer.dispose(); + } + }); + + it('should populate oRTB Video and Content', function () { + const provider = VideojsProvider(config, videojs, adState, timeState, callbackStorage, utils); + provider.init(); + + const video = provider.getOrtbVideo(); + + expect(video.mimes).to.include(VIDEO_MIME_TYPE.MP4); + expect(video.protocols).to.deep.equal([2]); + expect(video.h).to.equal(100); + expect(video.w).to.equal(200); + + expect(video.maxextended).to.equal(-1); + expect(video.boxingallowed).to.equal(1); + expect(video.playbackmethod).to.include(PLAYBACK_METHODS.CLICK_TO_PLAY); + expect(video.playbackend).to.equal(1); + expect(video.api).to.deep.equal([2]); + expect(video.placement).to.be.equal(PLACEMENT.INSTREAM); + }); + + it('should populate oRTB Content', function () { + const provider = VideojsProvider(config, videojs, adState, timeState, callbackStorage, utils); + provider.init(); + + const content = provider.getOrtbContent(); + expect(content.url).to.be.equal('http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'); + expect(content).to.not.have.property('len'); + }); + + it('should change populated oRTB params when ima present', function () { + require('videojs-contrib-ads'); + require('videojs-ima'); + config.playerConfig = { + params: { + vendorConfig: { + mediaid: 'vendor-id', + advertising: { + tag: ['test-tag'] + } + } + } + } + + let provider = VideojsProvider(config, videojs, null, null, null, utils); + provider.init(); + const video = provider.getOrtbVideo(); + + expect(video.protocols).to.include(PROTOCOLS.VAST_2_0); + expect(video.api).to.include(API_FRAMEWORKS.VPAID_2_0); + expect(video.mimes).to.include(VPAID_MIME_TYPE); + }); + // + // We can't determine what type of outstream play is occuring + // if the src is absent so we should not set placement + it('should not set placement when src is absent', function() { + document.body.innerHTML = `` + const provider = VideojsProvider(config, videojs, null, null, null, utils); + provider.init(); + const video = provider.getOrtbVideo(); + expect(video).to.not.have.property('placement') + }) + // + it('should populate position when fullscreen', function () { + const provider = VideojsProvider(config, videojs, null, null, null, utils); + provider.init(); + const player = videojs.getPlayer('test') + player.isFullscreen = () => true; + const video = provider.getOrtbVideo(); + expect(video.pos).to.equal(7); + }); + // + it('should populate length when loaded', function () { + const provider = VideojsProvider(config, videojs, null, null, null, utils); + provider.init(); + const player = videojs.getPlayer('test') + player.readyState = () => 1 + player.duration = () => 100 + const content = provider.getOrtbContent(); + expect(content.len).to.equal(100); + }); + // + it('should return the correct playback method for autoplay', function () { + const provider = VideojsProvider(config, videojs, null, null, null, utils); + provider.init(); + const player = videojs.getPlayer('test') + player.autoplay(true) + const video = provider.getOrtbVideo(); + expect(video.playbackmethod).to.include(PLAYBACK_METHODS.AUTOPLAY); + }); + // + it('should return the correct playback method for autoplay muted', function () { + const provider = VideojsProvider(config, videojs, null, null, null, utils); + provider.init(); + const player = videojs.getPlayer('test') + player.muted = () => true + player.autoplay = () => true + const video = provider.getOrtbVideo(); + expect(video.playbackmethod).to.include(PLAYBACK_METHODS.AUTOPLAY_MUTED); + }); + // + it('should return the correct playback method for the other autoplay muted', function () { + const provider = VideojsProvider(config, videojs, null, null, null, utils); + provider.init(); + const player = videojs.getPlayer('test') + player.autoplay = () => 'muted' + const video = provider.getOrtbVideo(); + expect(video.playbackmethod).to.include(PLAYBACK_METHODS.AUTOPLAY_MUTED); + }); + }); +}); + +describe('utils', function() { + describe('getSetupConfig', function() { + it('should return undefined when config is absent', function () { + expect(utils.getSetupConfig()).to.be.undefined; + }); + + it('should give priority to vendorConfig', function () { + const config = { + autostart: false, + mute: false, + params: { + vendorConfig: { + autostart: true, + mute: true, + other: true + } + } + }; + const setupConfig = utils.getSetupConfig(config); + expect(setupConfig.autostart).to.be.true; + expect(setupConfig.mute).to.be.true; + expect(setupConfig.other).to.be.true; + }); + + it('should only global apply properties when absent from vendor config', function () { + const config = { + autostart: false, + params: { + vendorConfig: { + other: true + } + } + }; + const setupConfig = utils.getSetupConfig(config); + expect(setupConfig.autostart).to.be.false; + expect(setupConfig.mute).to.be.undefined; + expect(setupConfig.other).to.be.true; + }); + }); + + describe('getAdConfig', function () { + it('should return empty object when config is absent', function () { + expect(utils.getAdConfig()).to.deep.equal({}); + }); + + it('should return adPluginConfig', function () { + const config = { + params: { + adPluginConfig: { + vpaid: true, + } + } + }; + + expect(utils.getAdConfig(config)).to.be.equal(config.params.adPluginConfig); + }); + }); + + describe('getPositionCode', function() { + it('should return the correct position when video is above the fold', function () { + const code = utils.getPositionCode({ + left: window.innerWidth / 10, + top: 0, + width: window.innerWidth - window.innerWidth / 10, + height: window.innerHeight, + }) + expect(code).to.equal(AD_POSITION.ABOVE_THE_FOLD) + }); + + it('should return the correct position when video is below the fold', function () { + const code = utils.getPositionCode({ + left: window.innerWidth / 10, + top: window.innerHeight, + width: window.innerWidth - window.innerWidth / 10, + height: window.innerHeight / 2, + }) + expect(code).to.equal(AD_POSITION.BELOW_THE_FOLD) + }); + + it('should return the unkown position when the video is out of bounds', function () { + const code = utils.getPositionCode({ + left: window.innerWidth / 10, + top: window.innerHeight, + width: window.innerWidth, + height: window.innerHeight, + }) + expect(code).to.equal(AD_POSITION.UNKNOWN) + }); + }); + + describe('Playlist', function () { + const emptyPlayer = {}; + + describe('getPlaylistCount', function () { + it('should return 1 when playlist is absent', function () { + expect(utils.getPlaylistCount(emptyPlayer)).to.be.equal(1); + }); + + it('should return playlist length', function () { + document.body.innerHTML = ` + `; + const player = videojs('test', {}); + player.playlist([{ + sources: { src: 'sample.mp4' } + }, { + sources: { src: 'sample2.mp4' } + }]); + expect(utils.getPlaylistCount(player)).to.be.equal(2); + player.dispose(); + }); + }); + + describe('getCurrentPlaylistIndex', function () { + it('should return 0 when playlist is absent', function () { + expect(utils.getCurrentPlaylistIndex(emptyPlayer)).to.be.equal(0); + }); + }); + + describe('getCurrentPlaylistItem', function () { + it('should return undefined when playlist is absent', function () { + expect(utils.getCurrentPlaylistItem(emptyPlayer)).to.be.undefined; + }); + }); + }); + + describe('Get Media', function () { + describe('parseSource', function () { + it('should return src property when source is object', function () { + expect(utils.parseSource({ + src: 'test.url', + other: 'other' + })).to.be.equal('test.url'); + }); + + it('should return source when it is a string', function () { + expect(utils.parseSource('test.url')).to.be.equal('test.url'); + }); + + it('should return undefined when not object or string', function () { + expect(utils.parseSource(() => {})).to.be.undefined; + }); + }); + + describe('getMediaUrl', function () { + it('should return undefined when arg is missing', function () { + expect(utils.getMediaUrl()).to.be.undefined; + }); + + it('should parse first index when arg is array', function () { + expect(utils.getMediaUrl(['test.url.1', 'test.url.2'])).to.be.equal('test.url.1'); + }); + }); + }); +}) diff --git a/test/spec/modules/videoModule/videoImpressionVerifier_spec.js b/test/spec/modules/videoModule/videoImpressionVerifier_spec.js new file mode 100644 index 00000000000..58109219a37 --- /dev/null +++ b/test/spec/modules/videoModule/videoImpressionVerifier_spec.js @@ -0,0 +1,112 @@ +import { baseImpressionVerifier, PB_PREFIX } from 'modules/videoModule/videoImpressionVerifier.js'; + +let trackerMock; +trackerMock = { + store: sinon.spy(), + remove: sinon.spy() +} + +describe('Base Impression Verifier', function() { + describe('trackBid', function () { + it('should generate uuid', function () { + const baseVerifier = baseImpressionVerifier(trackerMock); + const uuid = baseVerifier.trackBid({}); + expect(uuid.substring(0, 3)).to.equal(PB_PREFIX); + expect(uuid.length).to.be.lessThan(16); + }); + }); + + describe('getBidIdentifiers', function () { + it('should match ad id to uuid', function () { + + }); + }); +}); + +/* +const adUnitCode = 'test_ad_unit_code'; +const sampleBid = { + adId: 'test_ad_id', + adUnitCode, + vastUrl: 'test_ad_url' +}; +const sampleAdUnit = { + code: adUnitCode, +}; + +const expectedImpressionUrl = 'test_impression_url'; +const expectedImpressionId = 'test_impression_id'; +const expectedErrorUrl = 'test_error_url'; +const expectedVastXml = 'test_xml'; + +it('should not modify the bid\'s adXml when the tracking config is omitted', function () { + const adUnit = Object.assign({}, sampleAdUnit, { video: { adServer: { tracking: null } } }); + const pbGlobal = Object.assign({}, pbGlobalMock, { adUnits: [ adUnit ] }); + pbVideoFactory(null, () => ({}), pbGlobal, pbEvents); + + bidAdjustmentCb(sampleBid); + // expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.called).to.be.false; + // expect(vastXmlEditorMock.buildVastWrapper.called).to.be.false; +}); + +it('should request a vast wrapper when only an ad url is provided', function () { + const adUnit = Object.assign({}, sampleAdUnit, { video: { adServer: { tracking: { } } } }); + const pbGlobal = Object.assign({}, pbGlobalMock, { adUnits: [ adUnit ] }); + pbVideoFactory(null, () => ({}), pbGlobal, pbEvents); + + bidAdjustmentCb(sampleBid); + // expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.called).to.be.false; + // expect(vastXmlEditorMock.buildVastWrapper.called).to.be.true; +}); + +it('should request the addition of tracking nodes when an ad xml is provided', function () { + const adUnit = Object.assign({}, sampleAdUnit, { video: { adServer: { tracking: { } } } }); + const pbGlobal = Object.assign({}, pbGlobalMock, { adUnits: [ adUnit ] }); + pbVideoFactory(null, () => ({}), pbGlobal, pbEvents); + + const bid = Object.assign({}, sampleBid, { vastXml: 'test_xml' }); + bidAdjustmentCb(bid); + // expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.called).to.be.true; + // expect(vastXmlEditorMock.buildVastWrapper.called).to.be.false; +}); + +it('should pass the tracking information as args to the xml editing function', function () { + const adUnit = Object.assign({}, sampleAdUnit, { video: { adServer: { tracking: { + impression: { + url: expectedImpressionUrl, + id: expectedImpressionId + }, + error: { + url: expectedErrorUrl + } + } } } }); + const pbGlobal = Object.assign({}, pbGlobalMock, { adUnits: [ adUnit ] }); + pbVideoFactory(null, () => ({}), pbGlobal, pbEvents); + + const bid = Object.assign({}, sampleBid, { vastXml: expectedVastXml }); + bidAdjustmentCb(bid); + // expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.called).to.be.true; + // expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.calledWith(expectedVastXml, expectedImpressionUrl, expectedImpressionId, expectedErrorUrl)) + // expect(vastXmlEditorMock.buildVastWrapper.called).to.be.false; +}); + +it('should generate the impression id when not specified in config', function () { + const adUnit = Object.assign({}, sampleAdUnit, { video: { adServer: { tracking: { + impression: { + url: expectedImpressionUrl, + }, + error: { + url: expectedErrorUrl + } + } } } }); + const pbGlobal = Object.assign({}, pbGlobalMock, { adUnits: [ adUnit ] }); + pbVideoFactory(null, () => ({}), pbGlobal, pbEvents); + + const bid = Object.assign({}, sampleBid, { vastXml: expectedVastXml }); + bidAdjustmentCb(bid); + const expectedGeneratedId = sampleBid.adId + '-impression'; + // expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.called).to.be.true; + // expect(vastXmlEditorMock.getVastXmlWithTrackingNodes.calledWith(expectedVastXml, expectedImpressionUrl, expectedGeneratedId, expectedErrorUrl)) + // expect(vastXmlEditorMock.buildVastWrapper.called).to.be.false; +}); +*/ diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index aac36ee76a1..4c1f5c3b455 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -1241,7 +1241,7 @@ describe('Unit: Prebid Module', function () { it('should require doc and id params', function () { $$PREBID_GLOBAL$$.renderAd(); - var error = 'Error trying to write ad Id :undefined to the page. Missing document or adId'; + var error = 'Error trying to write ad Id :undefined to the page. Missing adId'; assert.ok(spyLogError.calledWith(error), 'expected param error was logged'); }); From 21712ca1f99e573c51d217ddcc4a4f08273dfb9d Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Fri, 21 Oct 2022 12:21:48 -0700 Subject: [PATCH 052/367] PBJS-ORTB conversion library (#8738) * Automatically resolve libraries and their dependencies * Move AnalyticsAdapter under libraries * PBJS-ORTB conversion library * Update ortbConverter README * Improvements on request generation * refactor openxOrtbBidAdapter * Update README * Filter out imps that have no id * Fix nativeMapper logic * Prebid core: simplify native ORTB logic * Remove nativeMapper; do not mix ORTB request and response * fix lint * set bidRequest.nativeParams after ortb -> legacy conversion * Fix native trackers for native ortb responses (including Prebid Server) * Clean up native processors; add s2sConfig.ortbNative * Make ext.prebid.floors.enabled respect first party data * do not set placement for oustream video * Improvements * convert improvedigitalBidAdapter * Update openxOrtbBidAdapter * Improve video validation logic * Move skip validation back to improvedigital * Update README * Override (not merge) context.nativeRequest * Update improvedigital adapter * Address PR feedback on improvedigital * Fix tmax to s2sConfig.timeout for PBS adapter * PBS adapter: set source.ext.schain with the most commonly used schain * Remove dead code * Use auctionId for source.tid * Update package-lock * Set source.tid to auctionId * Update README * Update README * Update README --- libraries/ortbConverter/README.md | 378 +++++++++ libraries/ortbConverter/converter.js | 135 ++++ libraries/ortbConverter/lib/composer.js | 43 + .../ortbConverter/lib/mergeProcessors.js | 9 + libraries/ortbConverter/lib/sizes.js | 14 + libraries/ortbConverter/processors/banner.js | 40 + libraries/ortbConverter/processors/default.js | 167 ++++ .../ortbConverter/processors/mediaType.js | 21 + libraries/ortbConverter/processors/native.js | 37 + libraries/ortbConverter/processors/video.js | 66 ++ libraries/pbsExtensions/pbsExtensions.js | 12 + libraries/pbsExtensions/processors/aliases.js | 17 + .../pbsExtensions/processors/mediaType.js | 23 + libraries/pbsExtensions/processors/params.js | 22 + libraries/pbsExtensions/processors/pbs.js | 99 +++ .../processors/requestExtPrebid.js | 30 + libraries/pbsExtensions/processors/video.js | 23 + modules/consentManagement.js | 23 +- modules/consentManagementUsp.js | 11 +- modules/currency.js | 9 + modules/improvedigitalBidAdapter.js | 620 ++++----------- modules/multibid/index.js | 12 + modules/openxOrtbBidAdapter.js | 395 +++------- modules/prebidServerBidAdapter/index.js | 735 +----------------- .../prebidServerBidAdapter/ortbConverter.js | 274 +++++++ modules/priceFloors.js | 72 ++ modules/schain.js | 25 +- modules/userId/index.js | 11 +- package-lock.json | 12 +- src/pbjsORTB.js | 35 + src/utils.js | 21 + src/utils/currency.js | 16 + .../modules/improvedigitalBidAdapter_spec.js | 356 ++++----- test/spec/modules/openxOrtbBidAdapter_spec.js | 126 +-- .../modules/prebidServerBidAdapter_spec.js | 276 +++---- test/spec/ortbConverter/banner_spec.js | 203 +++++ test/spec/ortbConverter/composer_spec.js | 69 ++ test/spec/ortbConverter/converter_spec.js | 283 +++++++ test/spec/ortbConverter/currency_spec.js | 40 + .../ortbConverter/default_processors_spec.js | 61 ++ test/spec/ortbConverter/gdpr_spec.js | 38 + test/spec/ortbConverter/mediaTypes_spec.js | 67 ++ .../ortbConverter/mergeProcessors_spec.js | 59 ++ test/spec/ortbConverter/multibid_spec.js | 35 + test/spec/ortbConverter/native_spec.js | 95 +++ test/spec/ortbConverter/pbjsORTB_spec.js | 67 ++ .../pbsExtensions/aliases_spec.js | 57 ++ .../pbsExtensions/params_spec.js | 96 +++ .../ortbConverter/pbsExtensions/video_spec.js | 52 ++ test/spec/ortbConverter/priceFloors_spec.js | 143 ++++ test/spec/ortbConverter/schain_spec.js | 33 + test/spec/ortbConverter/userId_spec.js | 21 + test/spec/ortbConverter/usp_spec.js | 15 + test/spec/ortbConverter/video_spec.js | 189 +++++ test/spec/utils_spec.js | 46 +- 55 files changed, 3970 insertions(+), 1864 deletions(-) create mode 100644 libraries/ortbConverter/README.md create mode 100644 libraries/ortbConverter/converter.js create mode 100644 libraries/ortbConverter/lib/composer.js create mode 100644 libraries/ortbConverter/lib/mergeProcessors.js create mode 100644 libraries/ortbConverter/lib/sizes.js create mode 100644 libraries/ortbConverter/processors/banner.js create mode 100644 libraries/ortbConverter/processors/default.js create mode 100644 libraries/ortbConverter/processors/mediaType.js create mode 100644 libraries/ortbConverter/processors/native.js create mode 100644 libraries/ortbConverter/processors/video.js create mode 100644 libraries/pbsExtensions/pbsExtensions.js create mode 100644 libraries/pbsExtensions/processors/aliases.js create mode 100644 libraries/pbsExtensions/processors/mediaType.js create mode 100644 libraries/pbsExtensions/processors/params.js create mode 100644 libraries/pbsExtensions/processors/pbs.js create mode 100644 libraries/pbsExtensions/processors/requestExtPrebid.js create mode 100644 libraries/pbsExtensions/processors/video.js create mode 100644 modules/prebidServerBidAdapter/ortbConverter.js create mode 100644 src/pbjsORTB.js create mode 100644 src/utils/currency.js create mode 100644 test/spec/ortbConverter/banner_spec.js create mode 100644 test/spec/ortbConverter/composer_spec.js create mode 100644 test/spec/ortbConverter/converter_spec.js create mode 100644 test/spec/ortbConverter/currency_spec.js create mode 100644 test/spec/ortbConverter/default_processors_spec.js create mode 100644 test/spec/ortbConverter/gdpr_spec.js create mode 100644 test/spec/ortbConverter/mediaTypes_spec.js create mode 100644 test/spec/ortbConverter/mergeProcessors_spec.js create mode 100644 test/spec/ortbConverter/multibid_spec.js create mode 100644 test/spec/ortbConverter/native_spec.js create mode 100644 test/spec/ortbConverter/pbjsORTB_spec.js create mode 100644 test/spec/ortbConverter/pbsExtensions/aliases_spec.js create mode 100644 test/spec/ortbConverter/pbsExtensions/params_spec.js create mode 100644 test/spec/ortbConverter/pbsExtensions/video_spec.js create mode 100644 test/spec/ortbConverter/priceFloors_spec.js create mode 100644 test/spec/ortbConverter/schain_spec.js create mode 100644 test/spec/ortbConverter/userId_spec.js create mode 100644 test/spec/ortbConverter/usp_spec.js create mode 100644 test/spec/ortbConverter/video_spec.js diff --git a/libraries/ortbConverter/README.md b/libraries/ortbConverter/README.md new file mode 100644 index 00000000000..31f56b4c754 --- /dev/null +++ b/libraries/ortbConverter/README.md @@ -0,0 +1,378 @@ +# Prebid.js - ORTB conversion library + +This library provides methods to convert Prebid.js bid request objects to ORTB requests, +and ORTB responses to Prebid.js bid response objects. + +## Usage + +The simplest way to use this from an adapter is: + +```javascript +import {ortbConverter} from '../../libraries/ortbConverter/converter.js' + +const converter = ortbConverter({ + context: { + // `netRevenue` and `ttl` are required properties of bid responses - provide a default for them + netRevenue: true, // or false if your adapter should set bidResponse.netRevenue = false + ttl: 30 // default bidResponse.ttl (when not specified in ORTB response.seatbid[].bid[].exp) + } +}); + +registerBidder({ + // ... rest of your spec goes here ... + buildRequests(bidRequests, bidderRequest) { + const data = converter.toORTB({bidRequests, bidderRequest}) + // you may need to adjust `data` to suit your needs - see "customization" below + return [{ + method: METHOD, + url: ENDPOINT_URL, + data + }] + }, + interpretResponse(response, request) { + const bids = converter.fromORTB({response: response.body, request: request.data}).bids; + // likewise, you may need to adjust the bid response objects + return bids; + }, +}) +``` + +Without any customization, the library will generate complete ORTB requests, but ignores your [bid params](#params). +If your endpoint sets `response.seatbid[].bid[].mtype` (part of the ORTB 2.6 spec), it will also parse the response into complete bidResponse objects. See [setting response mediaTypes](#response-mediaTypes) if that is not the case. + +### Module-specific conversions + +Prebid.js features that require a module also require it for their corresponding ORTB conversion logic. For example, `imp.bidfloor` is only populated if the `priceFloors` module is active; `request.cur` needs the `currency` module, and so on. Notably, this means that to get those fields populated from your unit tests, you must import those modules first; see [this suite](https://github.com/prebid/Prebid.js/blob/master/test/spec/modules/openxOrtbBidAdapter_spec.js) for an example. + +## Customization + +### Modifying return values directly + +You are free to modify the objects returned by both `toORTB` and `fromORTB`: + +```javascript +const data = converter.toORTB({bidRequests, bidderRequest}); +deepSetValue(data.imp[0], 'ext.myCustomParam', bidRequests[0].params.myCustomParam); +``` + +However, there are two restrictions (to avoid them, use the [other customization options](#fine-customization)): + + - you may not change the `imp[].id` returned by `toORTB`; they ared used internally to match responses to their requests. + ```javascript + const data = converter.toORTB({bidRequests, bidderRequest}); + data.imp[0].id = 'custom-imp-id' // do not do this - it will cause an error later in `fromORTB` + ``` + See also [overriding `imp.id`](#imp-id). + - the `request` argument passed to `fromORTB` must be the same object returned by `toORTB`. + ```javascript + let data = converter.toORTB({bidRequests, bidderRequest}); + + data = mergeDeep( // the original object is lost + {ext: {myCustomParam: bidRequests[0].params.myCustomParam}}, // `fromORTB` will later throw an error + data + ); + + // do this instead: + mergeDeep( + data, + {ext: {myCustomParam: bidRequests[0].params.myCustomParam}}, + data + ) + ``` + + +### Fine grained customization - imp, request, bidResponse, response + +When invoked, `toORTB({bidRequests, bidderRequest})` first loops through each request in `bidRequests`, converting them into ORTB `imp` objects. +It then packages them into a single ORTB request, adding other parameters that are not imp-specific (such as for example `request.tmax`). + +Likewise, `fromORTB({request, response})` first loops through each `response.seatbid[].bid[]`, converting them into Prebid bidResponses; it then packages them into +a single return value. + +You can customize each of these steps using the `ortbConverter` arguments `imp`, `request`, `bidResponse` and `response`: + +### Customizing imps: `imp(buildImp, bidRequest, context)` + +Invoked once for each input `bidRequest`; should return the ORTB `imp` object to include in the request. +The arguments are: + +- `buildImp`: a function taking `(bidRequest, context)` and returning an ORTB `imp` object; +- `bidRequest`: the bid request object to convert; +- `context`: a [context object](#context) that contains at least: + - `bidderRequest`: the `bidderRequest` argument passed to `toORTB`. + +#### Example: attaching custom bid params + +```javascript +const converter = ortbConverter({ + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + deepSetValue(imp, 'ext.params', bidRequest.params); + return imp; + } +}) +``` + +#### Example: overriding imp.id + +```javascript +const converter = ortbConverter({ + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + imp.id = randomIdentifierStr(); + return imp; + } +}) +``` + +### Customizing the request: `request(buildRequest, imps, bidderRequest, context)` + +Invoked once after all bidRequests have been converted into `imp`s; should return the complete ORTB request. The return value +of this function is also the return value of `toORTB`. +The arguments are: + +- `buildRequest`: a function taking `(imps, bidderRequest, context)` and returning an ORTB request object; +- `imps` an array of ORTB `imp` objects that should be included in the request; +- `bidderRequest`: the `bidderRequest` argument passed to `toORTB`; +- `context`: a [context object](#context) that contains at least: + - `bidRequests`: the `bidRequests` argument passed to `toORTB`. + +#### Example: setting additional request properties + +```javascript +const converter = ortbConverter({ + request(buildRequest, imps, bidderRequest, context) { + const request = buildRequest(imps, bidderRequest, context); + deepSetValue(request, 'ext.adapterVersion', '0.0.1'); + return request; + } +}) +``` + +### Customizing bid responses: `bidResponse(buildBidResponse, bid, context)` + +Invoked once for each `seatbid[].bid[]` in the response; should return the corresponding Prebid.js bid response object. +The arguments are: +- `buildBidResponse`: a function taking `(bid, context)` and returning a Prebid.js bid response object; +- `bid`: an ORTB `seatbid[].bid[]` object; +- `context`: a [context object](#context) that contains at least: + - `seatbid`: the ORTB `seatbid[]` object that encloses `bid`; + - `imp`: the ORTB request's `imp` object that matches `bid.impid`; + - `bidRequest`: the Prebid.js bid request object that was used to generate `context.imp`; + - `ortbRequest`: the `request` argument passed to `fromORTB`; + - `ortbResponse`: the `response` argument passed to `fromORTB`. + +#### Example: setting a custom outstream renderer + +```javascript +const converter = ortbConverter({ + bidResponse(buildBidResponse, bid, context) { + const bidResponse = buildBidResponse(bid, context); + const {bidRequest} = context; + if (bidResponse.mediaType === VIDEO && bidRequest.mediaTypes.video.context === 'outstream') { + bidResponse.renderer = Renderer.install({ + url: RENDERER_URL, + id: bidRequest.bidId, + adUnitCode: bidRequest.adUnitCode + }); + } + return bidResponse; + } +}) +``` + +#### Example: setting response mediaType + +In ORTB 2.5, bid responses do not specify their mediatype, which is something Prebid.js requires. You can provide it as +`context.mediaType`: + +```javascript +const converter = ortbConverter({ + bidResponse(buildBidResponse, bid, context) { + context.mediaType = deepAccess(bid, 'ext.mediaType'); + return buildBidResponse(bid, context) + } +}) +``` + +If you know that a particular ORTB request/response pair deals with exclusively one mediaType, you may also pass it directly in the [context parameter](#context). +Note that - compared to the above - this has additional effects, because `context.mediaType` is also considered during `imp` generation - see [special context properties](#special-context). + +```javascript +converter.toORTB({ + bidRequests: bidRequests.filter(isVideoBid), + bidderRequest, + context: {mediaType: 'video'} // make everything in this request/response deal with video only +}) +``` + +Note that this will _not_ work as intended: + +```javascript + +const converter = ortbConverter({ + bidResponse(buildBidResponse, bid, context) { + const bidResponse = buildBidResponse(bid, context); // this throws; buildBidResponse needs to know the + // mediaType to properly populate bidResponse.ad, + // bidResponse.native etc + bidResponse.mediaType = deepAccess(bid, 'ext.mediaType'); // too late, use context.mediaType + return bidResponse; + } +}); + +``` + +### Customizing the response: `response(buildResponse, bidResponses, ortbResponse, context)` + +Invoked once, after all `seatbid[].bid[]` objects have been converted to corresponding bid responses. The value returned +by this function is also the value returned by `fromORTB`. +The arguments are: + +- `buildResponse`: a function that takes `(bidResponses, ortbResponse, context)` and returns `{bids: bidResponses}`. In the future, this may contain additional response data not necessarily tied to any bid (for example fledge auction configuration). +- `bidResponses`: array of Prebid.js bid response objects +- `ortbResponse`: the `response` argument passed to `fromORTB` +- `context`: a [context object](#context) that contains at least: + - `ortbRequest`: the `request` argument passed to `fromORTB`; + - `bidderRequest`: the `bidderRequest` argument passed to `toORTB`; + - `bidRequests`: the `bidRequests` argument passed to `toORTB`. + +#### Example: logging server-side errors + +```javascript +const converter = ortbConverter({ + response(buildResponse, bidResponses, ortbResponse, context) { + (deepAccess(ortbResponse, 'ext.errors') || []).forEach((e) => logWarn('Server error', e)); + return buildResponse(bidResponses, ortbResponse, context); + } +}) +``` + +### Even finer grained customization - processor overrides + +Each of the four conversion steps described above - imp, request, bidResponse and response - is further broken down into +smaller units of work (called _processors_). For example, when the currency module is included, it adds a _request processor_ +that sets `request.cur`; the priceFloors module adds an _imp processor_ that sets `imp.bidfloor` and `imp.bidfloorcur`, and so on. + +Each processor can be overridden or disabled through the `overrides` argument: + +#### Example: disabling currency +```javascript +const converter = ortbConverter({ + overrides: { + request: { + currency: false + } + } +}) +``` + +The above is similar in effect to: + +```javascript +const converter = ortbConverter({ + request(buildRequest, imps, bidderRequest, context) { + const request = buildRequest(imps, bidderRequest, context); + delete request.cur; + return request; + } +}) +``` + +With the main difference being that setting `currency: false` will disable currency logic entirely, while the `request` +version will still set `request.cur`, then delete it. If the currency processor is ever updated to deal with more than just `request.cur`, the `request` +function will also need to be updated accordingly. + +#### Example: taking video parameters from `bidRequest.params.video` + +Processors can also be overridden: + +```javascript +const converter = ortbConverter({ + overrides: { + imp: { + video(orig, imp, bidRequest, context) { + // `orig` is the video imp processor, which looks at bidRequest.mediaTypes[VIDEO] + // to populate imp.video + // alter its input `bidRequest` to also pick up parameters from `bidRequest.params` + let videoParams = bidRequest.mediaTypes[VIDEO]; + if (videoParams) { + videoParams = Object.assign({}, videoParams, bidRequest.params.video); + bidRequest = {...bidRequest, mediaTypes: {[VIDEO]: videoParams}} + } + orig(imp, bidRequest, context); + } + } + } +}); +``` + +#### Processor override functions + +Processor overrides are similar to the override options described above, except that they take the object to process as argument: + +- `imp` processor overrides take `(orig, imp, bidRequest, context)`, where: + - `orig` is the processor function being overridden, which itself takes `(imp, bidRequest, context)`; + - `imp` is the (partial) imp object to modify; + - `bidRequest` and `context` are the same arguments passed to [imp](#imp). +- `request` processor overrides take `(orig, ortbRequest, bidderRequest, context)`, where: + - `orig` is the processor function being overridden, and takes `(ortbRequest, bidderRequest, context)`; + - `ortbRequest` is the partial request to modify; + - `bidderRequest` and `context` are the same arguments passed to [request](#reuqest). +- `bidResponse` processor overrides take `(orig, bidResponse, bid, context)`, where: + - `orig` is the processor function being overridden, and takes `(bidResponse, bid, context)`; + - `bidResponse` is the partial bid response to modify; + - `bid` and `context` are the same arguments passed to [bidResponse](#bidResponse) +- `response` processor overrides take `(orig, response, ortbResponse, context)`, where: + - `orig` is the processor function being overriden, and takes `(response, ortbResponse, context)`; + - `response` is the partial response to modify; + - `ortbRespones` and `context` are the same arguments passed to [response](#response). + +### The `context` argument + +All customization functions take a `context` argument. This is a plain JS object that is shared between `request` and its corresponding `response`; and between `imp` and its corresponding `bidResponse`: + +```javascript +const converter = ortbConverter({ + imp(buildImp, bidRequest, context) { + // `context` here will be later passed to `bidResponse` (if one matches the imp generated here) + context.someData = somethingInterestingAbout(bidRequest); + return buildImp(bidRequest, context); + }, + bidResponse(buildBidResponse, bid, context) { + const bidResponse = buildBidResponse(bid, context); + doSomethingWith(context.someData); + return bidResponse; + } +}) +``` + +`ortbConverter` automatically populates `context` with some values of interest, such as `bidRequest`, `bidderRequest`, etc - as detailed above. In addition, you may pass additional context properties through: + +- the `context` argument of `ortbConverter`: e.g. `ortbConverter({context: {ttl: 30}})`. This will set `context.ttl = 30` globally for the converter. +- the `context` argument of `toORTB`: e.g. `converter.toORTB({bidRequests, bidderRequest, context: {ttl: 30}})`. This will set `context.ttl = 30` only for this request. + +### Special `context` properties + +For ease of use, the conversion logic gives special meaning to some context properties: + + - `currency`: a currency string (e.g. `'EUR'`). If specified, overrides the currency to use for computing price floors and `request.cur`. If omitted, both default to `getConfig('currency.adServerCurrency')`. + - `mediaType`: a bid mediaType (`'banner'`, `'video'`, or `'native'`). If specified: + - disables `imp` generation for other media types (i.e., if `context.mediaType === 'banner'`, only `imp.banner` will be populated; `imp.video` and `imp.native` will not, even if the bid request specifies them); + - is passed as the `mediaType` option to `bidRequest.getFloor` when computing price floors; + - sets `bidResponse.mediaType`. + - `nativeRequest`: a plain object that serves as the base value for `imp.native.request` (and is relevant only for native bid requests). + If not specified, the only property that is guaranteed to be populated is `assets`, since Prebid does not require anything else to define a native adUnit. You can use `context.nativeRequest` to provide other properties; for example, you may want to signal support for native impression trackers by setting it to `{eventtrackers: [{event: 1, methods: [1, 2]}]}` (see also the [ORTB Native spec](https://www.iab.com/wp-content/uploads/2018/03/OpenRTB-Native-Ads-Specification-Final-1.2.pdf)). + - `netRevenue`: the value to set as `bidResponse.netRevenue`. This is a required property of bid responses that does not have a clear ORTB counterpart. + - `ttl`: the default value to use for `bidResponse.ttl` (if the ORTB response does not provide one in `seatbid[].bid[].exp`). + +## Prebid Server extensions + +If your endpoint is a Prebid Server instance, you may take advantage of the `pbsExtension` companion library, which adds a number of processors that can populate and parse PBS-specific extensions (typically prefixed `ext.prebid`); these include bidder params (with `transformBidParams`), bidder aliases, targeting keys, and others. + +```javascript +import {pbsExtensions} from '../../libraries/pbsExtensions/pbsExtensions.js' + +const pbsConverter = ortbConverter({ + processors: pbsExtensions +}) +``` diff --git a/libraries/ortbConverter/converter.js b/libraries/ortbConverter/converter.js new file mode 100644 index 00000000000..2057af8b6d3 --- /dev/null +++ b/libraries/ortbConverter/converter.js @@ -0,0 +1,135 @@ +import {compose} from './lib/composer.js'; +import {logError, memoize} from '../../src/utils.js'; +import {DEFAULT_PROCESSORS} from './processors/default.js'; +import {BID_RESPONSE, DEFAULT, getProcessors, IMP, REQUEST, RESPONSE} from '../../src/pbjsORTB.js'; +import {mergeProcessors} from './lib/mergeProcessors.js'; + +export function ortbConverter({ + context: defaultContext = {}, + processors = defaultProcessors, + overrides = {}, + imp, + request, + bidResponse, + response, +} = {}) { + const REQ_CTX = new WeakMap(); + + function builder(slot, wrapperFn, builderFn, errorHandler) { + let build; + return function () { + if (build == null) { + build = (function () { + let delegate = builderFn.bind(this, compose(processors()[slot] || {}, overrides[slot] || {})); + if (wrapperFn) { + delegate = wrapperFn.bind(this, delegate); + } + return function () { + try { + return delegate.apply(this, arguments); + } catch (e) { + errorHandler.call(this, e, ...arguments); + } + } + })(); + } + return build.apply(this, arguments); + } + } + + const buildImp = builder(IMP, imp, + function (process, bidRequest, context) { + const imp = {}; + process(imp, bidRequest, context); + return imp; + }, + function (error, bidRequest, context) { + logError('Error while converting bidRequest to ORTB imp; request skipped.', {error, bidRequest, context}); + } + ); + + const buildRequest = builder(REQUEST, request, + function (process, imps, bidderRequest, context) { + const ortbRequest = {imp: imps}; + process(ortbRequest, bidderRequest, context); + return ortbRequest; + }, + function (error, imps, bidderRequest, context) { + logError('Error while converting to ORTB request', {error, imps, bidderRequest, context}); + throw error; + } + ); + + const buildBidResponse = builder(BID_RESPONSE, bidResponse, + function (process, bid, context) { + const bidResponse = {}; + process(bidResponse, bid, context); + return bidResponse; + }, + function (error, bid, context) { + logError('Error while converting ORTB seatbid.bid to bidResponse; bid skipped.', {error, bid, context}); + } + ); + + const buildResponse = builder(RESPONSE, response, + function (process, bidResponses, ortbResponse, context) { + const response = {bids: bidResponses}; + process(response, ortbResponse, context); + return response; + }, + function (error, bidResponses, ortbResponse, context) { + logError('Error while converting from ORTB response', {error, bidResponses, ortbResponse, context}); + throw error; + } + ); + + return { + toORTB({bidderRequest, bidRequests, context = {}}) { + bidRequests = bidRequests || bidderRequest.bids; + const ctx = { + req: Object.assign({bidRequests}, defaultContext, context), + imp: {} + } + const imps = bidRequests.map(bidRequest => { + const impContext = Object.assign({bidderRequest, reqContext: ctx.req}, defaultContext, context); + const result = buildImp(bidRequest, impContext); + if (result != null) { + if (result.hasOwnProperty('id')) { + impContext.bidRequest = bidRequest; + ctx.imp[result.id] = impContext; + return result; + } + logError('Converted ORTB imp does not specify an id, ignoring bid request', bidRequest, result); + } + }).filter(Boolean); + + const request = buildRequest(imps, bidderRequest, ctx.req); + ctx.req.bidderRequest = bidderRequest; + if (request != null) { + REQ_CTX.set(request, ctx); + } + return request; + }, + fromORTB({request, response}) { + const ctx = REQ_CTX.get(request); + if (ctx == null) { + throw new Error('ortbRequest passed to `fromORTB` must be the same object returned by `toORTB`') + } + function augmentContext(ctx, extraParams = {}) { + return Object.assign({ortbRequest: request}, extraParams, ctx); + } + const impsById = Object.fromEntries((request.imp || []).map(imp => [imp.id, imp])); + const bidResponses = (response.seatbid || []).flatMap(seatbid => + (seatbid.bid || []).map((bid) => { + if (impsById.hasOwnProperty(bid.impid) && ctx.imp.hasOwnProperty(bid.impid)) { + return buildBidResponse(bid, augmentContext(ctx.imp[bid.impid], {imp: impsById[bid.impid], seatbid, ortbResponse: response})); + } + logError('ORTB response seatbid[].bid[].impid does not match any imp in request; ignoring bid', bid); + }) + ).filter(Boolean); + return buildResponse(bidResponses, response, augmentContext(ctx.req)); + } + } +} + +export const defaultProcessors = memoize(() => mergeProcessors(DEFAULT_PROCESSORS, getProcessors(DEFAULT))); diff --git a/libraries/ortbConverter/lib/composer.js b/libraries/ortbConverter/lib/composer.js new file mode 100644 index 00000000000..0ceff7f9edb --- /dev/null +++ b/libraries/ortbConverter/lib/composer.js @@ -0,0 +1,43 @@ +const SORTED = new WeakMap(); + +/** + * @typedef {Object} Component + * A component function, that can be composed with other compatible functions into one. + * Compatible functions take the same arguments; return values are ignored. + * + * @property {function} fn the component function; + * @property {number} priority determines the order in which this function will run when composed with others. + */ + +/** + * + * @param {Object[string, Component]} components to compose + * @param {Object[string, function|boolean]} overrides a map from component name, to a function that should override that component. + * Override functions are replacements, except that they get the original function they are overriding as their first argument. If the override + * is `false`, the component is disabled. + * + * @return a function that will run all components in order of priority, with functions from `overrides` taking + * precedence over components that match names + */ +export function compose(components, overrides = {}) { + if (!SORTED.has(components)) { + const sorted = Object.entries(components); + sorted.sort((a, b) => { + a = a[1].priority || 0; + b = b[1].priority || 0; + return a === b ? 0 : a > b ? -1 : 1 + }); + SORTED.set(components, sorted.map(([name, cmp]) => [name, cmp.fn])) + } + const fns = SORTED.get(components) + .filter(([name]) => !overrides.hasOwnProperty(name) || overrides[name]) + .map(function ([name, fn]) { + return overrides.hasOwnProperty(name) ? overrides[name].bind(this, fn) : fn; + }); + return function () { + const args = Array.from(arguments); + fns.forEach(fn => { + fn.apply(this, args); + }) + } +} diff --git a/libraries/ortbConverter/lib/mergeProcessors.js b/libraries/ortbConverter/lib/mergeProcessors.js new file mode 100644 index 00000000000..357cecd45aa --- /dev/null +++ b/libraries/ortbConverter/lib/mergeProcessors.js @@ -0,0 +1,9 @@ +import {PROCESSOR_TYPES} from '../../../src/pbjsORTB.js'; + +export function mergeProcessors(...processors) { + const left = processors.shift(); + const right = processors.length > 1 ? mergeProcessors(...processors) : processors[0]; + return Object.fromEntries( + PROCESSOR_TYPES.map(type => [type, Object.assign({}, left[type], right[type])]) + ) +} diff --git a/libraries/ortbConverter/lib/sizes.js b/libraries/ortbConverter/lib/sizes.js new file mode 100644 index 00000000000..16b75048203 --- /dev/null +++ b/libraries/ortbConverter/lib/sizes.js @@ -0,0 +1,14 @@ +import {parseSizesInput} from '../../../src/utils.js'; + +export function sizesToFormat(sizes) { + sizes = parseSizesInput(sizes); + + // get sizes in form [{ w: , h: }, ...] + return sizes.map(size => { + const [width, height] = size.split('x'); + return { + w: parseInt(width, 10), + h: parseInt(height, 10) + }; + }); +} diff --git a/libraries/ortbConverter/processors/banner.js b/libraries/ortbConverter/processors/banner.js new file mode 100644 index 00000000000..51c93b652ef --- /dev/null +++ b/libraries/ortbConverter/processors/banner.js @@ -0,0 +1,40 @@ +import {createTrackPixelHtml, deepAccess, inIframe, mergeDeep} from '../../../src/utils.js'; +import {BANNER} from '../../../src/mediaTypes.js'; +import {sizesToFormat} from '../lib/sizes.js'; + +/** + * fill in a request `imp` with banner parameters from `bidRequest`. + */ +export function fillBannerImp(imp, bidRequest, context) { + if (context.mediaType && context.mediaType !== BANNER) return; + + const bannerParams = deepAccess(bidRequest, 'mediaTypes.banner'); + if (bannerParams) { + const banner = { + topframe: inIframe() === true ? 0 : 1 + }; + if (bannerParams.sizes) { + banner.format = sizesToFormat(bannerParams.sizes); + } + if (bannerParams.hasOwnProperty('pos')) { + banner.pos = bannerParams.pos; + } + + imp.banner = mergeDeep(banner, imp.banner); + } +} + +export function bannerResponseProcessor({createPixel = (url) => createTrackPixelHtml(decodeURIComponent(url))} = {}) { + return function fillBannerResponse(bidResponse, bid) { + if (bidResponse.mediaType === BANNER) { + if (bid.adm && bid.nurl) { + bidResponse.ad = bid.adm; + bidResponse.ad += createPixel(bid.nurl); + } else if (bid.adm) { + bidResponse.ad = bid.adm; + } else if (bid.nurl) { + bidResponse.adUrl = bid.nurl; + } + } + }; +} diff --git a/libraries/ortbConverter/processors/default.js b/libraries/ortbConverter/processors/default.js new file mode 100644 index 00000000000..70acb7c9953 --- /dev/null +++ b/libraries/ortbConverter/processors/default.js @@ -0,0 +1,167 @@ +import {deepSetValue, getDefinedParams, getDNT, mergeDeep} from '../../../src/utils.js'; +import {bannerResponseProcessor, fillBannerImp} from './banner.js'; +import {fillVideoImp, fillVideoResponse} from './video.js'; +import {setResponseMediaType} from './mediaType.js'; +import {fillNativeImp, fillNativeResponse} from './native.js'; +import {BID_RESPONSE, IMP, REQUEST} from '../../../src/pbjsORTB.js'; +import {config} from '../../../src/config.js'; + +export const DEFAULT_PROCESSORS = { + [REQUEST]: { + fpd: { + // sets initial request to bidderRequest.ortb2 + priority: 99, + fn(ortbRequest, bidderRequest) { + mergeDeep(ortbRequest, bidderRequest.ortb2) + } + }, + // override FPD app, site, and device with getConfig('app'), etc if defined + // TODO: these should be deprecated for v8 + appFpd: fpdFromTopLevelConfig('app'), + siteFpd: fpdFromTopLevelConfig('site'), + deviceFpd: fpdFromTopLevelConfig('device'), + device: { + // sets device w / h / ua / language + fn: setDevice + }, + site: { + // sets site.domain, page, and ref from refererInfo + fn: setSite + }, + props: { + // sets request properties id, tmax, test, source.tid + fn(ortbRequest, bidderRequest) { + Object.assign(ortbRequest, { + id: ortbRequest.id || bidderRequest.auctionId, + test: ortbRequest.test || 0 + }); + const timeout = parseInt(bidderRequest.timeout, 10); + if (!isNaN(timeout)) { + ortbRequest.tmax = timeout; + } + deepSetValue(ortbRequest, 'source.tid', ortbRequest.source?.tid || bidderRequest.auctionId); + } + }, + coppa: { + fn(ortbRequest) { + const coppa = config.getConfig('coppa'); + if (typeof coppa === 'boolean') { + deepSetValue(ortbRequest, 'regs.coppa', coppa ? 1 : 0); + } + } + }, + }, + [IMP]: { + fpd: { + // sets initial imp to bidRequest.ortb2Imp + priority: 99, + fn(imp, bidRequest) { + mergeDeep(imp, bidRequest.ortb2Imp); + } + }, + id: { + // sets imp.id + fn(imp, bidRequest) { + imp.id = bidRequest.bidId; + } + }, + banner: { + // populates imp.banner + fn: fillBannerImp + }, + video: { + // populates imp.video + fn: fillVideoImp + }, + pbadslot: { + // removes imp.ext.data.pbaslot if it's not a string + // TODO: is this needed? + fn(imp) { + const pbadslot = imp.ext?.data?.pbadslot; + if (!pbadslot || typeof pbadslot !== 'string') { + delete imp.ext?.data?.pbadslot; + } + } + } + }, + [BID_RESPONSE]: { + mediaType: { + // sets bidResponse.mediaType from context.mediaType, falling back to seatbid.bid[].mtype + priority: 99, + fn: setResponseMediaType + }, + banner: { + // sets banner response attributes if bidResponse.mediaType === BANNER + fn: bannerResponseProcessor(), + }, + video: { + // sets video response attributes if bidResponse.mediaType === VIDEO + fn: fillVideoResponse + }, + props: { + // sets base bidResponse properties common to all types of bids + fn(bidResponse, bid, context) { + Object.entries({ + requestId: context.bidRequest?.bidId, + seatBidId: bid.id, + cpm: bid.price, + currency: context.ortbResponse.cur || context.currency, + width: bid.w, + height: bid.h, + dealId: bid.dealid, + creative_id: bid.crid, + creativeId: bid.crid, + burl: bid.burl, + ttl: bid.exp || context.ttl, + netRevenue: context.netRevenue, + }).filter(([k, v]) => typeof v !== 'undefined') + .forEach(([k, v]) => bidResponse[k] = v); + if (!bidResponse.meta) { + bidResponse.meta = {}; + } + if (bid.adomain) { + bidResponse.meta.advertiserDomains = bid.adomain; + } + } + } + } +} + +if (FEATURES.NATIVE) { + DEFAULT_PROCESSORS[IMP].native = { + // populates imp.native + fn: fillNativeImp + } + DEFAULT_PROCESSORS[BID_RESPONSE].native = { + // populates bidResponse.native if bidResponse.mediaType === NATIVE + fn: fillNativeResponse + } +} + +function fpdFromTopLevelConfig(prop) { + return { + priority: 90, // after FPD from 'ortb2', before the rest + fn(ortbRequest) { + const data = config.getConfig(prop); + if (typeof data === 'object') { + ortbRequest[prop] = data; + } + } + } +} + +export function setDevice(ortbRequest) { + ortbRequest.device = Object.assign({ + w: window.innerWidth, + h: window.innerHeight, + dnt: getDNT() ? 1 : 0, + ua: window.navigator.userAgent, + language: window.navigator.language.split('-').shift() + }, ortbRequest.device); +} + +export function setSite(ortbRequest, bidderRequest) { + if (bidderRequest.refererInfo) { + ortbRequest.site = Object.assign(getDefinedParams(bidderRequest.refererInfo, ['page', 'domain', 'ref']), ortbRequest.site); + } +} diff --git a/libraries/ortbConverter/processors/mediaType.js b/libraries/ortbConverter/processors/mediaType.js new file mode 100644 index 00000000000..67232b3ca44 --- /dev/null +++ b/libraries/ortbConverter/processors/mediaType.js @@ -0,0 +1,21 @@ +import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes.js'; + +export const ORTB_MTYPES = { + 1: BANNER, + 2: VIDEO, + 4: NATIVE +} + +/** + * Sets response mediaType, using ORTB 2.6 `seatbid.bid[].mtype`. + * + * Note that this will throw away bids if there is no `mtype` in the response. + */ +export function setResponseMediaType(bidResponse, bid, context) { + if (bidResponse.mediaType) return; + const mediaType = context.mediaType; + if (!mediaType && !ORTB_MTYPES.hasOwnProperty(bid.mtype)) { + throw new Error('Cannot determine mediaType for response') + } + bidResponse.mediaType = mediaType || ORTB_MTYPES[bid.mtype]; +} diff --git a/libraries/ortbConverter/processors/native.js b/libraries/ortbConverter/processors/native.js new file mode 100644 index 00000000000..ff231ce2b55 --- /dev/null +++ b/libraries/ortbConverter/processors/native.js @@ -0,0 +1,37 @@ +import {isPlainObject, logWarn, mergeDeep} from '../../../src/utils.js'; +import {NATIVE} from '../../../src/mediaTypes.js'; + +export function fillNativeImp(imp, bidRequest, context) { + if (context.mediaType && context.mediaType !== NATIVE) return; + let nativeReq = bidRequest.nativeOrtbRequest; + if (nativeReq) { + nativeReq = Object.assign({}, context.nativeRequest, nativeReq); + if (nativeReq.assets?.length) { + imp.native = mergeDeep({}, { + request: JSON.stringify(nativeReq), + ver: nativeReq.ver + }, imp.native) + } else { + logWarn('mediaTypes.native is set, but no assets were specified. Native request skipped.', bidRequest) + } + } +} + +export function fillNativeResponse(bidResponse, bid) { + if (bidResponse.mediaType === NATIVE) { + let ortb; + if (typeof bid.adm === 'string') { + ortb = JSON.parse(bid.adm); + } else { + ortb = bid.adm; + } + + if (isPlainObject(ortb) && Array.isArray(ortb.assets)) { + bidResponse.native = { + ortb, + } + } else { + throw new Error('ORTB native response contained no assets'); + } + } +} diff --git a/libraries/ortbConverter/processors/video.js b/libraries/ortbConverter/processors/video.js new file mode 100644 index 00000000000..5fe411e6bcf --- /dev/null +++ b/libraries/ortbConverter/processors/video.js @@ -0,0 +1,66 @@ +import {deepAccess, isEmpty, logWarn, mergeDeep} from '../../../src/utils.js'; +import {VIDEO} from '../../../src/mediaTypes.js'; +import {sizesToFormat} from '../lib/sizes.js'; + +// parameters that share the same name & semantics between pbjs adUnits and imp.video +const ORTB_VIDEO_PARAMS = new Set([ + 'pos', + 'placement', + 'api', + 'mimes', + 'protocols', + 'playbackmethod', + 'minduration', + 'maxduration', + 'w', + 'h', + 'startdelay', + 'placement', + 'linearity', + 'skip', + 'skipmin', + 'skipafter', + 'minbitrate', + 'maxbitrate', + 'delivery', + 'playbackend' +]); + +const PLACEMENT = { + 'instream': 1, +} + +export function fillVideoImp(imp, bidRequest, context) { + if (context.mediaType && context.mediaType !== VIDEO) return; + + const videoParams = deepAccess(bidRequest, 'mediaTypes.video'); + if (!isEmpty(videoParams)) { + const video = Object.fromEntries( + Object.entries(videoParams) + .filter(([name]) => ORTB_VIDEO_PARAMS.has(name)) + ); + if (videoParams.playerSize) { + const format = sizesToFormat(videoParams.playerSize); + if (format.length > 1) { + logWarn('video request specifies more than one playerSize; all but the first will be ignored') + } + Object.assign(video, format[0]); + } + const placement = PLACEMENT[videoParams.context]; + if (placement != null) { + video.placement = placement; + } + imp.video = mergeDeep(video, imp.video); + } +} + +export function fillVideoResponse(bidResponse, seatbid, context) { + if (bidResponse.mediaType === VIDEO) { + if (deepAccess(context.imp, 'video.w') && deepAccess(context.imp, 'video.h')) { + [bidResponse.playerWidth, bidResponse.playerHeight] = [context.imp.video.w, context.imp.video.h]; + } + + if (seatbid.adm) { bidResponse.vastXml = seatbid.adm; } + if (seatbid.nurl) { bidResponse.vastUrl = seatbid.nurl; } + } +} diff --git a/libraries/pbsExtensions/pbsExtensions.js b/libraries/pbsExtensions/pbsExtensions.js new file mode 100644 index 00000000000..1efded6173f --- /dev/null +++ b/libraries/pbsExtensions/pbsExtensions.js @@ -0,0 +1,12 @@ +import {mergeProcessors} from '../ortbConverter/lib/mergeProcessors.js'; +import {PBS_PROCESSORS} from './processors/pbs.js'; +import {getProcessors, PBS} from '../../src/pbjsORTB.js'; +import {defaultProcessors} from '../ortbConverter/converter.js'; +import {memoize} from '../../src/utils.js'; + +/** + * ORTB converter processor set that understands Prebid Server extensions. + * + * Pass this as the `processors` option to `ortbConverter` if your backend is a PBS instance. + */ +export const pbsExtensions = memoize(() => mergeProcessors(defaultProcessors(), PBS_PROCESSORS, getProcessors(PBS))); diff --git a/libraries/pbsExtensions/processors/aliases.js b/libraries/pbsExtensions/processors/aliases.js new file mode 100644 index 00000000000..3dcd2c4fd9b --- /dev/null +++ b/libraries/pbsExtensions/processors/aliases.js @@ -0,0 +1,17 @@ +import adapterManager from '../../../src/adapterManager.js'; +import {deepSetValue} from '../../../src/utils.js'; + +export function setRequestExtPrebidAliases(ortbRequest, bidderRequest, context, {am = adapterManager} = {}) { + if (am.aliasRegistry[bidderRequest.bidderCode]) { + const bidder = am.bidderRegistry[bidderRequest.bidderCode]; + // adding alias only if alias source bidder exists and alias isn't configured to be standalone + // pbs adapter + if (!bidder || !bidder.getSpec().skipPbsAliasing) { + deepSetValue( + ortbRequest, + `ext.prebid.aliases.${bidderRequest.bidderCode}`, + am.aliasRegistry[bidderRequest.bidderCode] + ); + } + } +} diff --git a/libraries/pbsExtensions/processors/mediaType.js b/libraries/pbsExtensions/processors/mediaType.js new file mode 100644 index 00000000000..cbcf9a013b1 --- /dev/null +++ b/libraries/pbsExtensions/processors/mediaType.js @@ -0,0 +1,23 @@ +import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes.js'; +import {ORTB_MTYPES} from '../../ortbConverter/processors/mediaType.js'; + +export const SUPPORTED_MEDIA_TYPES = { + // map from pbjs mediaType to its corresponding imp property + [BANNER]: 'banner', + [NATIVE]: 'native', + [VIDEO]: 'video' +} + +/** + * Sets bidResponse.mediaType, using ORTB 2.6 `seatbid.bid[].mtype`, falling back to `ext.prebid.type`, falling back to 'banner'. + */ +export function extPrebidMediaType(bidResponse, bid, context) { + let mediaType = context.mediaType; + if (!mediaType) { + mediaType = ORTB_MTYPES.hasOwnProperty(bid.mtype) ? ORTB_MTYPES[bid.mtype] : bid.ext?.prebid?.type + if (!SUPPORTED_MEDIA_TYPES.hasOwnProperty(mediaType)) { + mediaType = BANNER; + } + } + bidResponse.mediaType = mediaType; +} diff --git a/libraries/pbsExtensions/processors/params.js b/libraries/pbsExtensions/processors/params.js new file mode 100644 index 00000000000..010ffa5b372 --- /dev/null +++ b/libraries/pbsExtensions/processors/params.js @@ -0,0 +1,22 @@ +import {auctionManager} from '../../../src/auctionManager.js'; +import adapterManager from '../../../src/adapterManager.js'; +import {deepSetValue} from '../../../src/utils.js'; + +export function setImpBidParams( + imp, bidRequest, context, + {adUnit, bidderRequests, index = auctionManager.index, bidderRegistry = adapterManager.bidderRegistry} = {}) { + let params = bidRequest.params; + const adapter = bidderRegistry[bidRequest.bidder]; + if (adapter && adapter.getSpec().transformBidParams) { + adUnit = adUnit || index.getAdUnit(bidRequest); + bidderRequests = bidderRequests || [context.bidderRequest]; + params = adapter.getSpec().transformBidParams(params, true, adUnit, bidderRequests); + } + if (params) { + deepSetValue( + imp, + `ext.prebid.bidder.${bidRequest.bidder}`, + params + ); + } +} diff --git a/libraries/pbsExtensions/processors/pbs.js b/libraries/pbsExtensions/processors/pbs.js new file mode 100644 index 00000000000..56a2a391c76 --- /dev/null +++ b/libraries/pbsExtensions/processors/pbs.js @@ -0,0 +1,99 @@ +import {BID_RESPONSE, IMP, REQUEST, RESPONSE} from '../../../src/pbjsORTB.js'; +import {deepAccess, isPlainObject, isStr, mergeDeep} from '../../../src/utils.js'; +import {extPrebidMediaType} from './mediaType.js'; +import {setRequestExtPrebidAliases} from './aliases.js'; +import {setImpBidParams} from './params.js'; +import {setRequestExtPrebid, setRequestExtPrebidChannel} from './requestExtPrebid.js'; +import {setBidResponseVideoCache} from './video.js'; + +export const PBS_PROCESSORS = { + [REQUEST]: { + extPrebid: { + // set request.ext.prebid.auctiontimestamp, .debug and .targeting + fn: setRequestExtPrebid + }, + extPrebidChannel: { + // sets request.ext.prebid.channel + fn: setRequestExtPrebidChannel + }, + extPrebidAliases: { + // sets ext.prebid.aliases + fn: setRequestExtPrebidAliases + } + }, + [IMP]: { + params: { + // sets bid ext.prebid.bidder.[bidderCode] with bidRequest.params, passed through transformBidParams if necessary + fn: setImpBidParams + }, + }, + [BID_RESPONSE]: { + mediaType: { + // sets bidResponse.mediaType according to context.mediaType, falling back to imp.ext.prebid.type + fn: extPrebidMediaType, + priority: 99, + }, + videoCache: { + // sets response video attributes; in addition, looks at ext.prebid.cache and .targeting to set video cache key and URL + fn: setBidResponseVideoCache, + priority: -10, // after 'video' + }, + bidderCode: { + // sets bidderCode from on seatbid.seat + fn(bidResponse, bid, context) { + bidResponse.bidderCode = context.seatbid.seat; + bidResponse.adapterCode = deepAccess(bid, 'ext.prebid.meta.adaptercode') || context.bidRequest?.bidder || bidResponse.bidderCode; + } + }, + pbsBidId: { + // sets bidResponse.pbsBidId from ext.prebid.bidid + fn(bidResponse, bid) { + const bidId = deepAccess(bid, 'ext.prebid.bidid'); + if (isStr(bidId)) { + bidResponse.pbsBidId = bidId; + } + } + }, + adserverTargeting: { + // sets bidResponse.adserverTargeting from ext.prebid.targeting + fn(bidResponse, bid) { + const targeting = deepAccess(bid, 'ext.prebid.targeting'); + if (isPlainObject(targeting)) { + bidResponse.adserverTargeting = targeting; + } + } + }, + extPrebidMeta: { + // sets bidResponse.meta from ext.prebid.meta + fn(bidResponse, bid) { + bidResponse.meta = mergeDeep({}, deepAccess(bid, 'ext.prebid.meta'), bidResponse.meta); + } + }, + pbsWurl: { + // sets bidResponse.pbsWurl from ext.prebid.events.win + fn(bidResponse, bid) { + const wurl = deepAccess(bid, 'ext.prebid.events.win'); + if (isStr(wurl)) { + bidResponse.pbsWurl = wurl; + } + } + }, + }, + [RESPONSE]: { + serverSideStats: { + // updates bidderRequest and bidRequests with serverErrors from ext.errors and serverResponseTimeMs from ext.responsetimemillis + fn(response, ortbResponse, context) { + Object.entries({ + errors: 'serverErrors', + responsetimemillis: 'serverResponseTimeMs' + }).forEach(([serverName, clientName]) => { + const value = deepAccess(ortbResponse, `ext.${serverName}.${context.bidderRequest.bidderCode}`); + if (value) { + context.bidderRequest[clientName] = value; + context.bidRequests.forEach(bid => bid[clientName] = value); + } + }) + } + }, + } +} diff --git a/libraries/pbsExtensions/processors/requestExtPrebid.js b/libraries/pbsExtensions/processors/requestExtPrebid.js new file mode 100644 index 00000000000..bbb6add45ce --- /dev/null +++ b/libraries/pbsExtensions/processors/requestExtPrebid.js @@ -0,0 +1,30 @@ +import {deepSetValue, mergeDeep} from '../../../src/utils.js'; +import {config} from '../../../src/config.js'; +import {getGlobal} from '../../../src/prebidGlobal.js'; + +export function setRequestExtPrebid(ortbRequest, bidderRequest) { + deepSetValue( + ortbRequest, + 'ext.prebid', + mergeDeep( + { + auctiontimestamp: bidderRequest.auctionStart, + targeting: { + includewinners: true, + includebidderkeys: false + } + }, + ortbRequest.ext?.prebid, + ) + ); + if (config.getConfig('debug')) { + ortbRequest.ext.prebid.debug = true; + } +} + +export function setRequestExtPrebidChannel(ortbRequest) { + deepSetValue(ortbRequest, 'ext.prebid.channel', Object.assign({ + name: 'pbjs', + version: getGlobal().version + }, ortbRequest.ext?.prebid?.channel)); +} diff --git a/libraries/pbsExtensions/processors/video.js b/libraries/pbsExtensions/processors/video.js new file mode 100644 index 00000000000..0a517fd0575 --- /dev/null +++ b/libraries/pbsExtensions/processors/video.js @@ -0,0 +1,23 @@ +import {VIDEO} from '../../../src/mediaTypes.js'; +import {deepAccess} from '../../../src/utils.js'; + +export function setBidResponseVideoCache(bidResponse, bid) { + if (bidResponse.mediaType === VIDEO) { + // try to get cache values from 'response.ext.prebid.cache' + // else try 'bid.ext.prebid.targeting' as fallback + let {cacheId: videoCacheKey, url: vastUrl} = deepAccess(bid, 'ext.prebid.cache.vastXml') || {}; + if (!videoCacheKey || !vastUrl) { + const {hb_uuid: uuid, hb_cache_host: cacheHost, hb_cache_path: cachePath} = deepAccess(bid, 'ext.prebid.targeting') || {}; + if (uuid && cacheHost && cachePath) { + videoCacheKey = uuid; + vastUrl = `https://${cacheHost}${cachePath}?uuid=${uuid}`; + } + } + if (videoCacheKey && vastUrl) { + Object.assign(bidResponse, { + videoCacheKey, + vastUrl + }) + } + } +} diff --git a/modules/consentManagement.js b/modules/consentManagement.js index 3d6562958c3..95d622e55e4 100644 --- a/modules/consentManagement.js +++ b/modules/consentManagement.js @@ -4,11 +4,12 @@ * and make it available for any GDPR supported adapters to read/pass this information to * their system. */ -import {isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js'; +import {deepSetValue, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js'; import {config} from '../src/config.js'; import {gdprDataHandler} from '../src/adapterManager.js'; import {includes} from '../src/polyfill.js'; import {timedAuctionHook} from '../src/utils/perfMetrics.js'; +import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; const DEFAULT_CMP = 'iab'; const DEFAULT_CONSENT_TIMEOUT = 10000; @@ -354,3 +355,23 @@ export function setConsentConfig(config) { loadConsentData(); // immediately look up consent data to make it available without requiring an auction } config.getConfig('consentManagement', config => setConsentConfig(config.consentManagement)); + +export function setOrtbGdpr(ortbRequest, bidderRequest) { + const consent = bidderRequest.gdprConsent; + if (consent) { + if (typeof consent.gdprApplies === 'boolean') { + deepSetValue(ortbRequest, 'regs.ext.gdpr', consent.gdprApplies ? 1 : 0); + } + deepSetValue(ortbRequest, 'user.ext.consent', consent.consentString); + } +} + +export function setOrtbAdditionalConsent(ortbRequest, bidderRequest) { + const addtl = bidderRequest.gdprConsent?.addtlConsent; + if (addtl && typeof addtl === 'string') { + deepSetValue(ortbRequest, 'user.ext.ConsentedProvidersSettings.consented_providers', addtl); + } +} + +registerOrtbProcessor({type: REQUEST, name: 'gdpr', fn: setOrtbGdpr}); +registerOrtbProcessor({type: REQUEST, name: 'gdprAddtlConsent', fn: setOrtbAdditionalConsent}) diff --git a/modules/consentManagementUsp.js b/modules/consentManagementUsp.js index 76bc7982be7..1e77dd4ef48 100644 --- a/modules/consentManagementUsp.js +++ b/modules/consentManagementUsp.js @@ -4,9 +4,10 @@ * information and make it available for any USP (CCPA) supported adapters to * read/pass this information to their system. */ -import {isFn, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js'; +import {deepSetValue, isFn, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js'; import {config} from '../src/config.js'; import {uspDataHandler} from '../src/adapterManager.js'; +import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; import {timedAuctionHook} from '../src/utils/perfMetrics.js'; import {getHook} from '../src/hook.js'; @@ -308,3 +309,11 @@ function enableConsentManagement(configFromUser = false) { config.getConfig('consentManagement', config => setConsentConfig(config.consentManagement)); getHook('requestBids').before(requestBidsHook, 50); + +export function setOrtbUsp(ortbRequest, bidderRequest) { + if (bidderRequest.uspConsent) { + deepSetValue(ortbRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } +} + +registerOrtbProcessor({type: REQUEST, name: 'usp', fn: setOrtbUsp}); diff --git a/modules/currency.js b/modules/currency.js index 2c8070bcb08..9272a507d05 100644 --- a/modules/currency.js +++ b/modules/currency.js @@ -5,6 +5,7 @@ import {ajax} from '../src/ajax.js'; import {config} from '../src/config.js'; import {getHook} from '../src/hook.js'; import {defer} from '../src/utils/promise.js'; +import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; import {timedBidResponseHook} from '../src/utils/perfMetrics.js'; const DEFAULT_CURRENCY_RATE_URL = 'https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json?date=$$TODAY$$'; @@ -314,3 +315,11 @@ function roundFloat(num, dec) { } return Math.round(num * d) / d; } + +export function setOrtbCurrency(ortbRequest, bidderRequest, context) { + if (currencySupportEnabled) { + ortbRequest.cur = ortbRequest.cur || [context.currency || adServerCurrency]; + } +} + +registerOrtbProcessor({type: REQUEST, name: 'currency', fn: setOrtbCurrency}); diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js index 044c27dc9e8..cc039354878 100644 --- a/modules/improvedigitalBidAdapter.js +++ b/modules/improvedigitalBidAdapter.js @@ -1,24 +1,10 @@ -import { - cleanObj, - deepAccess, - deepClone, - deepSetValue, - getBidIdParameter, - getBidRequest, - getDNT, - getUniqueIdentifierStr, - isFn, - isPlainObject, - logWarn, - mergeDeep -} from '../src/utils.js'; +import {deepAccess, deepSetValue, getBidIdParameter, getUniqueIdentifierStr, logWarn, mergeDeep} 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'; -import {createEidsArray} from './userId/eids.js'; import {hasPurpose1Consent} from '../src/utils/gpdr.js'; -import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import {ortbConverter} from '../libraries/ortbConverter/converter.js'; import {loadExternalScript} from '../src/adloader.js'; const BIDDER_CODE = 'improvedigital'; @@ -31,44 +17,12 @@ const IFRAME_SYNC_URL = 'https://hb.360yield.com/prebid-universal-creative/load- const VIDEO_PARAMS = { DEFAULT_MIMES: ['video/mp4'], - SUPPORTED_PROPERTIES: ['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'], PLACEMENT_TYPE: { INSTREAM: 1, OUTSTREAM: 3, } }; -const NATIVE_DATA = { - VERSION: '1.2', - ASSET_TYPES: { - TITLE: 'title', - IMG: 'img', - DATA: 'data', - }, - ASSETS: { - title: {id: 0, name: 'title', assetType: 'title', default: {len: 140}}, - sponsoredBy: {id: 1, name: 'sponsoredBy', assetType: 'data', type: 1}, - icon: {id: 2, name: 'icon', assetType: 'img', type: 2}, - body: {id: 3, name: 'body', assetType: 'data', type: 2}, - image: {id: 4, name: 'image', assetType: 'img', type: 3}, - rating: {id: 5, name: 'rating', assetType: 'data', type: 3}, - likes: {id: 6, name: 'likes', assetType: 'data', type: 4}, - downloads: {id: 7, name: 'downloads', assetType: 'data', type: 5}, - price: {id: 8, name: 'price', assetType: 'data', type: 6}, - salePrice: {id: 9, name: 'salePrice', assetType: 'data', type: 7}, - phone: {id: 10, name: 'phone', assetType: 'data', type: 8}, - address: {id: 11, name: 'address', assetType: 'data', type: 9}, - body2: {id: 12, name: 'body2', assetType: 'data', type: 10}, - displayUrl: {id: 13, name: 'displayUrl', assetType: 'data', type: 11}, - cta: {id: 14, name: 'cta', assetType: 'data', type: 12}, - }, - getAssetById(id) { - return Object.values(this.ASSETS).find(asset => id === asset.id); - } -}; - export const spec = { code: BIDDER_CODE, gvlid: 253, @@ -94,85 +48,9 @@ export const spec = { * @return ServerRequest Info describing the request to the server. */ buildRequests(bidRequests, bidderRequest) { - // convert Native ORTB definition to old-style prebid native definition - bidRequests = convertOrtbRequestToProprietaryNative(bidRequests); - - const request = { - cur: [config.getConfig('currency.adServerCurrency') || 'USD'], - ext: { - improvedigital: { - sdk: { - name: 'pbjs', - version: '$prebid.version$', - } - } - } - }; - - // Device - request.device = (typeof config.getConfig('device') === 'object') ? config.getConfig('device') : {}; - request.device.w = request.device.w || window.innerWidth; - request.device.h = request.device.h || window.innerHeight; - if (getDNT()) { - request.device.dnt = 1; - } - - // Coppa - const coppa = config.getConfig('coppa'); - if (typeof coppa === 'boolean') { - deepSetValue(request, 'regs.coppa', Number(coppa)); - } - - if (bidderRequest) { - // GDPR - const gdprConsent = deepAccess(bidderRequest, 'gdprConsent'); - if (gdprConsent) { - if (typeof gdprConsent.gdprApplies === 'boolean') { - deepSetValue(request, 'regs.ext.gdpr', Number(gdprConsent.gdprApplies)); - } - deepSetValue(request, 'user.ext.consent', gdprConsent.consentString); - - // Additional Consent String - const additionalConsent = deepAccess(gdprConsent, 'addtlConsent'); - if (additionalConsent && additionalConsent.indexOf('~') !== -1) { - // Google Ad Tech Provider IDs - const atpIds = additionalConsent.substring(additionalConsent.indexOf('~') + 1); - if (atpIds) { - deepSetValue( - request, - 'user.ext.consented_providers_settings.consented_providers', - atpIds.split('.').map(id => parseInt(id, 10)) - ); - } - } - } - - // Timeout - if (bidderRequest.timeout) { - request.tmax = parseInt(bidderRequest.timeout); - } - // US Privacy - if (typeof bidderRequest.uspConsent !== typeof undefined) { - deepSetValue(request, 'regs.ext.us_privacy', bidderRequest.uspConsent); - } - } - - ID_REQUEST.buildSiteOrApp(request, bidderRequest); - - const bidRequest0 = bidRequests[0]; - - deepSetValue(request, 'source.ext.schain', bidRequest0.schain); - deepSetValue(request, 'source.tid', bidRequest0.transactionId); - // Save a placement id to send it to the ad server when fetching the user syncs - this.syncStore.placementId = this.syncStore.placementId || bidRequest0.params.placementId; - - if (bidRequest0.userId) { - const eids = createEidsArray(bidRequest0.userId); - deepSetValue(request, 'user.ext.eids', eids.length ? eids : undefined); - } - - return ID_REQUEST.buildServerRequests(request, bidRequests, bidderRequest); + this.syncStore.placementId = this.syncStore.placementId || bidRequests[0].params.placementId; + return ID_REQUEST.buildServerRequests(bidRequests, bidderRequest); }, /** @@ -182,48 +60,8 @@ export const spec = { * @param bidderRequest * @return {Bid[]} An array of bids which were nested inside the server. */ - interpretResponse(serverResponse, { bidderRequest }) { - if (!Array.isArray(deepAccess(serverResponse, 'body.seatbid'))) { - return []; - } - - const bids = []; - - serverResponse.body.seatbid.forEach(seatbid => { - if (!Array.isArray(seatbid.bid)) return; - - seatbid.bid.forEach(bidObject => { - if (!bidObject.adm || !bidObject.price || bidObject.hasOwnProperty('errorCode')) { - return; - } - const bidRequest = getBidRequest(bidObject.impid, [bidderRequest]); - const idExt = deepAccess(bidObject, `ext.${BIDDER_CODE}`, {}); - - const bid = { - requestId: bidObject.impid, - cpm: bidObject.price, - creativeId: bidObject.crid, - currency: serverResponse.body.cur.toUpperCase() || 'USD', - dealId: (typeof idExt.buying_type === 'string' && idExt.buying_type !== 'rtb') ? idExt.line_item_id : undefined, - meta: { - advertiserDomains: bidObject.adomain ? bidObject.adomain : [] - }, - netRevenue: idExt.is_net || false, - ttl: CREATIVE_TTL - } - - ID_RESPONSE.buildAd(bid, bidRequest, bidObject); - - ID_RAZR.forwardBid({ - bidRequest, - bid - }); - - bids.push(bid); - }); - }); - - return bids; + interpretResponse(serverResponse, { ortbRequest }) { + return CONVERTER.fromORTB({request: ortbRequest, response: serverResponse.body}).bids; }, /** @@ -267,38 +105,165 @@ export const spec = { registerBidder(spec); +export const CONVERTER = ortbConverter({ + context: { + ttl: CREATIVE_TTL, + nativeRequest: { + eventtrackers: [ + {event: 1, methods: [1, 2]}, + ] + } + }, + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + imp.secure = Number(window.location.protocol === 'https:'); + if (!imp.bidfloor && bidRequest.params.bidFloor) { + imp.bidfloor = bidRequest.params.bidFloor; + imp.bidfloorcur = getBidIdParameter('bidFloorCur', bidRequest.params).toUpperCase() || 'USD' + } + const bidderParamsPath = context.extendMode ? 'ext.prebid.bidder.improvedigital' : 'ext.bidder'; + const placementId = bidRequest.params.placementId; + if (placementId) { + deepSetValue(imp, `${bidderParamsPath}.placementId`, placementId); + if (context.extendMode) { + deepSetValue(imp, 'ext.prebid.storedrequest.id', '' + placementId); + } + } else { + deepSetValue(imp, `${bidderParamsPath}.publisherId`, getBidIdParameter('publisherId', bidRequest.params)); + deepSetValue(imp, `${bidderParamsPath}.placementKey`, getBidIdParameter('placementKey', bidRequest.params)); + } + deepSetValue(imp, `${bidderParamsPath}.keyValues`, getBidIdParameter('keyValues', bidRequest.params) || undefined); + + return imp; + }, + request(buildRequest, imps, bidderRequest, context) { + const request = buildRequest(imps, bidderRequest, context); + mergeDeep(request, { + id: getUniqueIdentifierStr(), + source: { + // TODO: once https://github.com/prebid/Prebid.js/issues/8573 is resolved, this should be handled by the base ortbConverter logic + tid: context.bidRequests[0].transactionId, + }, + ext: { + improvedigital: { + sdk: { + name: 'pbjs', + version: '$prebid.version$', + } + } + }, + }); + return request; + }, + bidResponse(buildBidResponse, bid, context) { + if (!bid.adm || !bid.price || bid.hasOwnProperty('errorCode')) { + return; + } + const {bidRequest} = context; + context.mediaType = (() => { + const requestMediaTypes = Object.keys(bidRequest.mediaTypes); + if (requestMediaTypes.length === 1) return requestMediaTypes[0]; + // Detect media type for multi-format response + if (bid.adm.search(/^(<\?xml| parseInt(id, 10)) + ); + } + } + } + } + } +}) + const ID_REQUEST = { - buildServerRequests(basicRequest, bidRequests, bidderRequest) { + buildServerRequests(bidRequests, bidderRequest) { const globalExtendMode = config.getConfig('improvedigital.extend') === true; const requests = []; const singleRequestMode = config.getConfig('improvedigital.singleRequest') === true; - const extendImps = []; - const adServerImps = []; + const extendBids = []; + const adServerBids = []; - function formatRequest(imps, transactionId, extendMode) { - const request = deepClone(basicRequest); - request.imp = imps; - request.id = getUniqueIdentifierStr(); - if (transactionId) { - deepSetValue(request, 'source.tid', transactionId); - } + function formatRequest(bidRequests, extendMode) { + const ortbRequest = CONVERTER.toORTB({bidRequests, bidderRequest, context: {extendMode}}); const adServerUrl = hasPurpose1Consent(bidderRequest?.gdprConsent) ? AD_SERVER_URL : BASIC_ADS_URL; return { method: 'POST', url: extendMode ? EXTEND_URL : adServerUrl, - data: JSON.stringify(request), - bidderRequest + data: JSON.stringify(ortbRequest), + ortbRequest } - }; + } bidRequests.map((bidRequest) => { const extendModeEnabled = this.isExtendModeEnabled(globalExtendMode, bidRequest.params); - const imp = this.buildImp(bidRequest, extendModeEnabled); if (singleRequestMode) { - extendModeEnabled ? extendImps.push(imp) : adServerImps.push(imp); + extendModeEnabled ? extendBids.push(bidRequest) : adServerBids.push(bidRequest); } else { - requests.push(formatRequest([imp], bidRequest.transactionId, extendModeEnabled)); + requests.push(formatRequest([bidRequest], extendModeEnabled)); } }); @@ -306,11 +271,11 @@ const ID_REQUEST = { return requests; } // In the single request mode, split imps between those going to the ad server and those going to extend server - if (extendImps.length) { - requests.push(formatRequest(extendImps, bidderRequest.auctionId, true)); + if (extendBids.length) { + requests.push(formatRequest(extendBids, true)); } - if (adServerImps.length) { - requests.push(formatRequest(adServerImps, bidderRequest.auctionId, false)); + if (adServerBids.length) { + requests.push(formatRequest(adServerBids, false)); } return requests; @@ -324,289 +289,10 @@ const ID_REQUEST = { return extendMode; }, - buildImp(bidRequest, extendMode) { - const imp = { - id: getBidIdParameter('bidId', bidRequest) || getUniqueIdentifierStr(), - secure: Number(window.location.protocol === 'https:'), - }; - - // Floor - const bidFloor = this.getBidFloor(bidRequest) || getBidIdParameter('bidFloor', bidRequest.params); - if (bidFloor) { - const bidFloorCur = getBidIdParameter('bidFloorCur', bidRequest.params) || 'USD'; - deepSetValue(imp, 'bidfloor', bidFloor); - deepSetValue(imp, 'bidfloorcur', bidFloorCur ? bidFloorCur.toUpperCase() : undefined); - } - - const bidderParamsPath = extendMode ? 'ext.prebid.bidder.improvedigital' : 'ext.bidder'; - const placementId = getBidIdParameter('placementId', bidRequest.params); - if (placementId) { - deepSetValue(imp, `${bidderParamsPath}.placementId`, placementId); - if (extendMode) { - deepSetValue(imp, 'ext.prebid.storedrequest.id', '' + placementId); - } - } else { - deepSetValue(imp, `${bidderParamsPath}.publisherId`, getBidIdParameter('publisherId', bidRequest.params)); - deepSetValue(imp, `${bidderParamsPath}.placementKey`, getBidIdParameter('placementKey', bidRequest.params)); - } - - deepSetValue(imp, `${bidderParamsPath}.keyValues`, getBidIdParameter('keyValues', bidRequest.params) || undefined); - - // Adding GPID - const gpid = deepAccess(bidRequest, 'ortb2Imp.ext.gpid') || - deepAccess(bidRequest, 'ortb2Imp.ext.data.pbadslot') || - deepAccess(bidRequest, 'ortb2Imp.ext.data.adserver.adslot'); - - deepSetValue(imp, 'ext.gpid', gpid); - - // Adding Interstitial Signal - if (deepAccess(bidRequest, 'ortb2Imp.instl')) { - imp.instl = 1; - } - - const videoParams = deepAccess(bidRequest, 'mediaTypes.video'); - if (videoParams) { - imp.video = this.buildVideoRequest(bidRequest); - deepSetValue(imp, 'ext.is_rewarded_inventory', (videoParams.rewarded === 1 || deepAccess(videoParams, 'ext.rewarded') === 1) || undefined); - } - - if (deepAccess(bidRequest, 'mediaTypes.banner')) { - imp.banner = this.buildBannerRequest(bidRequest); - } - - if (deepAccess(bidRequest, 'mediaTypes.native')) { - const nativeImp = this.buildNativeRequest(bidRequest); - if (nativeImp) { - imp.native = nativeImp; - } - } - - return imp; - }, - - buildVideoRequest(bidRequest) { - const videoParams = deepClone(bidRequest.mediaTypes.video); - const videoImproveParams = deepClone(deepAccess(bidRequest, 'params.video', {})); - const video = {...videoParams, ...videoImproveParams}; - - if (Array.isArray(video.playerSize)) { - // Player size can be defined as [w, h] or [[w, h]] - const size = Array.isArray(video.playerSize[0]) ? video.playerSize[0] : video.playerSize; - video.w = size[0]; - video.h = size[1]; - } - video.placement = this.isOutstreamVideo(bidRequest) ? VIDEO_PARAMS.PLACEMENT_TYPE.OUTSTREAM : VIDEO_PARAMS.PLACEMENT_TYPE.INSTREAM; - - // Mimes is required - if (!video.mimes) { - video.mimes = VIDEO_PARAMS.DEFAULT_MIMES; - } - - // skip must be 0 or 1 - if (video.skip !== 1) { - delete video.skipmin; - delete video.skipafter; - if (video.skip !== 0) { - logWarn(`video.skip: invalid value '${video.skip}'. Expected 0 or 1`); - delete video.skip; - } - } - - Object.keys(video).forEach(prop => { - if (VIDEO_PARAMS.SUPPORTED_PROPERTIES.indexOf(prop) === -1) delete video[prop]; - }); - return video; - }, - - buildBannerRequest(bidRequest) { - // Set the desired creative sizes - // Input Format: array of pairs, i.e. [[300, 250], [250, 250]] - // Unless improvedigital.usePrebidSizes == true, no sizes are sent to the server - // and the sizes defined in the server for the placement will be used - const banner = {}; - if (config.getConfig('improvedigital.usePrebidSizes') === true && bidRequest.sizes) { - // Convert sizes from [x, y] to { w: x, h: y} - banner.format = bidRequest.sizes.map(sizePair => ({w: sizePair[0], h: sizePair[1]})); - } - return banner; - }, - - buildNativeRequest(bidRequest) { - const nativeParams = bidRequest.nativeParams; - if (!nativeParams) { - return null; - } - const request = { - eventtrackers: [ - {event: 1, methods: [1, 2]} - ], - assets: [], - } - for (let i of Object.keys(nativeParams)) { - const assetOrtbParams = NATIVE_DATA.ASSETS[i]; - if (assetOrtbParams) { - const assetParams = nativeParams[i]; - const asset = { - id: assetOrtbParams.id, - required: Number(assetParams.required), - }; - switch (assetOrtbParams.assetType) { - case NATIVE_DATA.ASSET_TYPES.TITLE: - asset.title = {len: assetParams.len || assetOrtbParams.default.len}; - break; - case NATIVE_DATA.ASSET_TYPES.DATA: - asset.data = cleanObj({type: assetOrtbParams.type, len: assetParams.len}) - break; - case NATIVE_DATA.ASSET_TYPES.IMG: - asset.img = cleanObj({ - type: assetOrtbParams.type, - w: deepAccess(assetParams, 'sizes.0'), - h: deepAccess(assetParams, 'sizes.1'), - wmin: deepAccess(assetParams, 'aspect_ratios.0.min_width'), - hmin: deepAccess(assetParams, 'aspect_ratios.0.min_height') - }); - break; - default: - return; - } - request.assets.push(asset); - } - } - if (!request.assets.length) { - logWarn('No native assets recognized. Ignoring native ad request'); - return null; - } - return { ver: NATIVE_DATA.VERSION, request: JSON.stringify(request) }; - }, - isOutstreamVideo(bidRequest) { return deepAccess(bidRequest, 'mediaTypes.video.context') === 'outstream'; }, - getBidFloor(bidRequest) { - if (!isFn(bidRequest.getFloor)) { - return null; - } - const floor = bidRequest.getFloor({ - currency: 'USD', - mediaType: '*', - size: '*' - }); - if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') { - return floor.floor; - } - return null; - }, - - buildSiteOrApp(request, bidderRequest) { - const app = {}; - const configAppSettings = config.getConfig('app') || {}; - const fpdAppSettings = bidderRequest.ortb2?.app || {}; - mergeDeep(app, configAppSettings, fpdAppSettings); - - if (Object.keys(app).length !== 0) { - request.app = app; - } else { - const site = {}; - const url = deepAccess(bidderRequest, 'refererInfo.page'); - if (url) { - site.page = url; - site.domain = bidderRequest.refererInfo.domain; - } - const configSiteSettings = config.getConfig('site') || {}; - const fpdSiteSettings = deepAccess(bidderRequest, 'ortb2.site') || {}; - mergeDeep(site, configSiteSettings, fpdSiteSettings); - request.site = site; - } - }, -}; - -const ID_RESPONSE = { - buildAd(bid, bidRequest, bidResponse) { - if (bidRequest.mediaTypes && Object.keys(bidRequest.mediaTypes).length === 1) { - if (deepAccess(bidRequest, 'mediaTypes.video')) { - this.buildVideoAd(bid, bidRequest, bidResponse); - } else if (deepAccess(bidRequest, 'mediaTypes.banner')) { - this.buildBannerAd(bid, bidRequest, bidResponse); - } else if (deepAccess(bidRequest, 'mediaTypes.native')) { - this.buildNativeAd(bid, bidRequest, bidResponse) - } - } else { - // Detect media type for multi-format response - if (bidResponse.adm.search(/^(<\?xml| { - // Only handle impression event. Viewability events are not supported yet. - if (tracker.event !== 1) return; - switch (tracker.method) { - case 1: // img - nativeAd.impressionTrackers.push(tracker.url); - break; - case 2: // js - // javascriptTrackers is a string. If there's more than one JS tracker in bid response, the last script will be used. - nativeAd.javascriptTrackers = ``; - break; - } - }); - } else { - nativeAd.impressionTrackers = nativeResponse.imptrackers || []; - nativeAd.javascriptTrackers = nativeResponse.jstracker; - } - nativeResponse.assets.map(asset => { - const assetParams = NATIVE_DATA.getAssetById(asset.id); - switch (assetParams.assetType) { - case NATIVE_DATA.ASSET_TYPES.TITLE: - nativeAd.title = asset.title.text; - break; - case NATIVE_DATA.ASSET_TYPES.DATA: - nativeAd[assetParams.name] = asset.data.value; - break; - case NATIVE_DATA.ASSET_TYPES.IMG: - nativeAd[assetParams.name] = { - url: asset.img.url, - width: asset.img.w, - height: asset.img.h, - }; - break; - } - }); - bid.native = nativeAd; - }, }; const ID_OUTSTREAM = { diff --git a/modules/multibid/index.js b/modules/multibid/index.js index 76f4ede8f8e..df77a157bee 100644 --- a/modules/multibid/index.js +++ b/modules/multibid/index.js @@ -12,6 +12,7 @@ import * as events from '../../src/events.js'; import CONSTANTS from '../../src/constants.json'; import {addBidderRequests} from '../../src/auction.js'; import {getHighestCpmBidsFromBidPool, sortByDealAndPriceBucketOrCpm} from '../../src/targeting.js'; +import {PBS, registerOrtbProcessor, REQUEST} from '../../src/pbjsORTB.js'; import {timedBidResponseHook} from '../../src/utils/perfMetrics.js'; const MODULE_NAME = 'multibid'; @@ -236,3 +237,14 @@ function init() { } init(); + +export function setOrtbExtPrebidMultibid(ortbRequest) { + const multibid = config.getConfig('multibid'); + if (multibid) { + deepSetValue(ortbRequest, 'ext.prebid.multibid', multibid.map(o => + Object.fromEntries(Object.entries(o).map(([k, v]) => [k.toLowerCase(), v]))) + ) + } +} + +registerOrtbProcessor({type: REQUEST, name: 'extPrebidMultibid', fn: setOrtbExtPrebidMultibid, dialects: [PBS]}); diff --git a/modules/openxOrtbBidAdapter.js b/modules/openxOrtbBidAdapter.js index 50b62544dfa..200d2cf0fed 100644 --- a/modules/openxOrtbBidAdapter.js +++ b/modules/openxOrtbBidAdapter.js @@ -1,14 +1,12 @@ import {config} from '../src/config.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import * as utils from '../src/utils.js'; +import {mergeDeep} from '../src/utils.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {includes} from '../src/polyfill.js'; +import {ortbConverter} from '../libraries/ortbConverter/converter.js'; const bidderConfig = 'hb_pb_ortb'; const bidderVersion = '1.0'; -const VIDEO_TARGETING = ['startdelay', 'mimes', 'minduration', 'maxduration', 'delivery', - 'startdelay', 'skip', 'playbackmethod', 'api', 'protocol', 'boxingallowed', 'maxextended', - 'linearity', 'delivery', 'protocols', 'placement', 'minbitrate', 'maxbitrate', 'battr', 'ext']; export const REQUEST_URL = 'https://rtb.openx.net/openrtbb/prebidjs'; export const SYNC_URL = 'https://u.openx.net/w/1.0/pd'; export const DEFAULT_PH = '2d1251ae-7f3a-47cf-bd2a-2f288854a0ba'; @@ -24,6 +22,118 @@ export const spec = { registerBidder(spec); +const converter = ortbConverter({ + context: { + netRevenue: true, + ttl: 300 + }, + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + if (bidRequest.mediaTypes[VIDEO]?.context === 'outstream') { + imp.video.placement = imp.video.placement || 4; + } + if (imp.ext?.ae && !context.bidderRequest.fledgeEnabled) { + // TODO: we may want to standardize this and move fledge logic to ortbConverter + delete imp.ext.ae; + } + mergeDeep(imp, { + tagid: bidRequest.params.unit, + ext: { + divid: bidRequest.adUnitCode + } + }); + if (bidRequest.params.customParams) { + utils.deepSetValue(imp, 'ext.customParams', bidRequest.params.customParams); + } + if (bidRequest.params.customFloor && !imp.bidfloor) { + imp.bidfloor = bidRequest.params.customFloor; + } + return imp; + }, + request(buildRequest, imps, bidderRequest, context) { + const req = buildRequest(imps, bidderRequest, context); + mergeDeep(req, { + at: 1, + ext: { + bc: `${bidderConfig}_${bidderVersion}` + } + }) + const bid = context.bidRequests[0]; + if (bid.params.doNotTrack) { + utils.deepSetValue(req, 'device.dnt', 1); + } + if (bid.params.platform) { + utils.deepSetValue(req, 'ext.platform', bid.params.platform); + } + if (bid.params.delDomain) { + utils.deepSetValue(req, 'ext.delDomain', bid.params.delDomain); + } + if (bid.params.response_template_name) { + utils.deepSetValue(req, 'ext.response_template_name', bid.params.response_template_name); + } + if (bid.params.test) { + req.test = 1 + } + return req; + }, + bidResponse(buildBidResponse, bid, context) { + const bidResponse = buildBidResponse(bid, context); + if (bid.ext) { + bidResponse.meta.networkId = bid.ext.dsp_id; + bidResponse.meta.advertiserId = bid.ext.buyer_id; + bidResponse.meta.brandId = bid.ext.brand_id; + } + const {ortbResponse} = context; + if (ortbResponse.ext && ortbResponse.ext.paf) { + bidResponse.meta.paf = Object.assign({}, ortbResponse.ext.paf); + bidResponse.meta.paf.content_id = utils.deepAccess(bid, 'ext.paf.content_id'); + } + return bidResponse; + }, + response(buildResponse, bidResponses, ortbResponse, context) { + // pass these from request to the responses for use in userSync + const {ortbRequest} = context; + if (ortbRequest.ext) { + if (ortbRequest.ext.delDomain) { + utils.deepSetValue(ortbResponse, 'ext.delDomain', ortbRequest.ext.delDomain); + } + if (ortbRequest.ext.platform) { + utils.deepSetValue(ortbResponse, 'ext.platform', ortbRequest.ext.platform); + } + } + const response = buildResponse(bidResponses, ortbResponse, context); + // TODO: we may want to standardize this and move fledge logic to ortbConverter + let fledgeAuctionConfigs = utils.deepAccess(ortbResponse, 'ext.fledge_auction_configs'); + if (fledgeAuctionConfigs) { + fledgeAuctionConfigs = Object.entries(fledgeAuctionConfigs).map(([bidId, cfg]) => { + return Object.assign({ + bidId, + auctionSignals: {} + }, cfg); + }); + return { + bids: response.bids, + fledgeAuctionConfigs, + } + } else { + return response.bids + } + }, + overrides: { + imp: { + bidfloor(setBidFloor, imp, bidRequest, context) { + // enforce floors should always be in USD + // TODO: does it make sense that request.cur can be any currency, but request.imp[].bidfloorcur must be USD? + const floor = {}; + setBidFloor(floor, bidRequest, {...context, currency: 'USD'}); + if (floor.bidfloorcur === 'USD') { + Object.assign(imp, floor); + } + } + } + } +}); + function transformBidParams(params, isOpenRtb) { return utils.convertTypes({ 'unit': 'string', @@ -47,190 +157,21 @@ function isBidRequestValid(bidRequest) { function buildRequests(bids, bidderRequest) { let videoBids = bids.filter(bid => isVideoBid(bid)); let bannerBids = bids.filter(bid => isBannerBid(bid)); - let requests = bannerBids.length ? [createBannerRequest(bannerBids, bidderRequest)] : []; + let requests = bannerBids.length ? [createRequest(bannerBids, bidderRequest, BANNER)] : []; videoBids.forEach(bid => { - requests.push(createVideoRequest(bid, bidderRequest)); + requests.push(createRequest([bid], bidderRequest, VIDEO)); }); return requests; } -function createBannerRequest(bids, bidderRequest) { - let data = getBaseRequest(bids[0], bidderRequest); - data.imp = bids.map(bid => { - const floor = getFloor(bid, BANNER); - let imp = { - id: bid.bidId, - tagid: bid.params.unit, - banner: { - format: toFormat(bid.mediaTypes.banner.sizes), - topframe: utils.inIframe() ? 0 : 1 - }, - ext: {divid: bid.adUnitCode} - }; - - if (bidderRequest.fledgeEnabled) { - imp.ext.ae = bid?.ortb2Imp?.ext?.ae - } - - enrichImp(imp, bid, floor); - return imp; - }); +function createRequest(bidRequests, bidderRequest, mediaType) { return { method: 'POST', url: config.getConfig('openxOrtbUrl') || REQUEST_URL, - data: data - } -} - -function toFormat(sizes) { - return sizes.map((s) => { - return { w: s[0], h: s[1] }; - }); -} - -function enrichImp(imp, bid, floor) { - if (bid.params.customParams) { - utils.deepSetValue(imp, 'ext.customParams', bid.params.customParams); - } - if (floor > 0) { - imp.bidfloor = floor; - imp.bidfloorcur = 'USD'; - } else if (bid.params.customFloor) { - imp.bidfloor = bid.params.customFloor; - } - if (bid.ortb2Imp && bid.ortb2Imp.ext && bid.ortb2Imp.ext.data) { - imp.ext.data = bid.ortb2Imp.ext.data; + data: converter.toORTB({bidRequests, bidderRequest, context: {mediaType}}) } } -function createVideoRequest(bid, bidderRequest) { - let width; - let height; - const videoMediaType = utils.deepAccess(bid, `mediaTypes.video`); - const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize'); - const context = utils.deepAccess(bid, 'mediaTypes.video.context'); - const floor = getFloor(bid, VIDEO); - - // normalize config for video size - if (utils.isArray(bid.sizes) && bid.sizes.length === 2 && !utils.isArray(bid.sizes[0])) { - width = parseInt(bid.sizes[0], 10); - height = parseInt(bid.sizes[1], 10); - } else if (utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0]) && bid.sizes[0].length === 2) { - width = parseInt(bid.sizes[0][0], 10); - height = parseInt(bid.sizes[0][1], 10); - } else if (utils.isArray(playerSize) && playerSize.length === 2) { - width = parseInt(playerSize[0], 10); - height = parseInt(playerSize[1], 10); - } - - let data = getBaseRequest(bid, bidderRequest); - data.imp = [{ - id: bid.bidId, - tagid: bid.params.unit, - video: { - w: width, - h: height, - topframe: utils.inIframe() ? 0 : 1 - }, - ext: {divid: bid.adUnitCode} - }]; - - enrichImp(data.imp[0], bid, floor); - - if (context) { - if (context === 'instream') { - data.imp[0].video.placement = 1; - } else if (context === 'outstream') { - data.imp[0].video.placement = 4; - } - } - - // backward compatability for video params - let videoParams = bid.params.video || bid.params.openrtb || {}; - if (utils.isArray(videoParams.imp)) { - videoParams = videoParams[0].video; - } - - Object.keys(videoParams) - .filter(param => includes(VIDEO_TARGETING, param)) - .forEach(param => data.imp[0].video[param] = videoParams[param]); - Object.keys(videoMediaType) - .filter(param => includes(VIDEO_TARGETING, param)) - .forEach(param => data.imp[0].video[param] = videoMediaType[param]); - - return { - method: 'POST', - url: REQUEST_URL, - data: data - }; -} - -function getBaseRequest(bid, bidderRequest) { - let req = { - id: bidderRequest.auctionId, - cur: [config.getConfig('currency.adServerCurrency') || 'USD'], - at: 1, - tmax: config.getConfig('bidderTimeout'), - site: { - page: config.getConfig('pageUrl') || bidderRequest.refererInfo.referer - }, - regs: { - coppa: (config.getConfig('coppa') === true || bid.params.coppa) ? 1 : 0, - }, - device: { - dnt: (utils.getDNT() || bid.params.doNotTrack) ? 1 : 0, - h: screen.height, - w: screen.width, - ua: window.navigator.userAgent, - language: window.navigator.language.split('-').shift() - }, - ext: { - bc: `${bidderConfig}_${bidderVersion}` - } - }; - - if (bid.params.platform) { - utils.deepSetValue(req, 'ext.platform', bid.params.platform); - } - if (bid.params.delDomain) { - utils.deepSetValue(req, 'ext.delDomain', bid.params.delDomain); - } - if (bid.params.response_template_name) { - utils.deepSetValue(req, 'ext.response_template_name', bid.params.response_template_name); - } - if (bid.params.test) { - req.test = 1; - } - if (bidderRequest.gdprConsent) { - if (bidderRequest.gdprConsent.gdprApplies !== undefined) { - utils.deepSetValue(req, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies === true ? 1 : 0); - } - if (bidderRequest.gdprConsent.consentString !== undefined) { - utils.deepSetValue(req, 'user.ext.consent', bidderRequest.gdprConsent.consentString); - } - if (bidderRequest.gdprConsent.addtlConsent !== undefined) { - utils.deepSetValue(req, 'user.ext.ConsentedProvidersSettings.consented_providers', bidderRequest.gdprConsent.addtlConsent); - } - } - if (bidderRequest.uspConsent) { - utils.deepSetValue(req, 'regs.ext.us_privacy', bidderRequest.uspConsent); - } - if (bid.schain) { - utils.deepSetValue(req, 'source.ext.schain', bid.schain); - } - if (bid.userIdAsEids) { - utils.deepSetValue(req, 'user.ext.eids', bid.userIdAsEids); - } - const commonFpd = bidderRequest.ortb2 || {}; - if (commonFpd.site) { - utils.mergeDeep(req, {site: commonFpd.site}); - } - if (commonFpd.user) { - utils.mergeDeep(req, {user: commonFpd.user}); - } - return req; -} - function isVideoBid(bid) { return utils.deepAccess(bid, 'mediaTypes.video'); } @@ -239,107 +180,11 @@ function isBannerBid(bid) { return utils.deepAccess(bid, 'mediaTypes.banner') || !isVideoBid(bid); } -function getFloor(bid, mediaType) { - let floor = 0; - - if (typeof bid.getFloor === 'function') { - const floorInfo = bid.getFloor({ - currency: 'USD', - mediaType: mediaType, - size: '*' - }); - - if (typeof floorInfo === 'object' && - floorInfo.currency === 'USD' && - !isNaN(parseFloat(floorInfo.floor))) { - floor = Math.max(floor, parseFloat(floorInfo.floor)); - } - } - - return floor; -} - -function interpretOrtbResponse(resp, req) { +function interpretResponse(resp, req) { if (!resp.body) { resp.body = {nbr: 0}; } - - // pass these from request to the responses for use in userSync - if (req.data.ext) { - if (req.data.ext.delDomain) { - utils.deepSetValue(resp, 'body.ext.delDomain', req.data.ext.delDomain); - } - if (req.data.ext.platform) { - utils.deepSetValue(resp, 'body.ext.platform', req.data.ext.platform); - } - } - - const respBody = resp.body; - if (!respBody || 'nbr' in respBody || !Array.isArray(respBody.seatbid)) { - return []; - } - - let bids = []; - respBody.seatbid.forEach(seatbid => { - bids = [...bids, ...seatbid.bid.map(bid => { - let response = { - requestId: bid.impid, - cpm: bid.price, - width: bid.w, - height: bid.h, - creativeId: bid.crid, - dealId: bid.dealid, - currency: respBody.cur || 'USD', - netRevenue: true, - ttl: 300, - mediaType: 'banner' in req.data.imp[0] ? BANNER : VIDEO, - meta: { advertiserDomains: bid.adomain } - }; - - if (response.mediaType === VIDEO) { - if (bid.nurl) { - response.vastUrl = bid.nurl; - } else { - response.vastXml = bid.adm; - } - } else { - response.ad = bid.adm; - } - - if (bid.ext) { - response.meta.networkId = bid.ext.dsp_id; - response.meta.advertiserId = bid.ext.buyer_id; - response.meta.brandId = bid.ext.brand_id; - } - - if (respBody.ext && respBody.ext.paf) { - response.meta.paf = Object.assign({}, respBody.ext.paf); - response.meta.paf.content_id = utils.deepAccess(bid, 'ext.paf.content_id'); - } - - return response; - })]; - }); - - return bids; -} - -function interpretResponse(resp, req) { - const bids = interpretOrtbResponse(resp, req); - let fledgeAuctionConfigs = utils.deepAccess(resp, 'body.ext.fledge_auction_configs'); - if (fledgeAuctionConfigs) { - fledgeAuctionConfigs = Object.entries(fledgeAuctionConfigs).map(([bidId, cfg]) => { - return Object.assign({ - bidId, - auctionSignals: {} - }, cfg); - }); - return { - bids, - fledgeAuctionConfigs, - } - } - return bids; + return converter.fromORTB({request: req.data, response: resp.body}); } /** diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 3a082b3199f..072c280aecf 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -1,19 +1,11 @@ import Adapter from '../../src/adapter.js'; -import {createBid} from '../../src/bidfactory.js'; import { bind, - createTrackPixelHtml, - deepAccess, deepClone, - deepSetValue, flatten, generateUUID, - getBidRequest, - getDefinedParams, getPrebidInternal, insertUserSyncIframe, - isArray, - isEmpty, isNumber, isPlainObject, isStr, @@ -21,34 +13,27 @@ import { logInfo, logMessage, logWarn, - mergeDeep, - parseSizesInput, - timestamp, triggerPixel, - uniques + uniques, + deepAccess, } from '../../src/utils.js'; import CONSTANTS from '../../src/constants.json'; import adapterManager from '../../src/adapterManager.js'; import {config} from '../../src/config.js'; -import {NATIVE, VIDEO} from '../../src/mediaTypes.js'; import {isValid} from '../../src/adapters/bidderFactory.js'; import * as events from '../../src/events.js'; -import {find, includes} from '../../src/polyfill.js'; +import {includes} from '../../src/polyfill.js'; import {S2S_VENDORS} from './config.js'; import {ajax} from '../../src/ajax.js'; import {hook} from '../../src/hook.js'; -import {getGlobal} from '../../src/prebidGlobal.js'; import {hasPurpose1Consent} from '../../src/utils/gpdr.js'; +import {buildPBSRequest, interpretPBSResponse} from './ortbConverter.js'; import {useMetrics} from '../../src/utils/perfMetrics.js'; const getConfig = config.getConfig; const TYPE = CONSTANTS.S2S.SRC; let _syncCount = 0; -const DEFAULT_S2S_TTL = 60; -const DEFAULT_S2S_CURRENCY = 'USD'; -const DEFAULT_S2S_NETREVENUE = true; - let _s2sConfigs; let eidPermissions; @@ -95,12 +80,13 @@ let eidPermissions; * @property {boolean} [cacheMarkup] whether to cache the adm result * @property {string} [syncEndpoint] endpoint URL for syncing cookies * @property {Object} [extPrebid] properties will be merged into request.ext.prebid + * @property {Object} [ortbNative] base value for imp.native.request */ /** * @type {S2SDefaultConfig} */ -const s2sDefaultConfig = { +export const s2sDefaultConfig = { bidders: Object.freeze([]), timeout: 1000, syncTimeout: 1000, @@ -108,7 +94,14 @@ const s2sDefaultConfig = { adapter: 'prebidServer', allowUnknownBidderCodes: false, adapterOptions: {}, - syncUrlModifier: {} + syncUrlModifier: {}, + ortbNative: { + context: 1, + plcmttype: 1, + eventtrackers: [ + {event: 1, methods: [1]} + ], + } }; config.setDefaults({ @@ -355,97 +348,6 @@ function doClientSideSyncs(bidders, gdprConsent, uspConsent) { }); } -function _appendSiteAppDevice(request, pageUrl, accountId) { - if (!request) return; - - // ORTB specifies app OR site - if (typeof config.getConfig('app') === 'object') { - request.app = config.getConfig('app'); - request.app.publisher = {id: accountId}; - } else { - request.site = {}; - if (isPlainObject(config.getConfig('site'))) { - request.site = config.getConfig('site'); - } - // set publisher.id if not already defined - if (!deepAccess(request.site, 'publisher.id')) { - deepSetValue(request.site, 'publisher.id', accountId); - } - // set site.page if not already defined - if (!request.site.page) { - request.site.page = pageUrl; - } - } - if (typeof config.getConfig('device') === 'object') { - request.device = config.getConfig('device'); - } - if (!request.device) { - request.device = {}; - } - if (!request.device.w) { - request.device.w = window.innerWidth; - } - if (!request.device.h) { - request.device.h = window.innerHeight; - } -} - -function addBidderFirstPartyDataToRequest(request, bidderFpd) { - const fpdConfigs = Object.entries(bidderFpd).reduce((acc, [bidder, bidderOrtb2]) => { - const ortb2 = mergeDeep({}, bidderOrtb2); - acc.push({ - bidders: [ bidder ], - config: { ortb2 } - }); - return acc; - }, []); - - if (fpdConfigs.length) { - deepSetValue(request, 'ext.prebid.bidderconfig', fpdConfigs); - } -} - -// https://iabtechlab.com/wp-content/uploads/2016/07/OpenRTB-Native-Ads-Specification-Final-1.2.pdf#page=40 -let nativeDataNames = Object.keys(CONSTANTS.PREBID_NATIVE_DATA_KEYS_TO_ORTB); - -// returns object with legacy asset name as key and asset id as value: -// { "sponsoredBy": 1, ... } -let nativeDataIdMap = nativeDataNames.reduce((prev, key) => { - prev[key] = CONSTANTS.NATIVE_ASSET_TYPES[CONSTANTS.PREBID_NATIVE_DATA_KEYS_TO_ORTB[key]]; - return prev; -}, {}); - -let nativeImgIdMap = { - icon: 1, - image: 3 -}; - -let nativeEventTrackerEventMap = { - impression: 1, - 'viewable-mrc50': 2, - 'viewable-mrc100': 3, - 'viewable-video50': 4, -}; - -let nativeEventTrackerMethodMap = { - img: 1, - js: 2 -}; - -if (FEATURES.NATIVE) { - // enable reverse lookup - [ - nativeDataIdMap, - nativeImgIdMap, - nativeEventTrackerEventMap, - nativeEventTrackerMethodMap - ].forEach(map => { - Object.keys(map).forEach(key => { - map[map[key]] = key; - }); - }); -} - /** * map wurl to auction id and adId for use in the BID_WON event */ @@ -462,18 +364,6 @@ function addWurl(auctionId, adId, wurl) { } } -function getPbsResponseData(bidderRequests, response, pbsName, pbjsName) { - const bidderValues = deepAccess(response, `ext.${pbsName}`); - if (bidderValues) { - Object.keys(bidderValues).forEach(bidder => { - let biddersReq = find(bidderRequests, bidderReq => bidderReq.bidderCode === bidder); - if (biddersReq) { - biddersReq[pbjsName] = bidderValues[bidder]; - } - }); - } -} - /** * @param {string} auctionId * @param {string} adId generated value set to bidObject.adId by bidderFactory Bid() @@ -501,595 +391,6 @@ export function resetWurlMap() { wurlMap = {}; } -function ORTB2(s2sBidRequest, bidderRequests, adUnits, requestedBidders) { - this.s2sBidRequest = s2sBidRequest; - this.bidderRequests = bidderRequests; - this.adUnits = adUnits; - this.s2sConfig = s2sBidRequest.s2sConfig; - this.requestedBidders = requestedBidders; - - this.bidIdMap = {}; - this.adUnitsByImp = {}; - this.impRequested = {}; - this.auctionId = bidderRequests.map(br => br.auctionId).reduce((l, r) => (l == null || l === r) && r); - this.requestTimestamp = timestamp(); -} - -Object.assign(ORTB2.prototype, { - buildRequest() { - const {s2sBidRequest, bidderRequests: bidRequests, adUnits, s2sConfig, requestedBidders} = this; - - let imps = []; - let aliases = {}; - const firstBidRequest = bidRequests[0]; - let floorMin = null; - let floorMinCur = null; - - // transform ad unit into array of OpenRTB impression objects - let impIds = new Set(); - adUnits.forEach(adUnit => { - // TODO: support labels / conditional bids - // for now, just warn about them - adUnit.bids.forEach((bid) => { - if (bid.mediaTypes != null) { - logWarn(`Prebid Server adapter does not (yet) support bidder-specific mediaTypes for the same adUnit. Size mapping configuration will be ignored for adUnit: ${adUnit.code}, bidder: ${bid.bidder}`); - } - }); - - // in case there is a duplicate imp.id, add '-2' suffix to the second imp.id. - // e.g. if there are 2 adUnits (case of twin adUnit codes) with code 'test', - // first imp will have id 'test' and second imp will have id 'test-2' - let impressionId = adUnit.code; - let i = 1; - while (impIds.has(impressionId)) { - i++; - impressionId = `${adUnit.code}-${i}`; - } - impIds.add(impressionId); - this.adUnitsByImp[impressionId] = adUnit; - - const videoParams = deepAccess(adUnit, 'mediaTypes.video'); - const bannerParams = deepAccess(adUnit, 'mediaTypes.banner'); - - adUnit.bids.forEach(bid => { - this.setBidRequestId(impressionId, bid.bidder, bid.bid_id); - // check for and store valid aliases to add to the request - if (adapterManager.aliasRegistry[bid.bidder]) { - const bidder = adapterManager.bidderRegistry[bid.bidder]; - // adding alias only if alias source bidder exists and alias isn't configured to be standalone - // pbs adapter - if (!bidder || !bidder.getSpec().skipPbsAliasing) { - aliases[bid.bidder] = adapterManager.aliasRegistry[bid.bidder]; - } - } - }); - - let mediaTypes = {}; - if (bannerParams && bannerParams.sizes) { - const sizes = parseSizesInput(bannerParams.sizes); - - // get banner sizes in form [{ w: , h: }, ...] - const format = sizes.map(size => { - const [ width, height ] = size.split('x'); - const w = parseInt(width, 10); - const h = parseInt(height, 10); - return { w, h }; - }); - - mediaTypes['banner'] = {format}; - - if (bannerParams.pos) mediaTypes['banner'].pos = bannerParams.pos; - } - - if (!isEmpty(videoParams)) { - if (videoParams.context === 'outstream' && !videoParams.renderer && !adUnit.renderer) { - // Don't push oustream w/o renderer to request object. - logError('Outstream bid without renderer cannot be sent to Prebid Server.'); - } else { - if (videoParams.context === 'instream' && !videoParams.hasOwnProperty('placement')) { - videoParams.placement = 1; - } - - mediaTypes['video'] = Object.keys(videoParams).filter(param => param !== 'context') - .reduce((result, param) => { - if (param === 'playerSize') { - result.w = deepAccess(videoParams, `${param}.0.0`); - result.h = deepAccess(videoParams, `${param}.0.1`); - } else { - result[param] = videoParams[param]; - } - return result; - }, {}); - } - } - const nativeReq = deepAccess(adUnit, 'nativeOrtbRequest'); - if (FEATURES.NATIVE && nativeReq) { - const defaultRequest = { - // TODO: determine best way to pass these and if we allow defaults - context: 1, - plcmttype: 1, - eventtrackers: [ - { event: 1, methods: [1] } - ], - // TODO: figure out how to support privacy field - // privacy: int - }; - try { - const request = Object.assign(defaultRequest, nativeReq); - mediaTypes[NATIVE] = { - request: JSON.stringify(request), - ver: '1.2' - }; - } catch (e) { - logError('error creating native request: ' + String(e)); - } - } - - // get bidder params in form { : {...params} } - // initialize reduce function with the user defined `ext` properties on the ad unit - const ext = adUnit.bids.reduce((acc, bid) => { - if (bid.bidder == null) return acc; - const adapter = adapterManager.bidderRegistry[bid.bidder]; - if (adapter && adapter.getSpec().transformBidParams) { - bid.params = adapter.getSpec().transformBidParams(bid.params, true, adUnit, bidRequests); - } - deepSetValue(acc, - `prebid.bidder.${bid.bidder}`, - (s2sConfig.adapterOptions && s2sConfig.adapterOptions[bid.bidder]) ? Object.assign({}, bid.params, s2sConfig.adapterOptions[bid.bidder]) : bid.params - ); - return acc; - }, {...deepAccess(adUnit, 'ortb2Imp.ext')}); - - const imp = { ...adUnit.ortb2Imp, id: impressionId, ext, secure: s2sConfig.secure }; - - const ortb2 = {...deepAccess(adUnit, 'ortb2Imp.ext.data')}; - Object.keys(ortb2).forEach(prop => { - /** - * Prebid AdSlot - * @type {(string|undefined)} - */ - if (prop === 'pbadslot') { - if (typeof ortb2[prop] === 'string' && ortb2[prop]) { - deepSetValue(imp, 'ext.data.pbadslot', ortb2[prop]); - } else { - // remove pbadslot property if it doesn't meet the spec - delete imp.ext.data.pbadslot; - } - } else if (prop === 'adserver') { - /** - * Copy GAM AdUnit and Name to imp - */ - ['name', 'adslot'].forEach(name => { - /** @type {(string|undefined)} */ - const value = deepAccess(ortb2, `adserver.${name}`); - if (typeof value === 'string' && value) { - deepSetValue(imp, `ext.data.adserver.${name.toLowerCase()}`, value); - } - }); - } else { - deepSetValue(imp, `ext.data.${prop}`, ortb2[prop]); - } - }); - - mergeDeep(imp, mediaTypes); - - const convertCurrency = typeof getGlobal().convertCurrency !== 'function' - ? (amount) => amount - : (amount, from, to) => { - if (from === to) return amount; - let result = null; - try { - result = getGlobal().convertCurrency(amount, from, to); - } catch (e) { - } - return result; - } - - const floor = (() => { - // we have to pick a floor for the imp - here we attempt to find the minimum floor - // across all bids for this adUnit - const s2sCurrency = config.getConfig('currency.adServerCurrency') || DEFAULT_S2S_CURRENCY; - - return adUnit.bids - .map((bid) => this.getBidRequest(imp.id, bid.bidder)) - .map((bid) => { - if (!bid || typeof bid.getFloor !== 'function') return; - try { - const {currency, floor} = bid.getFloor({ - currency: s2sCurrency - }); - - return { - currency, - floor: parseFloat(floor) - } - } catch (e) { - logError('PBS: getFloor threw an error: ', e); - } - }) - .reduce((min, floor) => { - // if any bid does not have a valid floor, do not attempt to send any to PBS - if (floor == null || floor.currency == null || floor.floor == null || isNaN(floor.floor)) { - min.min = null; - } - if (min.min === null) { - return min; - } - // otherwise, pick the minimum one (or, in some strange confluence of circumstances, the one in the best currency) - if (min.ref == null) { - min.ref = min.min = floor; - } else { - const value = convertCurrency(floor.floor, floor.currency, min.ref.currency); - - if (value != null && value < min.ref.floor) { - min.ref.floor = value; - min.min = floor; - } - } - - return min; - }, {}).min - })(); - - if (floor) { - imp.bidfloor = floor.floor; - imp.bidfloorcur = floor.currency; - - // logic below relates to https://github.com/prebid/Prebid.js/issues/8749 and does the following: - // 1. check client-side floors (ref bidfloor/bidfloorcur & ortb2Imp floorMin/floorMinCur (if present)) - // 2. set pbs req wide floorMinCur to the first floor currency found when iterating over imp's - // (if currency conversion logic present, convert all imp floor values to this currency) - // 3. compare/store ref to lowest floorMin value as each imp is iterated over - // 4. set req wide floorMin and floorMinCur values for pbs after iterations are done - if (floorMinCur == null) { floorMinCur = floor.currency } - const ortb2ImpFloorMin = imp.ext?.prebid?.floors?.floorMin || imp.ext?.prebid?.floorMin; - const ortb2ImpFloorCur = imp.ext?.prebid?.floors?.floorMinCur || imp.ext?.prebid?.floorMinCur || floorMinCur; - - const convertedFloorMinValue = convertCurrency(floor.floor, floor.currency, floorMinCur); - const convertedOrtb2ImpFloorMinValue = ortb2ImpFloorMin && ortb2ImpFloorCur ? convertCurrency(ortb2ImpFloorMin, ortb2ImpFloorCur, floorMinCur) : false; - - const lowestImpFloorMin = convertedOrtb2ImpFloorMinValue && convertedOrtb2ImpFloorMinValue < convertedFloorMinValue - ? convertedOrtb2ImpFloorMinValue - : convertedFloorMinValue; - - deepSetValue(imp, 'ext.prebid.floors.floorMin', lowestImpFloorMin); - if (floorMin == null || floorMin > lowestImpFloorMin) { floorMin = lowestImpFloorMin } - } - - if (imp.banner || imp.video || imp.native) { - imps.push(imp); - } - }); - - if (!imps.length) { - logError('Request to Prebid Server rejected due to invalid media type(s) in adUnit.'); - return; - } - const request = { - id: firstBidRequest.auctionId, - source: {tid: firstBidRequest.auctionId}, - tmax: s2sConfig.timeout, - imp: imps, - // to do: add setconfig option to pass test = 1 - test: 0, - ext: { - prebid: { - // set ext.prebid.auctiontimestamp with the auction timestamp. Data type is long integer. - auctiontimestamp: firstBidRequest.auctionStart, - targeting: { - // includewinners is always true for openrtb - includewinners: true, - // includebidderkeys always false for openrtb - includebidderkeys: false - } - } - } - }; - - // If the price floors module is active, then we need to signal to PBS! If floorData obj is present is best way to check - if (typeof deepAccess(firstBidRequest, 'bids.0.floorData') === 'object') { - request.ext.prebid.floors = { enabled: false }; - } - - // This is no longer overwritten unless name and version explicitly overwritten by extPrebid (mergeDeep) - request.ext.prebid = Object.assign(request.ext.prebid, {channel: {name: 'pbjs', version: $$PREBID_GLOBAL$$.version}}); - - // set debug flag if in debug mode - if (getConfig('debug')) { - request.ext.prebid = Object.assign(request.ext.prebid, {debug: true}); - } - - // s2sConfig video.ext.prebid is passed through openrtb to PBS - if (s2sConfig.extPrebid && typeof s2sConfig.extPrebid === 'object') { - request.ext.prebid = mergeDeep(request.ext.prebid, s2sConfig.extPrebid); - } - - // get reference to pbs config schain bidder names (if any exist) - const pbsSchainBidderNamesArr = request.ext.prebid?.schains ? request.ext.prebid.schains.flatMap(s => s.bidders) : []; - // create an schains object - const schains = Object.fromEntries( - (request.ext.prebid?.schains || []).map(({bidders, schain}) => [JSON.stringify(schain), {bidders: new Set(bidders), schain}]) - ); - - // compare bidder specific schains with pbs specific schains - request.ext.prebid.schains = Object.values( - bidRequests - .map((req) => [req.bidderCode, req.bids[0].schain]) - .reduce((chains, [bidder, chain]) => { - const chainKey = JSON.stringify(chain); - - switch (true) { - // if pbjs bidder name is same as pbs bidder name, pbs bidder name always wins - case chainKey && pbsSchainBidderNamesArr.indexOf(bidder) !== -1: - logInfo(`bidder-specific schain for ${bidder} skipped due to existing entry`); - break; - // if a pbjs schain obj is equal to an schain obj that exists on the pbs side, add the bidder name on the pbs side - case chainKey && chains.hasOwnProperty(chainKey) && pbsSchainBidderNamesArr.indexOf(bidder) === -1: - chains[chainKey].bidders.add(bidder); - break; - // if a pbjs schain obj is not on the pbs side, add a new schain entry on the pbs side - case chainKey && !chains.hasOwnProperty(chainKey): - chains[chainKey] = {bidders: new Set(), schain: chain}; - chains[chainKey].bidders.add(bidder); - break; - default: - } - - return chains; - }, schains) - ).map(({bidders, schain}) => ({bidders: Array.from(bidders), schain})); - // if schains evaluates to an empty array, remove it from the prebid object - if (request.ext.prebid.schains.length === 0) delete request.ext.prebid.schains; - - /** - * @type {(string[]|string|undefined)} - OpenRTB property 'cur', currencies available for bids - */ - const adServerCur = config.getConfig('currency.adServerCurrency'); - if (adServerCur && typeof adServerCur === 'string') { - // if the value is a string, wrap it with an array - request.cur = [adServerCur]; - } else if (Array.isArray(adServerCur) && adServerCur.length) { - // if it's an array, get the first element - request.cur = [adServerCur[0]]; - } - - _appendSiteAppDevice(request, bidRequests[0].refererInfo.page, s2sConfig.accountId); - - // pass schain object if it is present - const schain = deepAccess(bidRequests, '0.bids.0.schain'); - if (schain) { - request.source.ext = { - schain: schain - }; - } - - if (!isEmpty(aliases)) { - request.ext.prebid.aliases = {...request.ext.prebid.aliases, ...aliases}; - } - - const bidUserIdAsEids = deepAccess(bidRequests, '0.bids.0.userIdAsEids'); - if (isArray(bidUserIdAsEids) && bidUserIdAsEids.length > 0) { - deepSetValue(request, 'user.ext.eids', bidUserIdAsEids); - } - - if (isArray(eidPermissions) && eidPermissions.length > 0) { - if (requestedBidders && isArray(requestedBidders)) { - eidPermissions.forEach(i => { - if (i.bidders) { - i.bidders = i.bidders.filter(bidder => includes(requestedBidders, bidder)) - } - }); - } - deepSetValue(request, 'ext.prebid.data.eidpermissions', eidPermissions); - } - - const multibid = config.getConfig('multibid'); - if (multibid) { - deepSetValue(request, 'ext.prebid.multibid', multibid.reduce((result, i) => { - let obj = {}; - - Object.keys(i).forEach(key => { - obj[key.toLowerCase()] = i[key]; - }); - - result.push(obj); - - return result; - }, [])); - } - - if (bidRequests) { - if (firstBidRequest.gdprConsent) { - // note - gdprApplies & consentString may be undefined in certain use-cases for consentManagement module - let gdprApplies; - if (typeof firstBidRequest.gdprConsent.gdprApplies === 'boolean') { - gdprApplies = firstBidRequest.gdprConsent.gdprApplies ? 1 : 0; - } - deepSetValue(request, 'regs.ext.gdpr', gdprApplies); - deepSetValue(request, 'user.ext.consent', firstBidRequest.gdprConsent.consentString); - if (firstBidRequest.gdprConsent.addtlConsent && typeof firstBidRequest.gdprConsent.addtlConsent === 'string') { - deepSetValue(request, 'user.ext.ConsentedProvidersSettings.consented_providers', firstBidRequest.gdprConsent.addtlConsent); - } - } - - // US Privacy (CCPA) support - if (firstBidRequest.uspConsent) { - deepSetValue(request, 'regs.ext.us_privacy', firstBidRequest.uspConsent); - } - } - - if (getConfig('coppa') === true) { - deepSetValue(request, 'regs.coppa', 1); - } - - const commonFpd = s2sBidRequest.ortb2Fragments?.global || {}; - mergeDeep(request, commonFpd); - - addBidderFirstPartyDataToRequest(request, s2sBidRequest.ortb2Fragments?.bidder || {}); - - request.imp.forEach((imp) => this.impRequested[imp.id] = imp); - - if (request.ext?.prebid?.floors?.enabled) { - request.ext.prebid.floors.floorMin = floorMin; - request.ext.prebid.floors.floorMinCur = floorMinCur; - } - - return request; - }, - - interpretResponse(response) { - const {bidderRequests, s2sConfig} = this; - const bids = []; - - [['errors', 'serverErrors'], ['responsetimemillis', 'serverResponseTimeMs']] - .forEach(info => getPbsResponseData(bidderRequests, response, info[0], info[1])) - - if (response.seatbid) { - // a seatbid object contains a `bid` array and a `seat` string - response.seatbid.forEach(seatbid => { - (seatbid.bid || []).forEach(bid => { - let bidRequest = this.getBidRequest(bid.impid, seatbid.seat); - if (bidRequest == null) { - // for stored impression, a request was made with bidder code `null`. Pick it up here so that NO_BID, BID_WON, etc events - // can work as expected (otherwise, the original request will always result in NO_BID). - bidRequest = this.getBidRequest(bid.impid, null); - } - - const cpm = bid.price; - const status = cpm !== 0 ? CONSTANTS.STATUS.GOOD : CONSTANTS.STATUS.NO_BID; - let bidObject = createBid(status, { - bidder: seatbid.seat, - src: TYPE, - bidId: bidRequest ? (bidRequest.bidId || bidRequest.bid_Id) : null, - transactionId: this.adUnitsByImp[bid.impid].transactionId, - auctionId: this.auctionId, - }); - bidObject.requestBidder = bidRequest?.bidder; - bidObject.requestTimestamp = this.requestTimestamp; - bidObject.cpm = cpm; - if (bid?.ext?.prebid?.meta?.adaptercode) { - bidObject.adapterCode = bid.ext.prebid.meta.adaptercode; - } else if (bidRequest?.bidder) { - bidObject.adapterCode = bidRequest.bidder; - } else { - bidObject.adapterCode = seatbid.seat; - } - - // temporarily leaving attaching it to each bidResponse so no breaking change - // BUT: this is a flat map, so it should be only attached to bidderRequest, a the change above does - let serverResponseTimeMs = deepAccess(response, ['ext', 'responsetimemillis', seatbid.seat].join('.')); - if (bidRequest && serverResponseTimeMs) { - bidRequest.serverResponseTimeMs = serverResponseTimeMs; - } - - // Look for seatbid[].bid[].ext.prebid.bidid and place it in the bidResponse object for use in analytics adapters as 'pbsBidId' - const bidId = deepAccess(bid, 'ext.prebid.bidid'); - if (isStr(bidId)) { - bidObject.pbsBidId = bidId; - } - - // store wurl by auctionId and adId so it can be accessed from the BID_WON event handler - if (isStr(deepAccess(bid, 'ext.prebid.events.win'))) { - addWurl(this.auctionId, bidObject.adId, deepAccess(bid, 'ext.prebid.events.win')); - } - - let extPrebidTargeting = deepAccess(bid, 'ext.prebid.targeting'); - - // If ext.prebid.targeting exists, add it as a property value named 'adserverTargeting' - // The removal of hb_winurl and hb_bidid targeting values is temporary - // once we get through the transition, this block will be removed. - if (isPlainObject(extPrebidTargeting)) { - // If wurl exists, remove hb_winurl and hb_bidid targeting attributes - if (isStr(deepAccess(bid, 'ext.prebid.events.win'))) { - extPrebidTargeting = getDefinedParams(extPrebidTargeting, Object.keys(extPrebidTargeting) - .filter(i => (i.indexOf('hb_winurl') === -1 && i.indexOf('hb_bidid') === -1))); - } - bidObject.adserverTargeting = extPrebidTargeting; - } - - bidObject.seatBidId = bid.id; - - if (deepAccess(bid, 'ext.prebid.type') === VIDEO) { - bidObject.mediaType = VIDEO; - const impReq = this.impRequested[bid.impid]; - [bidObject.playerWidth, bidObject.playerHeight] = [impReq.video.w, impReq.video.h]; - - // 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; - bidObject.vastUrl = bid.ext.prebid.cache.vastXml.url; - } else if (extPrebidTargeting && extPrebidTargeting.hb_uuid && extPrebidTargeting.hb_cache_host && extPrebidTargeting.hb_cache_path) { - bidObject.videoCacheKey = extPrebidTargeting.hb_uuid; - // build url using key and cache host - bidObject.vastUrl = `https://${extPrebidTargeting.hb_cache_host}${extPrebidTargeting.hb_cache_path}?uuid=${extPrebidTargeting.hb_uuid}`; - } - - if (bid.adm) { bidObject.vastXml = bid.adm; } - if (!bidObject.vastUrl && bid.nurl) { bidObject.vastUrl = bid.nurl; } - } else if (FEATURES.NATIVE && deepAccess(bid, 'ext.prebid.type') === NATIVE) { - bidObject.mediaType = NATIVE; - let ortb; - if (typeof bid.adm === 'string') { - ortb = bidObject.adm = JSON.parse(bid.adm); - } else { - ortb = bidObject.adm = bid.adm; - } - - if (isPlainObject(ortb) && Array.isArray(ortb.assets)) { - bidObject.native = { - ortb, - }; - } else { - logError('prebid server native response contained no assets'); - } - } else { // banner - if (bid.adm && bid.nurl) { - bidObject.ad = bid.adm; - bidObject.ad += createTrackPixelHtml(decodeURIComponent(bid.nurl)); - } else if (bid.adm) { - bidObject.ad = bid.adm; - } else if (bid.nurl) { - bidObject.adUrl = bid.nurl; - } - } - - bidObject.width = bid.w; - bidObject.height = bid.h; - if (bid.dealid) { bidObject.dealId = bid.dealid; } - bidObject.creative_id = bid.crid; - bidObject.creativeId = bid.crid; - if (bid.burl) { bidObject.burl = bid.burl; } - bidObject.currency = (response.cur) ? response.cur : DEFAULT_S2S_CURRENCY; - bidObject.meta = {}; - let extPrebidMeta = deepAccess(bid, 'ext.prebid.meta'); - if (extPrebidMeta && isPlainObject(extPrebidMeta)) { bidObject.meta = deepClone(extPrebidMeta); } - if (bid.adomain) { bidObject.meta.advertiserDomains = bid.adomain; } - - // the OpenRTB location for "TTL" as understood by Prebid.js is "exp" (expiration). - const configTtl = s2sConfig.defaultTtl || DEFAULT_S2S_TTL; - bidObject.ttl = (bid.exp) ? bid.exp : configTtl; - bidObject.netRevenue = (bid.netRevenue) ? bid.netRevenue : DEFAULT_S2S_NETREVENUE; - - bids.push({ adUnit: this.adUnitsByImp[bid.impid].code, bid: bidObject }); - }); - }); - } - - return bids; - }, - setBidRequestId(impId, bidderCode, bidId) { - this.bidIdMap[this.impBidderKey(impId, bidderCode)] = bidId; - }, - getBidRequest(impId, bidderCode) { - const key = this.impBidderKey(impId, bidderCode); - return this.bidIdMap[key] && getBidRequest(this.bidIdMap[key], this.bidderRequests); - }, - impBidderKey(impId, bidderCode) { - return `${impId}${bidderCode}`; - } -}); - /** * BID_WON event to request the wurl * @param {Bid} bid the winning bid object @@ -1161,6 +462,9 @@ export function PrebidServer() { } else { if (metrics.measureTime('addBidResponse.validate', () => isValid(adUnit, bid))) { addBidResponse(adUnit, bid); + if (bid.pbsWurl) { + addWurl(bid.auctionId, bid.adId, bid.pbsWurl); + } } else { addBidResponse.reject(adUnit, bid, CONSTANTS.REJECTION_REASON.INVALID); } @@ -1200,8 +504,7 @@ export const processPBSRequest = hook('sync', function (s2sBidRequest, bidReques .reduce(flatten, []) .filter(uniques); - const ortb2 = new ORTB2(s2sBidRequest, bidRequests, adUnits, requestedBidders); - const request = s2sBidRequest.metrics.measureTime('buildRequests', () => ortb2.buildRequest()); + const request = s2sBidRequest.metrics.measureTime('buildRequests', () => buildPBSRequest(s2sBidRequest, bidRequests, adUnits, requestedBidders, eidPermissions)); const requestJson = request && JSON.stringify(request); logInfo('BidRequest: ' + requestJson); const endpointUrl = getMatchingConsentUrl(s2sBidRequest.s2sConfig.endpoint, gdprConsent); @@ -1215,7 +518,7 @@ export const processPBSRequest = hook('sync', function (s2sBidRequest, bidReques let result; try { result = JSON.parse(response); - const bids = s2sBidRequest.metrics.measureTime('interpretResponse', () => ortb2.interpretResponse(result)); + const bids = s2sBidRequest.metrics.measureTime('interpretResponse', () => interpretPBSResponse(result, request).bids); bids.forEach(onBid); } catch (error) { logError(error); diff --git a/modules/prebidServerBidAdapter/ortbConverter.js b/modules/prebidServerBidAdapter/ortbConverter.js new file mode 100644 index 00000000000..0aee261c25d --- /dev/null +++ b/modules/prebidServerBidAdapter/ortbConverter.js @@ -0,0 +1,274 @@ +import {ortbConverter} from '../../libraries/ortbConverter/converter.js'; +import { + deepAccess, + deepSetValue, + getBidRequest, + getDefinedParams, + isArray, + logError, + logWarn, + mergeDeep, + timestamp +} from '../../src/utils.js'; +import {config} from '../../src/config.js'; +import CONSTANTS from '../../src/constants.json'; +import {createBid} from '../../src/bidfactory.js'; +import {pbsExtensions} from '../../libraries/pbsExtensions/pbsExtensions.js'; +import {setImpBidParams} from '../../libraries/pbsExtensions/processors/params.js'; +import {SUPPORTED_MEDIA_TYPES} from '../../libraries/pbsExtensions/processors/mediaType.js'; +import {IMP, REQUEST, RESPONSE} from '../../src/pbjsORTB.js'; +import {beConvertCurrency} from '../../src/utils/currency.js'; + +const DEFAULT_S2S_TTL = 60; +const DEFAULT_S2S_CURRENCY = 'USD'; +const DEFAULT_S2S_NETREVENUE = true; +const BIDDER_SPECIFIC_REQUEST_PROPS = new Set(['bidderCode', 'bidderRequestId', 'uniquePbsTid', 'bids', 'timeout']); + +const PBS_CONVERTER = ortbConverter({ + processors: pbsExtensions, + context: { + netRevenue: DEFAULT_S2S_NETREVENUE, + }, + imp(buildImp, proxyBidRequest, context) { + Object.assign(context, proxyBidRequest.pbsData); + const imp = buildImp(proxyBidRequest, context); + if (Object.values(SUPPORTED_MEDIA_TYPES).some(mtype => imp[mtype])) { + imp.secure = context.s2sBidRequest.s2sConfig.secure; + return imp; + } + }, + request(buildRequest, imps, proxyBidderRequest, context) { + if (!imps.length) { + logError('Request to Prebid Server rejected due to invalid media type(s) in adUnit.'); + } else { + let {s2sBidRequest, requestedBidders, eidPermissions} = context; + const request = buildRequest(imps, proxyBidderRequest, context); + + request.tmax = s2sBidRequest.s2sConfig.timeout; + deepSetValue(request, 'source.tid', proxyBidderRequest.auctionId); + + [request.app, request.site].forEach(section => { + if (section && !section.publisher?.id) { + deepSetValue(section, 'publisher.id', s2sBidRequest.s2sConfig.accountId); + } + }) + + if (isArray(eidPermissions) && eidPermissions.length > 0) { + if (requestedBidders && isArray(requestedBidders)) { + eidPermissions = eidPermissions.map(p => ({ + ...p, + bidders: p.bidders.filter(bidder => requestedBidders.includes(bidder)) + })) + } + deepSetValue(request, 'ext.prebid.data.eidpermissions', eidPermissions); + } + + return request; + } + }, + bidResponse(buildBidResponse, bid, context) { + // before sending the response throgh "stock" ortb conversion, here we need to: + // - filter out ones that come from an "unknown" bidder (if allowUnknownBidderCode is not set) + // - overwrite context.bidRequest with the actual bid request for this seat / imp combination + + let bidRequest = context.actualBidRequests.get(context.seatbid.seat); + if (bidRequest == null) { + // for stored impressions, a request was made with bidder code `null`. Pick it up here so that NO_BID, BID_WON, etc events + // can work as expected (otherwise, the original request will always result in NO_BID). + bidRequest = context.actualBidRequests.get(null); + } + + if (bidRequest) { + Object.assign(context, { + bidRequest, + bidderRequest: context.actualBidderRequests.find(req => req.bidderCode === bidRequest.bidder) + }) + } + + const bidResponse = buildBidResponse(bid, context); + bidResponse.requestBidder = bidRequest?.bidder; + + if (bidResponse.native?.ortb) { + // TODO: do we need to set bidResponse.adm here? + // Any consumers can now get the same object from bidResponse.native.ortb; + // I could not find any, which raises the question - who is looking for this? + bidResponse.adm = bidResponse.native.ortb; + } + + // because core has special treatment for PBS adapter responses, we need some additional processing + bidResponse.requestTimestamp = context.requestTimestamp; + const status = bid.price !== 0 ? CONSTANTS.STATUS.GOOD : CONSTANTS.STATUS.NO_BID; + return { + bid: Object.assign(createBid(status, { + src: CONSTANTS.S2S.SRC, + bidId: bidRequest ? (bidRequest.bidId || bidRequest.bid_Id) : null, + transactionId: context.adUnit.transactionId, + auctionId: context.bidderRequest.auctionId, + }), bidResponse), + adUnit: context.adUnit.code + }; + }, + overrides: { + [IMP]: { + id(orig, imp, proxyBidRequest, context) { + imp.id = context.impId; + }, + params(orig, imp, proxyBidRequest, context) { + // override params processing to do it for each bidRequest in this imp; + // also, take overrides from s2sConfig.adapterOptions + const adapterOptions = context.s2sBidRequest.s2sConfig.adapterOptions; + for (const req of context.actualBidRequests.values()) { + setImpBidParams(imp, req, context, context); + if (adapterOptions && adapterOptions[req.bidder]) { + Object.assign(imp.ext.prebid.bidder[req.bidder], adapterOptions[req.bidder]); + } + } + }, + bidfloor(orig, imp, proxyBidRequest, context) { + // for bid floors, we pass each bidRequest associated with this imp through normal bidfloor processing, + // and aggregate all of them into a single, minimum floor to put in the request + let min; + for (const req of context.actualBidRequests.values()) { + const floor = {}; + orig(floor, req, context); + // if any bid does not have a valid floor, do not attempt to send any to PBS + if (floor.bidfloorcur == null || floor.bidfloor == null) { + min = null; + break; + } else if (min == null) { + min = floor; + } else { + const value = beConvertCurrency(floor.bidfloor, floor.bidfloorcur, min.bidfloorcur); + if (value != null && value < min.bidfloor) { + min = floor; + } + } + } + if (min != null) { + Object.assign(imp, min); + } + } + }, + [REQUEST]: { + fpd(orig, ortbRequest, proxyBidderRequest, context) { + // FPD is handled different for PBS - the base request will only contain global FPD; + // bidder-specific values are set in ext.prebid.bidderconfig + + mergeDeep(ortbRequest, context.s2sBidRequest.ortb2Fragments?.global); + + // also merge in s2sConfig.extPrebid + if (context.s2sBidRequest.s2sConfig.extPrebid && typeof context.s2sBidRequest.s2sConfig.extPrebid === 'object') { + deepSetValue(ortbRequest, 'ext.prebid', mergeDeep(ortbRequest.ext?.prebid || {}, context.s2sBidRequest.s2sConfig.extPrebid)); + } + + const fpdConfigs = Object.entries(context.s2sBidRequest.ortb2Fragments?.bidder || {}).map(([bidder, ortb2]) => ({ + bidders: [bidder], + config: {ortb2} + })); + if (fpdConfigs.length) { + deepSetValue(ortbRequest, 'ext.prebid.bidderconfig', fpdConfigs); + } + }, + extPrebidAliases(orig, ortbRequest, proxyBidderRequest, context) { + // override alias processing to do it for each bidder in the request + context.actualBidderRequests.forEach(req => orig(ortbRequest, req, context)); + }, + sourceExtSchain(orig, ortbRequest, proxyBidderRequest, context) { + // pass schains in ext.prebid.schains, with the most commonly used one in source.ext.schain + let mainChain; + + let chains = (deepAccess(ortbRequest, 'ext.prebid.schains') || []); + const chainBidders = new Set(chains.flatMap((item) => item.bidders)); + + chains = Object.values( + chains + .concat(context.actualBidderRequests + .filter((req) => !chainBidders.has(req.bidderCode)) // schain defined in s2sConfig.extPrebid takes precedence + .map((req) => ({ + bidders: [req.bidderCode], + schain: deepAccess(req, 'bids.0.schain') + }))) + .filter(({bidders, schain}) => bidders?.length > 0 && schain) + .reduce((chains, {bidders, schain}) => { + const key = JSON.stringify(schain); + if (!chains.hasOwnProperty(key)) { + chains[key] = {bidders: new Set(), schain}; + } + bidders.forEach((bidder) => chains[key].bidders.add(bidder)); + if (mainChain == null || chains[key].bidders.size > mainChain.bidders.size) { + mainChain = chains[key] + } + return chains; + }, {}) + ).map(({bidders, schain}) => ({bidders: Array.from(bidders), schain})); + + if (mainChain != null) { + deepSetValue(ortbRequest, 'source.ext.schain', mainChain.schain); + } + + if (chains.length) { + deepSetValue(ortbRequest, 'ext.prebid.schains', chains); + } + } + }, + [RESPONSE]: { + serverSideStats(orig, response, ortbResponse, context) { + // override to process each request + context.actualBidderRequests.forEach(req => orig(response, ortbResponse, {...context, bidderRequest: req, bidRequests: req.bids})); + } + } + }, +}); + +export function buildPBSRequest(s2sBidRequest, bidderRequests, adUnits, requestedBidders, eidPermissions) { + const requestTimestamp = timestamp(); + const impIds = new Set(); + const proxyBidRequests = []; + + adUnits.forEach(adUnit => { + const actualBidRequests = new Map(); + + adUnit.bids.forEach((bid) => { + if (bid.mediaTypes != null) { + // TODO: support labels / conditional bids + // for now, just warn about them + logWarn(`Prebid Server adapter does not (yet) support bidder-specific mediaTypes for the same adUnit. Size mapping configuration will be ignored for adUnit: ${adUnit.code}, bidder: ${bid.bidder}`); + } + actualBidRequests.set(bid.bidder, getBidRequest(bid.bid_id, bidderRequests)); + }); + + let impId = adUnit.code; + let i = 1; + while (impIds.has(impId)) { + i++; + impId = `${adUnit.code}-${i}`; + } + impIds.add(impId) + proxyBidRequests.push({ + ...adUnit, + ...getDefinedParams(actualBidRequests.values().next().value || {}, ['userId', 'userIdAsEids', 'schain']), + pbsData: {impId, actualBidRequests, adUnit} + }); + }); + + const proxyBidderRequest = Object.fromEntries(Object.entries(bidderRequests[0]).filter(([k]) => !BIDDER_SPECIFIC_REQUEST_PROPS.has(k))) + + return PBS_CONVERTER.toORTB({ + bidderRequest: proxyBidderRequest, + bidRequests: proxyBidRequests, + context: { + currency: config.getConfig('currency.adServerCurrency') || DEFAULT_S2S_CURRENCY, + ttl: s2sBidRequest.s2sConfig.defaultTtl || DEFAULT_S2S_TTL, + requestTimestamp, + s2sBidRequest, + requestedBidders, + actualBidderRequests: bidderRequests, + eidPermissions, + nativeRequest: s2sBidRequest.s2sConfig.ortbNative, + } + }); +} + +export function interpretPBSResponse(response, request) { + return PBS_CONVERTER.fromORTB({response, request}); +} diff --git a/modules/priceFloors.js b/modules/priceFloors.js index 5aee87d474e..d7ab811d673 100644 --- a/modules/priceFloors.js +++ b/modules/priceFloors.js @@ -10,6 +10,7 @@ import { logError, logInfo, logWarn, + mergeDeep, parseGPTSingleSizeArray, parseUrl, pick @@ -24,7 +25,9 @@ import {find} from '../src/polyfill.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {bidderSettings} from '../src/bidderSettings.js'; import {auctionManager} from '../src/auctionManager.js'; +import {IMP, PBS, registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; import {timedAuctionHook, timedBidResponseHook} from '../src/utils/perfMetrics.js'; +import {beConvertCurrency} from '../src/utils/currency.js'; /** * @summary This Module is intended to provide users with the ability to dynamically set and enforce price floors on a per auction basis. @@ -745,3 +748,72 @@ export const addBidResponseHook = timedBidResponseHook('priceFloors', function a }); config.getConfig('floors', config => handleSetFloorsConfig(config.floors)); + +/** + * Sets bidfloor and bidfloorcur for ORTB imp objects + */ +export function setOrtbImpBidFloor(imp, bidRequest, context) { + if (typeof bidRequest.getFloor === 'function') { + let currency, floor; + try { + ({currency, floor} = bidRequest.getFloor({ + currency: context.currency || config.getConfig('currency.adServerCurrency') || 'USD', + mediaType: context.mediaType || '*', + size: '*' + })); + } catch (e) { + logWarn('Cannot compute floor for bid', bidRequest); + return; + } + floor = parseFloat(floor); + if (currency != null && floor != null && !isNaN(floor)) { + Object.assign(imp, { + bidfloor: floor, + bidfloorcur: currency + }); + } + } +} + +export function setImpExtPrebidFloors(imp, bidRequest, context) { + // logic below relates to https://github.com/prebid/Prebid.js/issues/8749 and does the following: + // 1. check client-side floors (ref bidfloor/bidfloorcur & ortb2Imp floorMin/floorMinCur (if present)) + // 2. set pbs req wide floorMinCur to the first floor currency found when iterating over imp's + // (if currency conversion logic present, convert all imp floor values to this currency) + // 3. compare/store ref to lowest floorMin value as each imp is iterated over + // 4. set req wide floorMin and floorMinCur values for pbs after iterations are done + + if (imp.bidfloor != null) { + let {floorMinCur, floorMin} = context.reqContext.floorMin || {}; + + if (floorMinCur == null) { floorMinCur = imp.bidfloorcur } + const ortb2ImpFloorCur = imp.ext?.prebid?.floors?.floorMinCur || imp.ext?.prebid?.floorMinCur || floorMinCur; + const ortb2ImpFloorMin = imp.ext?.prebid?.floors?.floorMin || imp.ext?.prebid?.floorMin; + const convertedFloorMinValue = beConvertCurrency(imp.bidfloor, imp.bidfloorcur, floorMinCur); + const convertedOrtb2ImpFloorMinValue = ortb2ImpFloorMin && ortb2ImpFloorCur ? beConvertCurrency(ortb2ImpFloorMin, ortb2ImpFloorCur, floorMinCur) : false; + + const lowestImpFloorMin = convertedOrtb2ImpFloorMinValue && convertedOrtb2ImpFloorMinValue < convertedFloorMinValue + ? convertedOrtb2ImpFloorMinValue + : convertedFloorMinValue; + + deepSetValue(imp, 'ext.prebid.floors.floorMin', lowestImpFloorMin); + if (floorMin == null || floorMin > lowestImpFloorMin) { floorMin = lowestImpFloorMin } + context.reqContext.floorMin = {floorMin, floorMinCur}; + } +} + +/** + * PBS specific extension: set ext.prebid.floors.enabled = false if floors are processed client-side + */ +export function setOrtbExtPrebidFloors(ortbRequest, bidderRequest, context) { + if (addedFloorsHook) { + deepSetValue(ortbRequest, 'ext.prebid.floors.enabled', ortbRequest.ext?.prebid?.floors?.enabled || false); + } + if (context?.floorMin) { + mergeDeep(ortbRequest, {ext: {prebid: {floors: context.floorMin}}}) + } +} + +registerOrtbProcessor({type: IMP, name: 'bidfloor', fn: setOrtbImpBidFloor}); +registerOrtbProcessor({type: IMP, name: 'extPrebidFloors', fn: setImpExtPrebidFloors, dialects: [PBS], priority: -1}); +registerOrtbProcessor({type: REQUEST, name: 'extPrebidFloors', fn: setOrtbExtPrebidFloors, dialects: [PBS]}); diff --git a/modules/schain.js b/modules/schain.js index ef1c6da78ce..eac2cb93b0a 100644 --- a/modules/schain.js +++ b/modules/schain.js @@ -1,6 +1,18 @@ 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'; +import { + isNumber, + isStr, + isArray, + isPlainObject, + hasOwn, + logError, + isInteger, + _each, + logWarn, + deepAccess, deepSetValue +} from '../src/utils.js'; +import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; // https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/supplychainobject.md @@ -181,3 +193,14 @@ export function init() { } init() + +export function setOrtbSourceExtSchain(ortbRequest, bidderRequest, context) { + if (!deepAccess(ortbRequest, 'source.ext.schain')) { + const schain = deepAccess(context, 'bidRequests.0.schain'); + if (schain) { + deepSetValue(ortbRequest, 'source.ext.schain', schain); + } + } +} + +registerOrtbProcessor({type: REQUEST, name: 'sourceExtSchain', fn: setOrtbSourceExtSchain}); diff --git a/modules/userId/index.js b/modules/userId/index.js index 73295011089..6df78b9e73c 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -149,11 +149,12 @@ import { logInfo, logWarn, timestamp, - isEmpty + isEmpty, deepSetValue } from '../../src/utils.js'; import {getPPID as coreGetPPID} from '../../src/adserver.js'; import {defer, GreedyPromise} from '../../src/utils/promise.js'; import {hasPurpose1Consent} from '../../src/utils/gpdr.js'; +import {registerOrtbProcessor, REQUEST} from '../../src/pbjsORTB.js'; import {newMetrics, timedAuctionHook, useMetrics} from '../../src/utils/perfMetrics.js'; const MODULE_NAME = 'User ID'; @@ -1082,3 +1083,11 @@ export function init(config, {delay = GreedyPromise.timeout} = {}) { init(config); module('userId', attachIdSystem); + +export function setOrtbUserExtEids(ortbRequest, bidderRequest, context) { + const eids = deepAccess(context, 'bidRequests.0.userIdAsEids'); + if (eids) { + deepSetValue(ortbRequest, 'user.ext.eids', eids); + } +} +registerOrtbProcessor({type: REQUEST, name: 'userExtEids', fn: setOrtbUserExtEids}); diff --git a/package-lock.json b/package-lock.json index daa59e6ad12..61d961b102e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19020,9 +19020,9 @@ } }, "node_modules/nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "dev": true, "optional": true }, @@ -43578,9 +43578,9 @@ } }, "nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "dev": true, "optional": true }, diff --git a/src/pbjsORTB.js b/src/pbjsORTB.js new file mode 100644 index 00000000000..cc5c1c5bdd9 --- /dev/null +++ b/src/pbjsORTB.js @@ -0,0 +1,35 @@ +export const PROCESSOR_TYPES = ['request', 'imp', 'bidResponse', 'response']; +export const PROCESSOR_DIALECTS = ['default', 'pbs']; +export const [REQUEST, IMP, BID_RESPONSE, RESPONSE] = PROCESSOR_TYPES; +export const [DEFAULT, PBS] = PROCESSOR_DIALECTS; + +const types = new Set(PROCESSOR_TYPES); + +export function processorRegistry() { + const processors = {}; + + return { + registerOrtbProcessor({type, name, fn, priority = 0, dialects = [DEFAULT]}) { + if (!types.has(type)) { + throw new Error(`ORTB processor type must be one of: ${PROCESSOR_TYPES.join(', ')}`) + } + dialects.forEach(dialect => { + if (!processors.hasOwnProperty(dialect)) { + processors[dialect] = {}; + } + if (!processors[dialect].hasOwnProperty(type)) { + processors[dialect][type] = {}; + } + processors[dialect][type][name] = { + priority, + fn + } + }) + }, + getProcessors(dialect) { + return processors[dialect] || {}; + } + } +} + +export const {registerOrtbProcessor, getProcessors} = processorRegistry(); diff --git a/src/utils.js b/src/utils.js index 9e49e1687ae..869e1007841 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1377,6 +1377,27 @@ export function safeJSONParse(data) { } catch (e) {} } +/** + * Returns a memoized version of `fn`. + * + * @param fn + * @param key cache key generator, invoked with the same arguments passed to `fn`. + * By default, the first argument is used as key. + * @return {function(): any} + */ +export function memoize(fn, key = function (arg) { return arg; }) { + const cache = new Map(); + const memoized = function () { + const cacheKey = key.apply(this, arguments); + if (!cache.has(cacheKey)) { + cache.set(cacheKey, fn.apply(this, arguments)); + } + return cache.get(cacheKey); + } + memoized.clear = cache.clear.bind(cache); + return memoized; +} + /** * Sets dataset attributes on a script * @param {Script} script diff --git a/src/utils/currency.js b/src/utils/currency.js new file mode 100644 index 00000000000..ab7e5faa1ea --- /dev/null +++ b/src/utils/currency.js @@ -0,0 +1,16 @@ +import {getGlobal} from '../prebidGlobal.js'; + +/** + * "best effort" wrapper around currency conversion; always returns an amount that may or may not be correct. + */ +export function beConvertCurrency(amount, from, to) { + if (from === to) return amount; + let result = amount; + if (typeof getGlobal().convertCurrency === 'function') { + try { + result = getGlobal().convertCurrency(amount, from, to); + } catch (e) { + } + } + return result; +} diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js index d88266af386..9190c008a9f 100644 --- a/test/spec/modules/improvedigitalBidAdapter_spec.js +++ b/test/spec/modules/improvedigitalBidAdapter_spec.js @@ -1,9 +1,20 @@ import { expect } from 'chai'; -import { spec } from 'modules/improvedigitalBidAdapter.js'; +import {CONVERTER, spec} from 'modules/improvedigitalBidAdapter.js'; import { config } from 'src/config.js'; import { deepClone } from 'src/utils.js'; import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes'; import { deepSetValue } from '../../../src/utils'; +// load modules that register ORTB processors +import 'src/prebid.js'; +import 'modules/currency.js'; +import 'modules/userId/index.js'; +import 'modules/multibid/index.js'; +import 'modules/priceFloors.js'; +import 'modules/consentManagement.js'; +import 'modules/consentManagementUsp.js'; +import 'modules/schain.js'; +import {decorateAdUnitsWithNativeParams, toLegacyResponse} from '../../../src/native.js'; +import {createEidsArray} from '../../../modules/userId/eids.js'; describe('Improve Digital Adapter Tests', function () { const METHOD = 'POST'; @@ -93,6 +104,7 @@ describe('Improve Digital Adapter Tests', function () { }; const simpleSmartTagBidRequest = { + mediaTypes: {}, bidder: 'improvedigital', bidId: '1a2b3c', placementCode: 'placement1', @@ -103,27 +115,27 @@ describe('Improve Digital Adapter Tests', function () { }; const bidderRequest = { - bids: [simpleBidRequest] + bids: [simpleBidRequest], }; const extendBidderRequest = { - bids: [extendBidRequest] + bids: [extendBidRequest], }; const instreamBidderRequest = { - bids: [instreamBidRequest] + bids: [instreamBidRequest], }; const outstreamBidderRequest = { - bids: [outstreamBidRequest] + bids: [outstreamBidRequest], }; const multiFormatBidderRequest = { - bids: [multiFormatBidRequest] + bids: [multiFormatBidRequest], }; const nativeBidderRequest = { - bids: [nativeBidRequest] + bids: [nativeBidRequest], }; const gdprConsent = { @@ -147,6 +159,12 @@ describe('Improve Digital Adapter Tests', function () { }, }; + function updateNativeParams(bidRequests) { + bidRequests = deepClone(bidRequests); + decorateAdUnitsWithNativeParams(bidRequests); + return bidRequests; + } + describe('isBidRequestValid', function () { it('should return false when no bid', function () { expect(spec.isBidRequestValid()).to.equal(false); @@ -203,20 +221,18 @@ describe('Improve Digital Adapter Tests', function () { expect(request).to.be.an('object'); expect(request.method).to.equal(METHOD); expect(request.url).to.equal(AD_SERVER_URL); - expect(request.bidderRequest).to.deep.equal(bidderRequest); const payload = JSON.parse(request.data); expect(payload).to.be.an('object'); expect(payload.id).to.be.a('string'); expect(payload.tmax).not.to.exist; - expect(payload.cur).to.be.an('array'); expect(payload.regs).to.not.exist; expect(payload.schain).to.not.exist; - expect(payload.source).to.deep.equal({ ext: {}, tid: 'f183e871-fbed-45f0-a427-c8a63c4c01eb' }); + sinon.assert.match(payload.source, {tid: 'f183e871-fbed-45f0-a427-c8a63c4c01eb'}) expect(payload.device).to.be.an('object'); expect(payload.user).to.not.exist; - expect(payload.imp).to.deep.equal([ - { + sinon.assert.match(payload.imp, [ + sinon.match({ id: '33e9500b21129f', secure: 0, ext: { @@ -230,28 +246,23 @@ describe('Improve Digital Adapter Tests', function () { {w: 160, h: 600}, ] } - } + }) ]); }); it('should make a well-formed request object for multi-format ad unit', function () { getConfigStub = sinon.stub(config, 'getConfig'); getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true); - const request = spec.buildRequests([multiFormatBidRequest], multiFormatBidderRequest)[0]; + const request = spec.buildRequests(updateNativeParams([multiFormatBidRequest]), multiFormatBidderRequest)[0]; expect(request).to.be.an('object'); expect(request.method).to.equal(METHOD); expect(request.url).to.equal(AD_SERVER_URL); - expect(request.bidderRequest).to.deep.equal(multiFormatBidderRequest); const payload = JSON.parse(request.data); expect(payload).to.be.an('object'); - expect(payload.imp).to.deep.equal([ - { + sinon.assert.match(payload.imp, [ + sinon.match({ id: '33e9500b21129f', - native: { - request: '{"eventtrackers":[{"event":1,"methods":[1,2]}],"assets":[{"id":3,"required":1,"data":{"type":2}}]}', - ver: '1.2' - }, secure: 0, ext: { bidder: { @@ -270,53 +281,54 @@ describe('Improve Digital Adapter Tests', function () { {w: 160, h: 600}, ] } - } + }) ]); + if (FEATURES.NATIVE) { + sinon.assert.match(payload.imp[0], { + native: { + ver: '1.2' + }, + }) + const nativeReq = JSON.parse(payload.imp[0].native.request); + sinon.assert.match(nativeReq, { + eventtrackers: [ + {event: 1, methods: [1, 2]}, + ], + 'assets': [ + sinon.match({'required': 1, 'data': {'type': 2}}) + ] + }); + } }); - it('should make a well-formed native request', function () { - const payload = JSON.parse(spec.buildRequests([nativeBidRequest], {})[0].data); - expect(payload.imp[0].native).to.deep.equal({ - ver: '1.2', - request: '{"eventtrackers":[{"event":1,"methods":[1,2]}],"assets":[{"id":0,"required":1,"title":{"len":140}},{"id":3,"required":1,"data":{"type":2}}]}' + if (FEATURES.NATIVE) { + it('should make a well-formed native request', function () { + const payload = JSON.parse(spec.buildRequests(updateNativeParams([nativeBidRequest]), {})[0].data); + const nativeReq = JSON.parse(payload.imp[0].native.request); + sinon.assert.match(nativeReq, { + eventtrackers: [ + {event: 1, methods: [1, 2]}, + ], + assets: [ + sinon.match({required: 1, title: {len: 140}}), + sinon.match({required: 1, data: {type: 2}}) + ] + }) }); - }); - it('should not make native request when nativeParams is undefined', function () { - const request = deepClone(nativeBidRequest); - delete request.nativeParams; - const payload = JSON.parse(spec.buildRequests([request], {})[0].data); - expect(payload.imp[0].native).to.not.exist; - }); - - it('should not make native request when no assets', function () { - const request = deepClone(nativeBidRequest); - request.nativeParams = {}; - const payload = JSON.parse(spec.buildRequests([request], {})[0].data); - expect(payload.imp[0].native).to.not.exist; - }); - - it('should make a well-formed native request', function () { - const payload = JSON.parse(spec.buildRequests([nativeBidRequest], {})[0].data); - expect(payload.imp[0].native).to.deep.equal({ - ver: '1.2', - request: '{"eventtrackers":[{"event":1,"methods":[1,2]}],"assets":[{"id":0,"required":1,"title":{"len":140}},{"id":3,"required":1,"data":{"type":2}}]}' + it('should not make native request when nativeOrtbRequest is undefined', function () { + const requests = updateNativeParams([nativeBidRequest]); + delete requests[0].nativeOrtbRequest; + const payload = JSON.parse(spec.buildRequests(requests, {})[0].data); + expect(payload.imp[0].native).to.not.exist; }); - }); - it('should not make native request when nativeParams is undefined', function () { - const request = deepClone(nativeBidRequest); - delete request.nativeParams; - const payload = JSON.parse(spec.buildRequests([request], {})[0].data); - expect(payload.imp[0].native).to.not.exist; - }); - - it('should not make native request when no assets', function () { - const request = deepClone(nativeBidRequest); - request.nativeParams = {}; - const payload = JSON.parse(spec.buildRequests([request], {})[0].data); - expect(payload.imp[0].native).to.not.exist; - }); + it('should not make native request when no assets', function () { + const requests = updateNativeParams([{...nativeBidRequest, nativeParams: {}}]) + const payload = JSON.parse(spec.buildRequests(requests, {})[0].data); + expect(payload.imp[0].native).to.not.exist; + }); + } it('should set placementKey and publisherId for smart tags', function () { const payload = JSON.parse(spec.buildRequests([simpleSmartTagBidRequest], bidderRequest)[0].data); @@ -337,10 +349,14 @@ describe('Improve Digital Adapter Tests', function () { }); it('should add currency', function () { - const bidRequest = Object.assign({}, simpleBidRequest); - getConfigStub = sinon.stub(config, 'getConfig').returns('JPY'); - const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data); - expect(payload.cur).to.deep.equal(['JPY']); + config.setConfig({currency: {adServerCurrency: 'JPY'}}); + try { + const bidRequest = Object.assign({}, simpleBidRequest); + const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest)[0].data); + expect(payload.cur).to.deep.equal(['JPY']); + } finally { + config.resetConfig(); + } }); it('should add bid floor', function () { @@ -486,40 +502,6 @@ describe('Improve Digital Adapter Tests', function () { expect(payload.imp[0].video.w).equal(640); }); - it('should set skip params only if skip=1', function() { - const bidRequest = deepClone(instreamBidRequest); - // 1 - const videoTest = { - skip: 1, - skipmin: 5, - skipafter: 30 - } - bidRequest.params.video = videoTest; - let request = spec.buildRequests([bidRequest], {})[0]; - let payload = JSON.parse(request.data); - expect(payload.imp[0].video.skip).to.equal(1); - expect(payload.imp[0].video.skipmin).to.equal(5); - expect(payload.imp[0].video.skipafter).to.equal(30); - - // 0 - leave out skipmin and skipafter - videoTest.skip = 0; - bidRequest.params.video = videoTest; - request = spec.buildRequests([bidRequest], {})[0]; - payload = JSON.parse(request.data); - expect(payload.imp[0].video.skip).to.equal(0); - expect(payload.imp[0].video.skipmin).to.not.exist; - expect(payload.imp[0].video.skipafter).to.not.exist; - - // other - videoTest.skip = 'blah'; - bidRequest.params.video = videoTest; - request = spec.buildRequests([bidRequest], {})[0]; - payload = JSON.parse(request.data); - expect(payload.imp[0].video.skip).to.not.exist; - expect(payload.imp[0].video.skipmin).to.not.exist; - expect(payload.imp[0].video.skipafter).to.not.exist; - }); - it('should ignore invalid/unexpected video params', function() { const bidRequest = deepClone(instreamBidRequest); // 1 @@ -583,7 +565,7 @@ describe('Improve Digital Adapter Tests', function () { }] }]}}; const bidRequest = Object.assign({}, simpleBidRequest); - bidRequest.userId = userId; + bidRequest.userIdAsEids = createEidsArray(userId); const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0]; const payload = JSON.parse(request.data); expect(payload.user).to.deep.equal(expectedUserObject); @@ -596,8 +578,6 @@ describe('Improve Digital Adapter Tests', function () { ], 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 () { @@ -632,7 +612,7 @@ describe('Improve Digital Adapter Tests', function () { getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true); const request = spec.buildRequests([simpleBidRequest], bidderRequest)[0]; const payload = JSON.parse(request.data); - expect(payload.imp[0].banner).to.deep.equal({ + sinon.assert.match(payload.imp[0].banner, { format: [ { w: 300, h: 250 }, { w: 160, h: 600 } @@ -651,7 +631,7 @@ describe('Improve Digital Adapter Tests', function () { bidRequest.params.size = size; const request = spec.buildRequests([bidRequest], bidderRequest)[0]; const payload = JSON.parse(request.data); - expect(payload.imp[0].banner).to.deep.equal({ + sinon.assert.match(payload.imp[0].banner, { format: [ { w: 300, h: 250 }, { w: 160, h: 600 } @@ -659,44 +639,6 @@ describe('Improve Digital Adapter Tests', function () { }); }); - it('should set GPID and Instl Signal', function () { - const bidRequest = Object.assign({ - ortb2Imp: { - instl: true, - ext: { - gpid: '/123/ID-FORMAT', - data: { - pbadslot: '/123/ID-FORMAT-PBADSLOT', - adserver: { - adslot: '/123/ID-FORMAT-ADSERVER-PB-ADSLOT', - } - } - }, - } - }, simpleBidRequest); - let request = spec.buildRequests([bidRequest], bidderRequest)[0]; - let payload = JSON.parse(request.data); - expect(payload.imp[0].ext.gpid).to.equal('/123/ID-FORMAT'); - expect(payload.imp[0].instl).to.equal(1); - - delete bidRequest.ortb2Imp.ext.gpid; - request = spec.buildRequests([bidRequest], bidderRequest)[0]; - payload = JSON.parse(request.data); - expect(payload.imp[0].ext.gpid).to.equal('/123/ID-FORMAT-PBADSLOT'); - - delete bidRequest.ortb2Imp.ext.data.pbadslot; - request = spec.buildRequests([bidRequest], bidderRequest)[0]; - payload = JSON.parse(request.data); - expect(payload.imp[0].ext.gpid).to.equal('/123/ID-FORMAT-ADSERVER-PB-ADSLOT'); - - delete bidRequest.ortb2Imp.ext.data.adserver; - delete bidRequest.ortb2Imp.instl; - request = spec.buildRequests([bidRequest], bidderRequest)[0]; - payload = JSON.parse(request.data); - expect(payload.imp[0].ext.gpid).to.not.exist; - expect(payload.imp[0].instl).to.not.exist; - }); - it('should not set site when app is defined in FPD', function () { const ortb2 = {app: {content: 'XYZ'}}; let request = spec.buildRequests([simpleBidRequest], {...bidderRequest, ortb2})[0]; @@ -747,6 +689,7 @@ describe('Improve Digital Adapter Tests', function () { it('should set site when app not available', function () { getConfigStub = sinon.stub(config, 'getConfig'); getConfigStub.withArgs('app').returns(undefined); + getConfigStub.withArgs('site').returns({}); let request = spec.buildRequests([simpleBidRequest], bidderRequest)[0]; let payload = JSON.parse(request.data); expect(payload.site).does.exist; @@ -829,7 +772,6 @@ describe('Improve Digital Adapter Tests', function () { 'agency_id': '0' } }, - 'exp': 120, 'crid': '510265', 'price': 1.9200543539802946, 'id': '35adfe19-d6e9-46b9-9f7d-20da7026b965', @@ -872,7 +814,6 @@ describe('Improve Digital Adapter Tests', function () { 'agency_id': '0' } }, - 'exp': 120, 'crid': '510265', 'price': 1.9200543539802946, 'id': '35adfe19-d6e9-46b9-9f7d-20da7026b965', @@ -892,7 +833,6 @@ describe('Improve Digital Adapter Tests', function () { 'agency_id': '0' } }, - 'exp': 120, 'crid': '479163', 'price': 1.9200543539802946, 'id': '83c8d524-0955-4d0c-b558-4c9f3600e09b', @@ -937,10 +877,9 @@ describe('Improve Digital Adapter Tests', function () { } }, 'crid': '544456', - 'exp': 120, 'id': '52098fad-20c1-476b-a4fa-41e275e5a4a5', 'price': 1.8600000000000003, - 'adm': '{"ver":"1.1","imptrackers":["https://secure.adnxs.com/imptr?id=52311&t=2","https://euw-ice.360yield.com/imp_pixel?ic=hcUBlCANx1FabHBf6FR2gC7UO4xEyXahdZAn0-B5qL-bb3A74BJ1smyWIyW7IWcC0SOjSXzVpevTHXxTqJ.sf.Qhahyy6tSo.0j1QWfXlH8sM4-8vKWjMjw-x.IrJJNlwkQ0s1CdwcwTefcLXm5l2E-W19VhACuV7f3mgrZMNjiSw.SjJAfyPC3SIyAMRjYfj53UmjriQ46T7lhmkqxK8wHmksYCdbZc3PZESk8NWl28sxdjNvnYYCFMcJbeav.LOLabyTXfwy-1cEPbQs.IKMRZIKaqccTDPV3wOtzbNv0jQzatd3Nnv-PGFQcjQ-GW3i27W04Fws4kodpFSn-B6VwZAjzLzoyd5gBncyRnAyCplEbgHU5sZ1IyKHWjgCl3ZtRIK5vqrRD5D-xqgSnOi7-phG.CqZWDZ4bMDSfQg2ZnbvUTyGKcEl0WR59dW5izTMV4Fjizcrvr5T-t.zMbGwz.hGnmLIyhTqh.IcwW.GiDLVExlDlix5S1LXIWVsSyrQ=="],"assets":[{"id":1,"data":{"value":"ImproveDigital","type":1}},{"id":3,"data":{"value":"Test content.","type":2}},{"id":0,"title":{"text":"Sample Prebid Test Title"}}],"link":{"url":"https://euw-ice.360yield.com/click/hcUBlHOV7YhVse8RyBa0ajjyPa9Vt17e4g-1m3cRj3E67vq-RYux.SiUeAmBfNBcoOqkUc6A15AWmi4yFu5K-BdkaYjildyyk7fNLyR6hWr411kv4vrFwm5jrIBceuHS6K8oN69f.uCo8zGTdR2TbSlldwcpahQPlufZU.6VaMsu4IC53uEiUT5vb7kAw6TTlxuGBNq6zaGryiWEV2.N3YYJDTyYPh8tv-ZFyeFZFm0Gnjv.xWbC.70JcRUVU9UelQaPsTpTWYTXBhJt84YJUw1-GNtaLNVLSjjZbVoA2fsMti5p6OBmF.7u39on2OPgvseIkSmge7Pqg63pRqdP75hp.DAEk6OkcN1jGnwP2DSbvpaSbin5lVqjfO0B-wnQgfQTCUtM5v4JmkNweLhUf9Q-x.nPKLW5SccEk9ZFXzY2-1wpT3PWm8Tix3NRscLPZub9wHzL..pl6ip8cQ9hp16UjwT4H6RMAxL0R7bl-h2pAicGAzYmuO7ntRESKUoIWA==//http%3A%2F%2Fquantum-advertising.com%2Ffr%2F"},"jstracker":""}', + 'adm': "{\"ver\":\"1.1\",\"imptrackers\":[\"https://secure.adnxs.com/imptr?id=52311&t=2\",\"https://euw-ice.360yield.com/imp_pixel?ic=hcUBlCANx1FabHBf6FR2gC7UO4xEyXahdZAn0-B5qL-bb3A74BJ1smyWIyW7IWcC0SOjSXzVpevTHXxTqJ.sf.Qhahyy6tSo.0j1QWfXlH8sM4-8vKWjMjw-x.IrJJNlwkQ0s1CdwcwTefcLXm5l2E-W19VhACuV7f3mgrZMNjiSw.SjJAfyPC3SIyAMRjYfj53UmjriQ46T7lhmkqxK8wHmksYCdbZc3PZESk8NWl28sxdjNvnYYCFMcJbeav.LOLabyTXfwy-1cEPbQs.IKMRZIKaqccTDPV3wOtzbNv0jQzatd3Nnv-PGFQcjQ-GW3i27W04Fws4kodpFSn-B6VwZAjzLzoyd5gBncyRnAyCplEbgHU5sZ1IyKHWjgCl3ZtRIK5vqrRD5D-xqgSnOi7-phG.CqZWDZ4bMDSfQg2ZnbvUTyGKcEl0WR59dW5izTMV4Fjizcrvr5T-t.zMbGwz.hGnmLIyhTqh.IcwW.GiDLVExlDlix5S1LXIWVsSyrQ==\"],\"assets\":[{\"id\":1,\"data\":{\"value\":\"ImproveDigital\",\"type\":1}},{\"id\":3,\"data\":{\"value\":\"Test content.\",\"type\":2}},{\"id\":0,\"title\":{\"text\":\"Sample Prebid Test Title\"}}],\"link\":{\"url\":\"https://euw-ice.360yield.com/click/hcUBlHOV7YhVse8RyBa0ajjyPa9Vt17e4g-1m3cRj3E67vq-RYux.SiUeAmBfNBcoOqkUc6A15AWmi4yFu5K-BdkaYjildyyk7fNLyR6hWr411kv4vrFwm5jrIBceuHS6K8oN69f.uCo8zGTdR2TbSlldwcpahQPlufZU.6VaMsu4IC53uEiUT5vb7kAw6TTlxuGBNq6zaGryiWEV2.N3YYJDTyYPh8tv-ZFyeFZFm0Gnjv.xWbC.70JcRUVU9UelQaPsTpTWYTXBhJt84YJUw1-GNtaLNVLSjjZbVoA2fsMti5p6OBmF.7u39on2OPgvseIkSmge7Pqg63pRqdP75hp.DAEk6OkcN1jGnwP2DSbvpaSbin5lVqjfO0B-wnQgfQTCUtM5v4JmkNweLhUf9Q-x.nPKLW5SccEk9ZFXzY2-1wpT3PWm8Tix3NRscLPZub9wHzL..pl6ip8cQ9hp16UjwT4H6RMAxL0R7bl-h2pAicGAzYmuO7ntRESKUoIWA==//http%3A%2F%2Fquantum-advertising.com%2Ffr%2F\"},\"jstracker\":\"\"}", 'impid': '33e9500b21129f', 'cid': '196108' } @@ -968,7 +907,6 @@ describe('Improve Digital Adapter Tests', function () { 'agency_id': '0' } }, - 'exp': 120, 'crid': '484367', 'price': 9.600271769901472, 'id': 'b131fd7b-5759-4b72-800e-60e69291e7d9', @@ -1012,7 +950,6 @@ describe('Improve Digital Adapter Tests', function () { 'agency_id': '0' } }, - 'exp': 120, 'crid': '544063', 'price': 1.9199364935359489, 'id': '1fcf4dd8-a783-48ed-b59c-8fc8eeccb024', @@ -1041,20 +978,17 @@ describe('Improve Digital Adapter Tests', function () { width: 728, height: 90, ttl: 300, - ad: '  ', + ad: '\x3Cscript>window.__razr_config = {"prebid":{"bidRequest":{"bidder":"improvedigital","params":{"placementId":1053688,"keyValues":{"testKey":["testValue"]},"bidFloor":0.05,"bidFloorCur":"eUR","size":{"w":800,"h":600}},"adUnitCode":"div-gpt-ad-1499748733608-0","transactionId":"f183e871-fbed-45f0-a427-c8a63c4c01eb","bidId":"33e9500b21129f","bidderRequestId":"2772c1e566670b","auctionId":"192721e36a0239","mediaTypes":{"banner":{"sizes":[[300,250],[160,600]]}},"sizes":[[300,250],[160,600]]},"bid":{"mediaType":"banner","ad":"\\"\\"","requestId":"33e9500b21129f","seatBidId":"35adfe19-d6e9-46b9-9f7d-20da7026b965","cpm":1.9200543539802946,"currency":"EUR","width":728,"height":90,"creative_id":"510265","creativeId":"510265","ttl":300,"meta":{},"dealId":320896,"netRevenue":false}}};\x3C/script>  ', creativeId: '510265', dealId: 320896, netRevenue: false, mediaType: BANNER, - meta: { - advertiserDomains: [] - } } ]; const multiFormatExpectedBid = [ Object.assign({}, expectedBid[0], { - ad: '  ' + ad: '\x3Cscript>window.__razr_config = {"prebid":{"bidRequest":{"bidder":"improvedigital","params":{"placementId":1053688},"adUnitCode":"div-gpt-ad-1499748733608-0","transactionId":"f183e871-fbed-45f0-a427-c8a63c4c01eb","bidId":"33e9500b21129f","bidderRequestId":"2772c1e566670b","auctionId":"192721e36a0239","mediaTypes":{"banner":{"sizes":[[300,250],[160,600]]},"native":{},"video":{"context":"outstream","playerSize":[640,480]}},"sizes":[[300,250],[160,600]],"nativeParams":{"body":{"required":true}}},"bid":{"mediaType":"banner","ad":"\\"\\"","requestId":"33e9500b21129f","seatBidId":"35adfe19-d6e9-46b9-9f7d-20da7026b965","cpm":1.9200543539802946,"currency":"EUR","width":728,"height":90,"creative_id":"510265","creativeId":"510265","ttl":300,"meta":{},"dealId":320896,"netRevenue":false}}};\x3C/script>  ', }) ]; @@ -1067,14 +1001,11 @@ describe('Improve Digital Adapter Tests', function () { width: 300, height: 250, ttl: 300, - ad: '  ', + ad: '\x3Cscript>window.__razr_config = {"prebid":{"bidRequest":{"bidder":"improvedigital","params":{"placementId":1053688,"keyValues":{"testKey":["testValue"]},"bidFloor":0.05,"bidFloorCur":"eUR","size":{"w":800,"h":600}},"adUnitCode":"div-gpt-ad-1499748733608-0","transactionId":"f183e871-fbed-45f0-a427-c8a63c4c01eb","bidId":"33e9500b21129f","bidderRequestId":"2772c1e566670b","auctionId":"192721e36a0239","mediaTypes":{"banner":{"sizes":[[300,250],[160,600]]}},"sizes":[[300,250],[160,600]]},"bid":{"mediaType":"banner","ad":"\\"\\"","requestId":"33e9500b21129f","seatBidId":"83c8d524-0955-4d0c-b558-4c9f3600e09b","cpm":1.9200543539802946,"currency":"EUR","width":300,"height":250,"creative_id":"479163","creativeId":"479163","ttl":300,"meta":{},"dealId":320896,"netRevenue":false}}};\x3C/script>  ', creativeId: '479163', dealId: 320896, netRevenue: false, mediaType: BANNER, - meta: { - advertiserDomains: [] - } } ]; @@ -1100,93 +1031,106 @@ describe('Improve Digital Adapter Tests', function () { content: expectedBidOutstreamVideo[0].vastXml }; + function makeRequest(bidderRequest) { + return { + ortbRequest: CONVERTER.toORTB({bidderRequest}) + } + } + + function expectMatch(actual, expected) { + sinon.assert.match(actual, expected.map(i => sinon.match(i))); + } + it('should return a well-formed display bid', function () { - const bids = spec.interpretResponse(serverResponse, {bidderRequest}); - expect(bids).to.deep.equal(expectedBid); + const bids = spec.interpretResponse(serverResponse, makeRequest(bidderRequest)); + expectMatch(bids, 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(multiFormatExpectedBid); + const bids = spec.interpretResponse(serverResponse, makeRequest(multiFormatBidderRequest)); + + expectMatch(bids, multiFormatExpectedBid); }); it('should return two bids', function () { - const bids = spec.interpretResponse(serverResponseTwoBids, {bidderRequest}); - expect(bids).to.deep.equal(expectedTwoBids); + const bids = spec.interpretResponse(serverResponseTwoBids, makeRequest(bidderRequest)); + expectMatch(bids, expectedTwoBids); }); it('should set dealId correctly', function () { + const request = makeRequest(bidderRequest); const response = deepClone(serverResponse); let bids; delete response.body.seatbid[0].bid[0].ext.improvedigital.line_item_id; response.body.seatbid[0].bid[0].ext.improvedigital.buying_type = 'deal_id'; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids[0].dealId).to.not.exist; response.body.seatbid[0].bid[0].ext.improvedigital.line_item_id = 268515; delete response.body.seatbid[0].bid[0].ext.improvedigital.buying_type; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids[0].dealId).to.not.exist; response.body.seatbid[0].bid[0].ext.improvedigital.line_item_id = 268515; response.body.seatbid[0].bid[0].ext.improvedigital.buying_type = 'rtb'; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids[0].dealId).to.not.exist; response.body.seatbid[0].bid[0].ext.improvedigital.line_item_id = 268515; response.body.seatbid[0].bid[0].ext.improvedigital.buying_type = 'classic'; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids[0].dealId).to.equal(268515); response.body.seatbid[0].bid[0].ext.improvedigital.line_item_id = 268515; response.body.seatbid[0].bid[0].ext.improvedigital.buying_type = 'deal_id'; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids[0].dealId).to.equal(268515); }); it('should set currency', function () { const response = deepClone(serverResponse); - response.body.cur = 'eur'; - const bids = spec.interpretResponse(response, {bidderRequest}); + response.body.cur = 'EUR'; + const bids = spec.interpretResponse(response, makeRequest(bidderRequest)); expect(bids[0].currency).to.equal('EUR'); }); it('should return empty array for bad response or no price', function () { + const request = makeRequest(bidderRequest); let response = deepClone(serverResponse); let bids; // Price missing or 0 response.body.seatbid[0].bid[0].price = 0; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids).to.deep.equal([]); delete response.body.seatbid[0].bid[0]; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids).to.deep.equal([]); response.body.seatbid[0].bid[0] = []; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids).to.deep.equal([]); // errorCode present response = deepClone(serverResponse); response.body.seatbid[0].bid[0].errorCode = undefined; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids).to.deep.equal([]); // adm and native missing response = deepClone(serverResponse); delete response.body.seatbid[0].bid[0].adm; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids).to.deep.equal([]); response.body.seatbid[0].bid[0].adm = null; - bids = spec.interpretResponse(response, {bidderRequest}); + bids = spec.interpretResponse(response, request); expect(bids).to.deep.equal([]); }); it('should set netRevenue', function () { const response = deepClone(serverResponse); response.body.seatbid[0].bid[0].ext.improvedigital.is_net = true; - const bids = spec.interpretResponse(response, {bidderRequest}); + const bids = spec.interpretResponse(response, makeRequest(bidderRequest)); expect(bids[0].netRevenue).to.equal(true); }); @@ -1194,59 +1138,53 @@ describe('Improve Digital Adapter Tests', function () { const adomain = ['domain.com']; const response = deepClone(serverResponse); response.body.seatbid[0].bid[0].adomain = adomain; - const bids = spec.interpretResponse(response, {bidderRequest}); + const bids = spec.interpretResponse(response, makeRequest(bidderRequest)); expect(bids[0].meta.advertiserDomains).to.equal(adomain); }); // // Native ads - it('should return a well-formed native ad bid', function () { - const bids = spec.interpretResponse(serverResponseNative, {bidderRequest: nativeBidderRequest}); - // Verify Native Response - expect(bids[0].native).to.exist; - const nativeBid = bids[0].native; - const nativeResp = JSON.parse(serverResponseNative.body.seatbid[0].bid[0].adm); - // Verify Native Response - expect(nativeBid.clickUrl).to.exist.and.equal(nativeResp.link.url); - expect(nativeBid.impressionTrackers).to.exist.and.deep.equal(nativeResp.imptrackers); - expect(nativeBid.javascriptTrackers).to.exist.and.deep.equal(nativeResp.jstracker); - - // Verify Assets - expect(nativeBid.title).to.exist.and.equal('Sample Prebid Test Title'); - expect(nativeBid.sponsoredBy).to.exist.and.equal('ImproveDigital'); - expect(nativeBid.body).to.exist.and.equal('Test content.'); - }); + if (FEATURES.NATIVE) { + it('should return a well-formed native ad bid', function () { + const reqBids = updateNativeParams(nativeBidderRequest.bids); + const request = makeRequest({ + ...nativeBidderRequest, + reqBids + }) + const bids = spec.interpretResponse(serverResponseNative, request); + expect(bids[0].native.ortb).to.eql(JSON.parse(serverResponseNative.body.seatbid[0].bid[0].adm)) + }); - it('should return a well-formed native bid for multi-format ad unit', function () { - const bids = spec.interpretResponse(serverResponseNative, {bidderRequest: multiFormatBidderRequest}); - expect(bids[0].mediaType).to.equal(NATIVE); - }); + it('should return a well-formed native bid for multi-format ad unit', function () { + const bids = spec.interpretResponse(serverResponseNative, makeRequest(multiFormatBidderRequest)); + expect(bids[0].mediaType).to.equal(NATIVE); + }); + } // Video it('should return a well-formed instream video bid', function () { - const bids = spec.interpretResponse(serverResponseVideo, {bidderRequest: instreamBidderRequest}); - expect(bids).to.deep.equal(expectedBidInstreamVideo); + const bids = spec.interpretResponse(serverResponseVideo, makeRequest(instreamBidderRequest)); + expectMatch(bids, expectedBidInstreamVideo); }); it('should return a well-formed outstream video bid', function () { - const bids = spec.interpretResponse(serverResponseVideo, {bidderRequest: outstreamBidderRequest}); + const bids = spec.interpretResponse(serverResponseVideo, makeRequest(outstreamBidderRequest)); expect(bids[0].renderer).to.exist; - delete (bids[0].renderer); - expect(bids).to.deep.equal(expectedBidOutstreamVideo); + expectMatch(bids, expectedBidOutstreamVideo); }); it('should return a well-formed outstream video bid for multi-format ad unit', function () { + const request = makeRequest(multiFormatBidderRequest); const videoResponse = deepClone(serverResponseVideo); - let bids = spec.interpretResponse(videoResponse, {bidderRequest: multiFormatBidderRequest}); + let bids = spec.interpretResponse(videoResponse, request); expect(bids[0].renderer).to.exist; - delete (bids[0].renderer); - expect(bids).to.deep.equal(expectedBidOutstreamVideo); + expectMatch(bids, expectedBidOutstreamVideo); videoResponse.body.seatbid[0].bid[0].adm = ' { + let bids; + beforeEach(function () { + bidRequestConfigs = deepClone(SAMPLE_BID_REQUESTS); + bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0]; + bidResponse = deepClone(SAMPLE_BID_RESPONSE); + bidResponse.seatbid[0].bid.push(deepClone(bidResponse.seatbid[0].bid[0])); + bidResponse.seatbid[0].bid[1].ext.paf.content_id = 'second_paf' + + bids = spec.interpretResponse({body: bidResponse}, bidRequest); + }); + + it('should not confuse paf content_id', () => { + expect(bids.map(b => b.meta.paf.content_id)).to.eql(['paf_content_id', 'second_paf']); + }); + }) + context('when the response is a banner', function() { beforeEach(function () { bidRequestConfigs = [{ diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 4b9efa72e61..f5f77e61056 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1,5 +1,10 @@ import { expect } from 'chai'; -import { PrebidServer as Adapter, resetSyncedStatus, resetWurlMap } from 'modules/prebidServerBidAdapter/index.js'; +import { + PrebidServer as Adapter, + resetSyncedStatus, + resetWurlMap, + s2sDefaultConfig +} from 'modules/prebidServerBidAdapter/index.js'; import adapterManager from 'src/adapterManager.js'; import * as utils from 'src/utils.js'; import { ajax } from 'src/ajax.js'; @@ -13,6 +18,14 @@ import 'modules/appnexusBidAdapter.js' // appnexus alias test import 'modules/rubiconBidAdapter.js' // rubicon alias test import 'src/prebid.js' // $$PREBID_GLOBAL$$.aliasBidder test import 'modules/currency.js' // adServerCurrency test +// also load modules that register ORTB processors +import 'modules/currency.js'; +import 'modules/userId/index.js'; +import 'modules/multibid/index.js'; +import 'modules/priceFloors.js'; +import 'modules/consentManagement.js'; +import 'modules/consentManagementUsp.js'; +import 'modules/schain.js'; import { hook } from '../../../src/hook.js'; import { decorateAdUnitsWithNativeParams } from '../../../src/native.js'; import { auctionManager } from '../../../src/auctionManager.js'; @@ -552,6 +565,7 @@ describe('S2S Adapter', function () { beforeEach(function () { config.resetConfig(); + config.setConfig({floors: {enabled: false}}); adapter = new Adapter(); BID_REQUESTS = [ { @@ -620,6 +634,14 @@ describe('S2S Adapter', function () { expect(requestBid.source.tid).to.equal(BID_REQUESTS[0].auctionId); }); + it('should set tmax to s2sConfig.timeout', () => { + const cfg = {...CONFIG, timeout: 123}; + config.setConfig({s2sConfig: cfg}); + adapter.callBids({...REQUEST, s2sConfig: cfg}, BID_REQUESTS, addBidResponse, done, ajax); + const req = JSON.parse(server.requests[0].requestBody); + expect(req.tmax).to.eql(123); + }) + it('should block request if config did not define p1Consent URL in endpoint object config', function () { let badConfig = utils.deepClone(CONFIG); badConfig.endpoint = { noP1Consent: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' }; @@ -957,11 +979,11 @@ describe('S2S Adapter', function () { config.setConfig(_config); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); - expect(requestBid.device).to.deep.equal({ + sinon.assert.match(requestBid.device, { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC', w: window.innerWidth, h: window.innerHeight - }); + }) expect(requestBid.app).to.deep.equal({ bundle: 'com.test.app', publisher: { 'id': '1' } @@ -984,11 +1006,11 @@ describe('S2S Adapter', function () { config.setConfig(_config); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); - expect(requestBid.device).to.deep.equal({ + sinon.assert.match(requestBid.device, { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC', w: window.innerWidth, h: window.innerHeight - }); + }) expect(requestBid.app).to.deep.equal({ bundle: 'com.test.app', publisher: { 'id': '1' } @@ -1029,6 +1051,8 @@ describe('S2S Adapter', function () { expect( BID_REQUESTS[0].bids[0].getFloor.calledWith({ currency: 'USD', + mediaType: '*', + size: '*' }) ).to.be.true; @@ -1058,6 +1082,8 @@ describe('S2S Adapter', function () { expect( BID_REQUESTS[0].bids[0].getFloor.calledWith({ currency: 'USD', + mediaType: '*', + size: '*' }) ).to.be.true; @@ -1085,6 +1111,8 @@ describe('S2S Adapter', function () { expect( BID_REQUESTS[0].bids[0].getFloor.calledWith({ currency: 'JPY', + mediaType: '*', + size: '*' }) ).to.be.true; }); @@ -1250,9 +1278,9 @@ describe('S2S Adapter', function () { conversionFn: null }, 'is not working': { - expectDesc: 'first', - expectedFloor: 2, - expectedCur: '1', + expectDesc: 'absolute minimum', + expectedFloor: 1, + expectedCur: '10', conversionFn: () => { throw new Error(); } @@ -1291,6 +1319,47 @@ describe('S2S Adapter', function () { if (FEATURES.NATIVE) { describe('native requests', function () { + const ORTB_NATIVE_REQ = { + 'ver': '1.2', + 'assets': [ + { + 'required': 1, + 'id': 0, + 'title': { + 'len': 800 + } + }, + { + 'required': 1, + 'id': 1, + 'img': { + 'type': 3, + 'w': 989, + 'h': 742 + } + }, + { + 'required': 1, + 'id': 2, + 'img': { + 'type': 1, + 'wmin': 10, + 'hmin': 10, + 'ext': { + 'aspectratios': ['1:1'] + } + } + }, + { + 'required': 1, + 'id': 3, + 'data': { + 'type': 1 + } + } + ] + }; + it('adds device.w and device.h even if the config lacks a device object', function () { const _config = { s2sConfig: CONFIG, @@ -1300,14 +1369,15 @@ describe('S2S Adapter', function () { config.setConfig(_config); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); - expect(requestBid.device).to.deep.equal({ + sinon.assert.match(requestBid.device, { w: window.innerWidth, h: window.innerHeight - }); + }) expect(requestBid.app).to.deep.equal({ bundle: 'com.test.app', publisher: { 'id': '1' } }); + expect(requestBid.imp[0].native.ver).to.equal('1.2'); }); it('adds native request for OpenRTB', function () { @@ -1316,54 +1386,17 @@ describe('S2S Adapter', function () { }; config.setConfig(_config); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids({...REQUEST, s2sConfig: Object.assign({}, CONFIG, s2sDefaultConfig)}, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); const ortbReq = JSON.parse(requestBid.imp[0].native.request); expect(ortbReq).to.deep.equal({ - 'ver': '1.2', + ...ORTB_NATIVE_REQ, 'context': 1, 'plcmttype': 1, 'eventtrackers': [{ event: 1, methods: [1] }], - 'assets': [ - { - 'required': 1, - 'id': 0, - 'title': { - 'len': 800 - } - }, - { - 'required': 1, - 'id': 1, - 'img': { - 'type': 3, - 'w': 989, - 'h': 742 - } - }, - { - 'required': 1, - 'id': 2, - 'img': { - 'type': 1, - 'wmin': 10, - 'hmin': 10, - 'ext': { - 'aspectratios': ['1:1'] - } - } - }, - { - 'required': 1, - 'id': 3, - 'data': { - 'type': 1 - } - } - ] }); expect(requestBid.imp[0].native.ver).to.equal('1.2'); }); @@ -1388,6 +1421,29 @@ describe('S2S Adapter', function () { expect(requestBid.imp[0].native.ver).to.equal('1.2'); }); + it('can override default values for imp.native.request with s2sConfig.ortbNative', () => { + const cfg = { + ...CONFIG, + ortbNative: { + eventtrackers: [ + {event: 1, methods: [1, 2]} + ] + } + } + config.setConfig({ + s2sConfig: cfg + }); + adapter.callBids({...REQUEST, s2sConfig: cfg}, BID_REQUESTS, addBidResponse, done, ajax); + const requestBid = JSON.parse(server.requests[0].requestBody); + const ortbReq = JSON.parse(requestBid.imp[0].native.request); + expect(ortbReq).to.eql({ + ...ORTB_NATIVE_REQ, + eventtrackers: [ + {event: 1, methods: [1, 2]} + ] + }) + }) + it('should not include ext.aspectratios if adunit\'s aspect_ratios do not define radio_width and ratio_height', () => { const req = deepClone(REQUEST); req.ad_units[0].mediaTypes.native.icon.aspect_ratios[0] = {'min_width': 1, 'min_height': 2}; @@ -1444,13 +1500,14 @@ describe('S2S Adapter', function () { const aliasBidder = { bidder: 'beintoo', + bid_id: REQUEST.ad_units[0].bids[0].bid_id, params: { placementId: '123456' } }; const request = utils.deepClone(REQUEST); request.ad_units[0].bids = [aliasBidder]; - adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(request, [{...BID_REQUESTS[0], bidderCode: 'beintoo'}], addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.ext).to.haveOwnProperty('prebid'); @@ -1472,6 +1529,7 @@ describe('S2S Adapter', function () { config.setConfig({ s2sConfig: adjustedConfig }); const aliasBidder = { + ...REQUEST.ad_units[0].bids[0], bidder: 'bidderD', params: { unit: '10433394', @@ -1484,7 +1542,7 @@ describe('S2S Adapter', function () { request.ad_units[0].bids = [aliasBidder]; request.s2sConfig = adjustedConfig; - adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(request, [{...BID_REQUESTS[0], bidderCode: aliasBidder.bidder}], addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.ext.prebid.aliases).to.deep.equal({ bidderD: 'mockBidder' }); @@ -1496,6 +1554,7 @@ describe('S2S Adapter', function () { const alias = 'foobar'; const aliasBidder = { bidder: alias, + bid_id: REQUEST.ad_units[0].bids[0].bid_id, params: { placementId: '123456' } }; @@ -1504,7 +1563,7 @@ describe('S2S Adapter', function () { // TODO: stub this $$PREBID_GLOBAL$$.aliasBidder('appnexus', alias); - adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(request, [{...BID_REQUESTS[0], bidderCode: 'foobar'}], addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.ext).to.haveOwnProperty('prebid'); @@ -1536,13 +1595,14 @@ describe('S2S Adapter', function () { }) const aliasBidder = { bidder: 'bidderCodeForTestSkipBPSAlias_Alias', + bid_id: REQUEST.ad_units[0].bids[0].bid_id, params: { aid: 123 } }; const request = utils.deepClone(REQUEST); request.ad_units[0].bids = [aliasBidder]; - adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(request, [{...BID_REQUESTS[0], bidderCode: aliasBidder.bidder}], addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); @@ -1572,6 +1632,7 @@ describe('S2S Adapter', function () { const alias = 'foobar_1'; const aliasBidder = { bidder: alias, + bid_id: REQUEST.ad_units[0].bids[0].bid_id, params: { aid: 1234567 } }; @@ -1580,7 +1641,7 @@ describe('S2S Adapter', function () { // TODO: stub this $$PREBID_GLOBAL$$.aliasBidder('appnexus', alias, { skipPbsAliasing: true }); - adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(request, [{...BID_REQUESTS[0], bidderCode: aliasBidder.bidder}], addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); @@ -1607,14 +1668,15 @@ describe('S2S Adapter', function () { }); config.setConfig({ s2sConfig: s2sConfig }); - const myRequest = utils.deepClone(REQUEST); - myRequest.ad_units[0].bids[0].params.usePaymentRule = true; - myRequest.ad_units[0].bids[0].params.keywords = { - foo: ['bar', 'baz'], - fizz: ['buzz'] - }; + Object.assign(BID_REQUESTS[0].bids[0].params, { + usePaymentRule: true, + keywords: { + foo: ['bar', 'baz'], + fizz: ['buzz'] + } + }) - adapter.callBids(myRequest, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); const requestParams = requestBid.imp[0].ext.prebid.bidder; @@ -1812,18 +1874,6 @@ describe('S2S Adapter', function () { 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 () { - config.setConfig({ - currency: { adServerCurrency: ['USD', 'GB', 'UK', 'AU'] }, - }); - - const bidRequests = utils.deepClone(BID_REQUESTS); - adapter.callBids(REQUEST, bidRequests, addBidResponse, done, ajax); - - const parsedRequestBody = JSON.parse(server.requests[0].requestBody); - expect(parsedRequestBody.cur).to.deep.equal(['USD']); - }); - it('when config \'currency.adServerCurrency\' value is a string: ORTB has property \'cur\' value set to a single item array', function () { config.setConfig({ currency: { adServerCurrency: 'NZ' }, @@ -2157,29 +2207,22 @@ describe('S2S Adapter', function () { ]); }); - it('passes schain object in request', function () { - const bidRequests = utils.deepClone(BID_REQUESTS); - const schainObject = { - 'ver': '1.0', - 'complete': 1, - 'nodes': [ - { - 'asi': 'indirectseller.com', - 'sid': '00001', - 'hp': 1 - }, + it('should "promote" the most reused bidder schain to source.ext.schain', () => { + const bidderReqs = [ + {...deepClone(BID_REQUESTS[0]), bidderCode: 'A'}, + {...deepClone(BID_REQUESTS[0]), bidderCode: 'B'}, + {...deepClone(BID_REQUESTS[0]), bidderCode: 'C'} + ]; + const chain1 = {chain: 1}; + const chain2 = {chain: 2}; - { - 'asi': 'indirectseller-2.com', - 'sid': '00002', - 'hp': 2 - } - ] - }; - bidRequests[0].bids[0].schain = schainObject; - adapter.callBids(REQUEST, bidRequests, addBidResponse, done, ajax); - const parsedRequestBody = JSON.parse(server.requests[0].requestBody); - expect(parsedRequestBody.source.ext.schain).to.deep.equal(schainObject); + bidderReqs[0].bids[0].schain = chain1; + bidderReqs[1].bids[0].schain = chain2; + bidderReqs[2].bids[0].schain = chain2; + + adapter.callBids(REQUEST, bidderReqs, addBidResponse, done, ajax); + const req = JSON.parse(server.requests[0].requestBody); + expect(req.source.ext.schain).to.eql(chain2); }); it('passes multibid array in request', function () { @@ -2842,43 +2885,6 @@ describe('S2S Adapter', function () { 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: { - p1Consent: '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', - } - }); - - const s2sVidRequest = utils.deepClone(VIDEO_REQUEST); - s2sVidRequest.s2sConfig = s2sConfig; - - adapter.callBids(s2sVidRequest, 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: { @@ -3513,11 +3519,7 @@ describe('S2S Adapter', function () { expect(requestBid.ext.prebid.floors).to.be.undefined; - // should pass of floorData is object - bidRequest[0].bids[0].floorData = { - skipped: false, - location: 'fetch', - } + config.setConfig({floors: {}}); adapter.callBids(REQUEST, bidRequest, addBidResponse, done, ajax); requestBid = JSON.parse(server.requests[1].requestBody); diff --git a/test/spec/ortbConverter/banner_spec.js b/test/spec/ortbConverter/banner_spec.js new file mode 100644 index 00000000000..0f6686283a1 --- /dev/null +++ b/test/spec/ortbConverter/banner_spec.js @@ -0,0 +1,203 @@ +import {fillBannerImp, bannerResponseProcessor} from '../../../libraries/ortbConverter/processors/banner.js'; +import {BANNER, VIDEO} from '../../../src/mediaTypes.js'; +import {inIframe} from '../../../src/utils.js'; + +const topframe = inIframe() ? 0 : 1; + +describe('pbjs -> ortb banner conversion', () => { + [ + { + t: 'non-banner request', + request: { + mediaTypes: { + video: {} + } + }, + imp: {} + }, + { + t: 'banner with no sizes', + request: { + mediaTypes: { + banner: { + pos: 'pos', + } + } + }, + imp: { + banner: { + topframe, + pos: 'pos', + } + } + }, + { + t: 'single size banner', + request: { + mediaTypes: { + banner: { + sizes: [1, 2], + } + } + }, + imp: { + banner: { + format: [ + {w: 1, h: 2} + ], + topframe, + } + } + }, + { + t: 'multi size banner', + request: { + mediaTypes: { + banner: { + sizes: [[1, 2], [3, 4]] + } + } + }, + imp: { + banner: { + format: [ + {w: 1, h: 2}, + {w: 3, h: 4} + ], + topframe, + } + } + }, + { + t: 'banner with pos param', + request: { + mediaTypes: { + banner: { + sizes: [1, 2], + pos: 'pos' + } + } + }, + imp: { + banner: { + format: [ + {w: 1, h: 2} + ], + pos: 'pos', + topframe, + } + }, + }, + { + t: 'banner with pos 0', + request: { + mediaTypes: { + banner: { + sizes: [1, 2], + pos: 0 + } + } + }, + imp: { + banner: { + format: [ + {w: 1, h: 2} + ], + pos: 0, + topframe, + } + } + } + ].forEach(({t, request, imp}) => { + it(`can convert ${t}`, () => { + const actual = {}; + fillBannerImp(actual, request, {}); + expect(actual).to.eql(imp); + }); + }); + + it('should keep ortb2Imp.banner', () => { + const imp = { + banner: { + someParam: 'someValue' + } + }; + fillBannerImp(imp, {mediaTypes: {banner: {sizes: [1, 2]}}}, {}); + expect(imp.banner.someParam).to.eql('someValue'); + }); + + it('does nothing if context.mediaType is set but is not BANNER', () => { + const imp = {}; + fillBannerImp(imp, {mediaTypes: {banner: {sizes: [1, 2]}}}, {mediaType: VIDEO}); + expect(imp).to.eql({}); + }) +}); + +describe('ortb -> pbjs banner conversion', () => { + let createPixel, seatbid2Banner; + beforeEach(() => { + createPixel = sinon.stub().callsFake((url) => `${url}Pixel`); + seatbid2Banner = bannerResponseProcessor({createPixel}); + }); + + [ + { + t: 'non-banner request', + seatbid: { + adm: 'mockAdm', + nurl: 'mockNurl' + }, + response: { + mediaType: VIDEO + }, + expected: { + mediaType: VIDEO + } + }, + { + t: 'response with both adm and nurl', + seatbid: { + adm: 'mockAdm', + nurl: 'mockUrl' + }, + response: { + mediaType: BANNER, + }, + expected: { + mediaType: BANNER, + ad: 'mockAdmmockUrlPixel' + } + }, + { + t: 'response with just adm', + seatbid: { + adm: 'mockAdm' + }, + response: { + mediaType: BANNER, + }, + expected: { + mediaType: BANNER, + ad: 'mockAdm' + } + }, + { + t: 'response with just nurl', + seatbid: { + nurl: 'mockNurl' + }, + response: { + mediaType: BANNER + }, + expected: { + mediaType: BANNER, + adUrl: 'mockNurl' + } + } + ].forEach(({t, seatbid, response, expected}) => { + it(`can handle ${t}`, () => { + seatbid2Banner(response, seatbid, context); + expect(response).to.eql(expected) + }) + }); +}) diff --git a/test/spec/ortbConverter/composer_spec.js b/test/spec/ortbConverter/composer_spec.js new file mode 100644 index 00000000000..f342df38fde --- /dev/null +++ b/test/spec/ortbConverter/composer_spec.js @@ -0,0 +1,69 @@ +import {compose} from '../../../libraries/ortbConverter/lib/composer.js'; + +describe('compose', () => { + it('runs each component in order of priority', () => { + const order = []; + const components = { + first: { + fn: sinon.stub().callsFake(() => order.push(1)), + }, + second: { + fn: sinon.stub().callsFake(() => order.push(2)), + priority: 10 + }, + third: { + fn: sinon.stub().callsFake(() => order.push(3)), + priority: 5 + } + }; + compose(components)(); + expect(order).to.eql([2, 3, 1]); + }); + + it('passes parameters to each component', () => { + const components = { + first: { + fn: sinon.stub() + }, + second: { + fn: sinon.stub() + } + }; + compose(components)('one', 'two'); + Object.values(components).forEach(comp => { + sinon.assert.calledWith(comp.fn, 'one', 'two') + }) + }) + + it('respects overrides', () => { + const components = { + first: { + fn: sinon.stub() + }, + second: { + fn: sinon.stub() + } + }; + const overrides = { + second: sinon.stub() + } + compose(components, overrides)('one', 'two'); + sinon.assert.calledWith(overrides.second, components.second.fn, 'one', 'two') + }) + + it('disables components when override is false', () => { + const components = { + first: { + fn: sinon.stub(), + }, + second: { + fn: sinon.stub() + } + }; + const overrides = { + second: false + }; + compose(components, overrides)('one', 'two'); + sinon.assert.notCalled(components.second.fn); + }) +}); diff --git a/test/spec/ortbConverter/converter_spec.js b/test/spec/ortbConverter/converter_spec.js new file mode 100644 index 00000000000..e00b46e66da --- /dev/null +++ b/test/spec/ortbConverter/converter_spec.js @@ -0,0 +1,283 @@ +import {ortbConverter} from '../../../libraries/ortbConverter/converter.js'; +import {BID_RESPONSE, IMP, REQUEST, RESPONSE} from '../../../src/pbjsORTB.js'; + +describe('pbjs-ortb converter', () => { + const MOCK_BIDDER_REQUEST = { + id: 'bidderRequest', + bids: [ + { + id: 111 + }, + { + id: 112 + } + ] + } + + const MOCK_ORTB_RESPONSE = { + id: 'response', + seatbid: [ + { + seat: 'mockBidder1', + bid: [ + { + impid: 'imp0' + }, + { + impid: 'imp1' + } + ] + }, + { + seat: 'mockBidder2', + bid: [ + { + impid: 'imp1' + } + ] + } + ] + } + + let processors, reqCnt, impCnt; + + beforeEach(() => { + reqCnt = 0; + impCnt = 0; + processors = { + [REQUEST]: { + req: { + fn(ortbRequest, bidderRequest, context) { + ortbRequest.id = `req${reqCnt++}`; + if (context.ctx) { + ortbRequest.ctx = context.ctx; + } + } + } + }, + [IMP]: { + imp: { + fn(imp, bidRequest, context) { + imp.id = `imp${impCnt++}`; + imp.bidId = bidRequest.id; + if (context.ctx) { + imp.ctx = context.ctx; + } + if (context.reqContext?.ctx) { + imp.reqCtx = context.reqContext?.ctx; + } + } + } + }, + [BID_RESPONSE]: { + resp: { + fn(bidResponse, bid, context) { + bidResponse.impid = bid.impid; + bidResponse.bidId = context.imp.bidId; + if (context.ctx) { + bidResponse.ctx = context.ctx; + } + if (context.reqContext?.ctx) { + bidResponse.reqCtx = context.reqContext?.ctx; + } + } + } + }, + [RESPONSE]: { + resp: { + fn(response, ortbResponse, context) { + response.marker = true; + if (context.ctx) { + response.ctx = context.ctx; + } + } + } + } + } + }); + + function makeConverter(options = {}) { + options = Object.assign({ + processors: () => processors + }, options); + return ortbConverter(options); + } + + it('runs each processor', () => { + const cvt = makeConverter(); + const request = cvt.toORTB({bidderRequest: MOCK_BIDDER_REQUEST}); + expect(request).to.eql({ + id: 'req0', + imp: [ + {id: 'imp0', bidId: 111}, + {id: 'imp1', bidId: 112} + ] + }); + const response = cvt.fromORTB({request, response: MOCK_ORTB_RESPONSE}); + expect(response.bids).to.eql([{ + impid: 'imp0', + bidId: 111 + }, { + impid: 'imp1', + bidId: 112 + }, { + impid: 'imp1', + bidId: 112 + }]); + expect(response.marker).to.be.true; + }); + + it('fromORTB throws if request was not produced by the same converter', () => { + expect(() => { + makeConverter().fromORTB({ + request: { + imp: [ + { + id: 'imp0' + } + ] + }, + response: MOCK_ORTB_RESPONSE + }) + }).to.throw(); + }); + + it('gives precedence to the bidRequests argument over bidderRequest.bids', () => { + expect(makeConverter().toORTB({bidderRequest: MOCK_BIDDER_REQUEST, bidRequests: [MOCK_BIDDER_REQUEST.bids[0]]})).to.eql({ + id: 'req0', + imp: [ + { + id: 'imp0', + bidId: 111 + } + ] + }) + }); + + it('passes context to every processor', () => { + const cvt = makeConverter(); + const request = cvt.toORTB({bidderRequest: MOCK_BIDDER_REQUEST, context: {ctx: 'context'}}); + expect(request.ctx).to.equal('context'); + request.imp.forEach(imp => expect(imp.ctx).to.equal('context')); + const response = cvt.fromORTB({request, response: MOCK_ORTB_RESPONSE}); + expect(response.ctx).to.eql('context'); + response.bids.forEach(bidResponse => expect(bidResponse.ctx).to.equal('context')); + }); + + it('passes request context to imp and bidResponse processors', () => { + const cvt = makeConverter(); + const request = cvt.toORTB({bidderRequest: MOCK_BIDDER_REQUEST, context: {ctx: 'context'}}); + expect(request.imp[0].reqCtx).to.eql('context'); + const response = cvt.fromORTB({request, response: MOCK_ORTB_RESPONSE}); + expect(response.bids[0].reqCtx).to.eql('context'); + }); + + it('allows overriding of imp building with `imp`', () => { + const cvt = makeConverter({ + imp: function (buildImp, bidRequest, context) { + return Object.assign({ + extraArg: bidRequest.id, + extraCtx: context.ctx + }, buildImp(bidRequest, context)); + } + }); + const request = cvt.toORTB({bidderRequest: MOCK_BIDDER_REQUEST, context: {ctx: 'context'}}); + expect(request.imp.length).to.eql(2); + request.imp.forEach(imp => { + expect(imp.extraArg).to.eql(imp.bidId); + expect(imp.extraCtx).to.eql('context'); + }) + }); + + it('allows filtering imps with `imp`', () => { + const cvt = makeConverter({ + imp(buildImp, bidRequest, context) { + if (bidRequest.id === 112) { + return buildImp(bidRequest, context); + } + } + }); + expect(cvt.toORTB({bidderRequest: MOCK_BIDDER_REQUEST}).imp.length).to.eql(1); + }); + + it('does not include imps that have no id', () => { + const cvt = makeConverter({ + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + delete imp.id; + return imp; + } + }); + expect(cvt.toORTB({bidderRequest: MOCK_BIDDER_REQUEST}).imp.length).to.eql(0); + }) + + it('allows overriding of response building with bidResponse', () => { + const cvt = makeConverter({ + bidResponse(buildResponse, bid, context) { + return Object.assign({ + extraArg: context.bidRequest.id, + extraCtx: context.ctx + }, buildResponse(bid, context)); + } + }); + const response = cvt.fromORTB({ + response: MOCK_ORTB_RESPONSE, + request: cvt.toORTB({bidderRequest: MOCK_BIDDER_REQUEST, context: {ctx: 'context'}}) + }); + + expect(response.bids.length).to.equal(3); + response.bids.forEach(response => { + expect(response.extraArg).to.eql(response.bidId); + expect(response.extraCtx).to.eql('context'); + }); + }); + + it('allows filtering of responses with `bidResponse`', () => { + const cvt = makeConverter({ + bidResponse(buildBidResponse, bid, context) { + if (context.seatbid.seat === 'mockBidder1' && context.imp.id === 'imp0') { + return buildBidResponse(bid, context); + } + } + }); + expect(cvt.fromORTB({ + request: cvt.toORTB({bidderRequest: MOCK_BIDDER_REQUEST}), + response: MOCK_ORTB_RESPONSE + }).bids.length).to.equal(1); + }); + + it('allows overriding of request building with `request`', () => { + const cvt = makeConverter({ + request(buildRequest, imps, bidderRequest, context) { + return { + request: buildRequest(imps, bidderRequest, context), + extraArg: bidderRequest.id, + extraCtx: context.ctx + } + } + }); + const req = cvt.toORTB({bidderRequest: MOCK_BIDDER_REQUEST, context: {ctx: 'context'}}); + expect(req.extraArg).to.equal(MOCK_BIDDER_REQUEST.id); + expect(req.extraCtx).to.equal('context'); + expect(req.request.imp.length).to.equal(2); + }); + + it('allows overriding of response building with `response`', () => { + const cvt = makeConverter({ + response(buildResponse, bidResponses, ortbResponse, context) { + return { + response: buildResponse(bidResponses, ortbResponse, context), + extraArg: ortbResponse.id, + extraCtx: context.ctx + } + } + }); + const resp = cvt.fromORTB({ + request: cvt.toORTB({bidderRequest: MOCK_BIDDER_REQUEST, context: {ctx: 'context'}}), + response: MOCK_ORTB_RESPONSE, + }); + expect(resp.extraArg).to.equal(MOCK_ORTB_RESPONSE.id); + expect(resp.extraCtx).to.equal('context'); + expect(resp.response.bids.length).to.equal(3); + }) +}) diff --git a/test/spec/ortbConverter/currency_spec.js b/test/spec/ortbConverter/currency_spec.js new file mode 100644 index 00000000000..76f81223f27 --- /dev/null +++ b/test/spec/ortbConverter/currency_spec.js @@ -0,0 +1,40 @@ +import {config} from 'src/config.js'; +import {setOrtbCurrency} from '../../../modules/currency.js'; + +describe('pbjs -> ortb currency', () => { + before(() => { + config.resetConfig(); + }); + + afterEach(() => { + config.resetConfig(); + }); + + it('does not set cur by default', () => { + const req = {}; + setOrtbCurrency(req, {}, {}); + expect(req).to.eql({}); + }); + + it('sets currency based on config', () => { + config.setConfig({ + currency: { + adServerCurrency: 'EUR' + } + }); + const req = {}; + setOrtbCurrency(req, {}, {}); + expect(req.cur).to.eql(['EUR']); + }); + + it('sets currency based on context', () => { + config.setConfig({ + currency: { + adServerCurrency: 'EUR' + } + }); + const req = {}; + setOrtbCurrency(req, {}, {currency: 'JPY'}); + expect(req.cur).to.eql(['JPY']); + }) +}); diff --git a/test/spec/ortbConverter/default_processors_spec.js b/test/spec/ortbConverter/default_processors_spec.js new file mode 100644 index 00000000000..28a35390b86 --- /dev/null +++ b/test/spec/ortbConverter/default_processors_spec.js @@ -0,0 +1,61 @@ +import {setDevice, setSite} from '../../../libraries/ortbConverter/processors/default.js'; + +describe('setDevice', () => { + it('sets device.w, h, dnt, language, ua', () => { + const req = {}; + setDevice(req); + ['h', 'w', 'dnt', 'language', 'ua'].forEach(prop => expect(req.device[prop]).to.exist) + }); + + it('does not override FPD', () => { + const req = { + device: { + w: 'w', + h: 'h', + ext: {} + } + }; + setDevice(req); + sinon.assert.match(req.device, { + w: 'w', + h: 'h', + ext: {} + }) + }); +}); + +describe('setSite', () => { + const refererInfo = { + page: 'page.com', + ref: 'ref.com', + domain: 'domain.com' + }; + + it('sets site, domain, ref from refererInfo', () => { + const req = { + site: { + ext: {} + } + }; + setSite(req, {refererInfo}); + sinon.assert.match(req.site, refererInfo); + expect(req.site.ext).to.eql({}); + }); + + it('does not override FPD', () => { + const req = { + site: { + ref: 'other ref' + } + } + setSite(req, {refererInfo}); + expect(req.site.ref).to.eql('other ref'); + ['domain', 'page'].forEach(prop => expect(req.site[prop]).to.eql(refererInfo[prop])); + }); + + it('does not set null properties from refererInfo', () => { + const req = {}; + setSite(req, {refererInfo: {...refererInfo, ref: null}}); + expect(req.site.ref).to.not.exist; + }); +}); diff --git a/test/spec/ortbConverter/gdpr_spec.js b/test/spec/ortbConverter/gdpr_spec.js new file mode 100644 index 00000000000..9851d7603b4 --- /dev/null +++ b/test/spec/ortbConverter/gdpr_spec.js @@ -0,0 +1,38 @@ +import {setOrtbAdditionalConsent, setOrtbGdpr} from '../../../modules/consentManagement.js'; + +describe('pbjs - ortb gpdr', () => { + it('sets gdpr properties from bidderRequest', () => { + const req = {}; + setOrtbGdpr(req, {gdprConsent: {gdprApplies: true, consentString: 'consent'}}); + expect(req.regs.ext.gdpr).to.eql(1); + expect(req.user.ext.consent).to.eql('consent'); + }); + + it('does not set it if missing', () => { + const req = {}; + setOrtbGdpr(req, {}); + expect(req).to.eql({}); + }); + + it('sets user.ext.consent, but not regs.ext.gdpr, if gpdrApplies is not a boolean', () => { + const req = {}; + setOrtbGdpr(req, { + gdprConsent: {consentString: 'mock-consent'} + }); + expect(req).to.eql({ + user: { + ext: { + consent: 'mock-consent' + } + } + }) + }); +}); + +describe('pbjs -> ortb addtlConsent', () => { + it('sets ConsentedProvidersSettings', () => { + const req = {}; + setOrtbAdditionalConsent(req, {gdprConsent: {addtlConsent: 'tl'}}); + expect(req.user.ext.ConsentedProvidersSettings.consented_providers).to.eql('tl'); + }); +}) diff --git a/test/spec/ortbConverter/mediaTypes_spec.js b/test/spec/ortbConverter/mediaTypes_spec.js new file mode 100644 index 00000000000..4f4fd99fb75 --- /dev/null +++ b/test/spec/ortbConverter/mediaTypes_spec.js @@ -0,0 +1,67 @@ +import {ORTB_MTYPES, setResponseMediaType} from '../../../libraries/ortbConverter/processors/mediaType.js'; +import {BANNER} from '../../../src/mediaTypes.js'; +import {extPrebidMediaType} from '../../../libraries/pbsExtensions/processors/mediaType.js'; + +function testMtype(processor) { + describe('respects 2.6 mtype', () => { + Object.entries(ORTB_MTYPES).forEach(([mtype, pbtype]) => { + it(`${mtype} -> ${pbtype}`, () => { + const resp = {}; + processor(resp, { + mtype: parseInt(mtype, 10) + }, {}); + expect(resp.mediaType).to.eql(pbtype); + }); + }); + }); +} + +describe('ortb -> pbjs mediaType conversion', () => { + testMtype(setResponseMediaType); + it('throws if mtype is missing', () => { + expect(() => { + setResponseMediaType({}, {}); + }).to.throw(); + }); + + it('respects pre-set bidResponse.mediaType', () => { + const resp = {mediaType: 'video'}; + setResponseMediaType(resp, {mtype: 1}); + expect(resp.mediaType).to.eql('video'); + }); + + it('gives precedence to context.mediaType', () => { + const resp = {}; + setResponseMediaType(resp, {mtype: 1}, {mediaType: 'video'}); + expect(resp.mediaType).to.eql('video') + }) +}); + +describe('ortb -> pbjs mediaType conversion based on ext.prebid.type', () => { + testMtype(extPrebidMediaType); + describe('respects ext.prebid.type', () => { + Object.values(ORTB_MTYPES).forEach(mediaType => { + const response = {}; + extPrebidMediaType(response, { + ext: { + prebid: { + type: mediaType + } + } + }, {}); + expect(response.mediaType).to.eql(mediaType); + }); + }); + + it('defaults to banner', () => { + const response = {}; + extPrebidMediaType(response, {}, {}); + expect(response.mediaType).to.eql(BANNER); + }); + + it('gives precedence to context.mediaType', () => { + const response = {}; + extPrebidMediaType(response, {ext: {prebid: {type: 'banner'}}}, {mediaType: 'video'}); + expect(response.mediaType).to.eql('video'); + }) +}); diff --git a/test/spec/ortbConverter/mergeProcessors_spec.js b/test/spec/ortbConverter/mergeProcessors_spec.js new file mode 100644 index 00000000000..ba15de06031 --- /dev/null +++ b/test/spec/ortbConverter/mergeProcessors_spec.js @@ -0,0 +1,59 @@ +import {mergeProcessors} from '../../../libraries/ortbConverter/lib/mergeProcessors.js'; +import {BID_RESPONSE, IMP, REQUEST, RESPONSE} from '../../../src/pbjsORTB.js'; + +describe('mergeProcessors', () => { + it('can merge', () => { + const result = mergeProcessors({ + [REQUEST]: { + first: { + priority: 0, + fn: 'first' + } + }, + [RESPONSE]: { + second: { + priority: 1, + fn: 'second' + } + } + }, { + [REQUEST]: { + first: { + fn: 'overriden' + } + }, + [IMP]: { + third: { + fn: 'third' + } + } + }, { + [IMP]: { + third: { + priority: 3, + fn: 'overridden' + } + } + }); + expect(result).to.eql({ + [REQUEST]: { + first: { + fn: 'overriden' + } + }, + [IMP]: { + third: { + priority: 3, + fn: 'overridden' + }, + }, + [RESPONSE]: { + second: { + priority: 1, + fn: 'second' + } + }, + [BID_RESPONSE]: {} + }); + }); +}); diff --git a/test/spec/ortbConverter/multibid_spec.js b/test/spec/ortbConverter/multibid_spec.js new file mode 100644 index 00000000000..4886aaf6069 --- /dev/null +++ b/test/spec/ortbConverter/multibid_spec.js @@ -0,0 +1,35 @@ +import {config} from 'src/config.js'; +import {setOrtbExtPrebidMultibid} from '../../../modules/multibid/index.js'; + +describe('pbjs - ortb ext.prebid.multibid', () => { + before(() => { + config.resetConfig(); + }); + afterEach(() => { + config.resetConfig(); + }); + + it('sets ext.prebid.multibid according to config', () => { + config.setConfig({ + multibid: [ + { + bidder: 'A', + maxBids: 2 + }, + { + bidder: 'B', + maxBids: 3 + } + ] + }); + const req = {}; + setOrtbExtPrebidMultibid(req); + expect(req.ext.prebid.multibid).to.eql([{bidder: 'A', maxbids: 2}, {bidder: 'B', maxbids: 3}]); + }); + + it('does not set it if not configured', () => { + const req = {}; + setOrtbExtPrebidMultibid(req); + expect(req).to.eql({}); + }) +}); diff --git a/test/spec/ortbConverter/native_spec.js b/test/spec/ortbConverter/native_spec.js new file mode 100644 index 00000000000..56c733817cd --- /dev/null +++ b/test/spec/ortbConverter/native_spec.js @@ -0,0 +1,95 @@ +import {fillNativeImp, fillNativeResponse} from '../../../libraries/ortbConverter/processors/native.js'; +import {BANNER, NATIVE} from '../../../src/mediaTypes.js'; + +describe('pbjs -> ortb native requests', () => { + function toNative(bidRequest, context) { + const imp = {}; + fillNativeImp(imp, bidRequest, context); + return imp; + } + + it('should do nothing if request has no nativeOrtbRequest', () => { + expect(toNative({}, {})).to.eql({}); + }); + + it('should set imp.native according to nativeOrtbRequest', () => { + const nativeOrtbRequest = {ver: 'version', prop: 'value', assets: [{}]}; + const imp = toNative({nativeOrtbRequest}, {}); + expect(imp.native.ver).to.eql('version'); + expect(JSON.parse(imp.native.request)).to.eql(nativeOrtbRequest); + }); + + it('should do nothing if context.mediaType is set but is not NATIVE', () => { + expect(toNative({nativeOrtbRequest: {ver: 'version'}}, {mediaType: BANNER})).to.eql({}) + }); + + it('should merge context.nativeRequest', () => { + const nativeOrtbRequest = {ver: 'version', eventtrackers: [{tracker: 'req'}], assets: [{}]}; + const nativeDefaults = {eventtrackers: [{tracker: 'default'}], other: 'other'}; + const imp = toNative({nativeOrtbRequest}, {nativeRequest: nativeDefaults}); + expect(imp.native.ver).to.eql('version'); + expect(JSON.parse(imp.native.request)).to.eql({ + assets: [{}], + ver: 'version', + eventtrackers: [{tracker: 'req'}], + other: 'other' + }); + }); + + it('should keep ortb2Imp.native', () => { + const imp = { + native: { + something: 'orother' + } + } + fillNativeImp(imp, {nativeOrtbRequest: {ver: 'version'}}, {}); + expect(imp.native.something).to.eql('orother') + }); + + it('should do nothing if there are no assets', () => { + const imp = {}; + fillNativeImp(imp, {nativeOrtbRequest: {assets: []}}, {}); + expect(imp).to.eql({}); + }) +}); + +describe('ortb -> ortb native response', () => { + const MOCK_NATIVE_RESPONSE = { + property: 'value', + assets: [ + { + id: 0 + } + ] + } + Object.entries({ + 'serialized': JSON.stringify(MOCK_NATIVE_RESPONSE), + 'an object': MOCK_NATIVE_RESPONSE + }).forEach(([t, adm]) => { + describe(`when adm is ${t}`, () => { + let bid; + beforeEach(() => { + bid = {adm}; + }) + it('should set bidResponse.native', () => { + const bidResponse = { + mediaType: NATIVE + }; + fillNativeResponse(bidResponse, bid, {}); + expect(bidResponse.native).to.eql({ortb: MOCK_NATIVE_RESPONSE}); + }); + }); + it('should throw if response has no assets', () => { + expect(() => fillNativeResponse({mediaType: NATIVE}, {adm: {...MOCK_NATIVE_RESPONSE, assets: null}}, {})).to.throw; + }) + it('should do nothing if bidResponse.mediaType is not NATIVE', () => { + const bidResponse = { + mediaType: BANNER + }; + fillNativeResponse(bidResponse, {adm: MOCK_NATIVE_RESPONSE}, {}); + expect(bidResponse).to.eql({ + mediaType: BANNER + }) + }) + }) +}); diff --git a/test/spec/ortbConverter/pbjsORTB_spec.js b/test/spec/ortbConverter/pbjsORTB_spec.js new file mode 100644 index 00000000000..16aefec2b35 --- /dev/null +++ b/test/spec/ortbConverter/pbjsORTB_spec.js @@ -0,0 +1,67 @@ +import { + DEFAULT, + PBS, + PROCESSOR_TYPES, + processorRegistry, + REQUEST +} from '../../../src/pbjsORTB.js'; + +describe('pbjsORTB register / get processors', () => { + let registerOrtbProcessor, getProcessors; + beforeEach(() => { + ({registerOrtbProcessor, getProcessors} = processorRegistry()); + }) + PROCESSOR_TYPES.forEach(type => { + it(`can get and set ${type} processors`, () => { + const proc = function () {}; + registerOrtbProcessor({ + type, + name: 'test', + fn: proc + }); + expect(getProcessors(DEFAULT)).to.eql({ + [type]: { + test: { + priority: 0, + fn: proc + } + } + }); + }); + }); + + it('throws on wrong type', () => { + expect(() => registerOrtbProcessor({ + type: 'incorrect', + name: 'test', + fn: function () {} + })).to.throw(); + }); + + it('can set priority', () => { + const proc = function () {}; + registerOrtbProcessor({type: REQUEST, name: 'test', fn: proc, priority: 10}); + expect(getProcessors(DEFAULT)).to.eql({ + [REQUEST]: { + test: { + priority: 10, + fn: proc + } + } + }) + }); + + it('can assign processors to specific dialects', () => { + const proc = function () {}; + registerOrtbProcessor({type: REQUEST, name: 'test', fn: proc, dialects: [PBS]}); + expect(getProcessors(DEFAULT)).to.eql({}); + expect(getProcessors(PBS)).to.eql({ + [REQUEST]: { + test: { + priority: 0, + fn: proc + } + } + }) + }); +}); diff --git a/test/spec/ortbConverter/pbsExtensions/aliases_spec.js b/test/spec/ortbConverter/pbsExtensions/aliases_spec.js new file mode 100644 index 00000000000..712ceaa397c --- /dev/null +++ b/test/spec/ortbConverter/pbsExtensions/aliases_spec.js @@ -0,0 +1,57 @@ +import {setRequestExtPrebidAliases} from '../../../../libraries/pbsExtensions/processors/aliases.js'; + +describe('PBS - ortb ext.prebid.aliases', () => { + let aliasRegistry, bidderRegistry; + + function setAliases(bidderRequest) { + const req = {} + setRequestExtPrebidAliases(req, bidderRequest, {}, { + am: { + bidderRegistry, + aliasRegistry + } + }); + return req; + } + + beforeEach(() => { + aliasRegistry = {}; + bidderRegistry = {}; + }) + + describe('has no effect if', () => { + it('bidder is not an alias', () => { + expect(setAliases({bidderCode: 'not-an-alias'})).to.eql({}); + }); + + it('bidder sets skipPbsAliasing', () => { + aliasRegistry['alias'] = 'bidder'; + bidderRegistry['alias'] = { + getSpec() { + return { + skipPbsAliasing: true + } + } + }; + expect(setAliases({bidderCode: 'alias'})).to.eql({}); + }); + }); + + it('sets ext.prebid.aliases.BIDDER', () => { + aliasRegistry['alias'] = 'bidder'; + bidderRegistry['alias'] = { + getSpec() { + return {} + } + }; + expect(setAliases({bidderCode: 'alias'})).to.eql({ + ext: { + prebid: { + aliases: { + alias: 'bidder' + } + } + } + }) + }); +}) diff --git a/test/spec/ortbConverter/pbsExtensions/params_spec.js b/test/spec/ortbConverter/pbsExtensions/params_spec.js new file mode 100644 index 00000000000..73b92a0755d --- /dev/null +++ b/test/spec/ortbConverter/pbsExtensions/params_spec.js @@ -0,0 +1,96 @@ +import {setImpBidParams} from '../../../../libraries/pbsExtensions/processors/params.js'; + +describe('pbjs -> ortb bid params to imp[].ext.prebid.BIDDER', () => { + let bidderRegistry, index, adUnit; + beforeEach(() => { + bidderRegistry = {}; + adUnit = {code: 'mockAdUnit'}; + index = { + getAdUnit() { + return adUnit; + } + } + }); + + function setParams(bidRequest, context, deps = {}) { + const imp = {}; + setImpBidParams(imp, bidRequest, context, Object.assign({bidderRegistry, index}, deps)) + return imp; + } + + it('sets params in ext.prebid.bidder.BIDDER', () => { + expect(setParams({bidder: 'mockBidder', params: {a: 'param'}})).to.eql({ + ext: { + prebid: { + bidder: { + mockBidder: { + a: 'param' + } + } + } + } + }) + }); + + it('has no effect if bidRequest has no params', () => { + expect(setParams({bidder: 'mockBidder'})).to.eql({}); + }) + + describe('when adapter provides transformBidParams', () => { + let transform, bidderRequest; + beforeEach(() => { + bidderRequest = {bidderCode: 'mockBidder'}; + transform = sinon.stub().callsFake((p) => Object.assign({transformed: true}, p)); + bidderRegistry.mockBidder = { + getSpec() { + return { + transformBidParams: transform + } + } + } + }) + + it('runs params through transform', () => { + expect(setParams({bidder: 'mockBidder', params: {a: 'param'}}, {bidderRequest})).to.eql({ + ext: { + prebid: { + bidder: { + mockBidder: { + a: 'param', + transformed: true + } + } + } + } + }); + }); + + it('runs through transform even if bid has no params', () => { + expect(setParams({bidder: 'mockBidder'}, {bidderRequest})).to.eql({ + ext: { + prebid: { + bidder: { + mockBidder: { + transformed: true + } + } + } + } + }) + }) + + it('by default, passes adUnit from index, bidderRequest from context', () => { + const params = {a: 'param'}; + setParams({bidder: 'mockBidder', params}, {bidderRequest}); + sinon.assert.calledWith(transform, params, true, adUnit, [bidderRequest]) + }); + + it('uses provided adUnit, bidderRequests', () => { + const adUnit = {code: 'other-ad-unit'}; + const bidderRequests = [{bidderCode: 'one'}, {bidderCode: 'two'}]; + const params = {a: 'param'}; + setParams({bidder: 'mockBidder', params}, {}, {adUnit, bidderRequests}); + sinon.assert.calledWith(transform, params, true, adUnit, bidderRequests); + }) + }); +}); diff --git a/test/spec/ortbConverter/pbsExtensions/video_spec.js b/test/spec/ortbConverter/pbsExtensions/video_spec.js new file mode 100644 index 00000000000..5bba32c447a --- /dev/null +++ b/test/spec/ortbConverter/pbsExtensions/video_spec.js @@ -0,0 +1,52 @@ +import {setBidResponseVideoCache} from '../../../../libraries/pbsExtensions/processors/video.js'; + +describe('pbjs - ortb videoCacheKey based on ext.prebid', () => { + const EXT_PREBID_CACHE = { + ext: { + prebid: { + cache: { + vastXml: { + cacheId: 'id', + url: 'url' + } + } + } + } + } + + function setCache(bid) { + const bidResponse = {mediaType: 'video'}; + setBidResponseVideoCache(bidResponse, bid); + return bidResponse; + } + + it('has no effect if mediaType is not video', () => { + const resp = {mediaType: 'banner'}; + setBidResponseVideoCache(resp, EXT_PREBID_CACHE); + expect(resp).to.eql({mediaType: 'banner'}); + }); + + it('sets videoCacheKey, vastUrl from ext.prebid.cache.vastXml', () => { + sinon.assert.match(setCache(EXT_PREBID_CACHE), { + videoCacheKey: 'id', + vastUrl: 'url' + }); + }); + + it('sets videoCacheKey, vastUrl from ext.prebid.targeting', () => { + sinon.assert.match(setCache({ + ext: { + prebid: { + targeting: { + hb_uuid: 'id', + hb_cache_host: 'host', + hb_cache_path: '/path' + } + } + } + }), { + vastUrl: 'https://host/path?uuid=id', + videoCacheKey: 'id' + }) + }); +}); diff --git a/test/spec/ortbConverter/priceFloors_spec.js b/test/spec/ortbConverter/priceFloors_spec.js new file mode 100644 index 00000000000..f6d37992711 --- /dev/null +++ b/test/spec/ortbConverter/priceFloors_spec.js @@ -0,0 +1,143 @@ +import {config} from 'src/config.js'; +import {setOrtbExtPrebidFloors, setOrtbImpBidFloor} from '../../../modules/priceFloors.js'; +import 'src/prebid.js'; + +describe('pbjs - ortb imp floor params', () => { + before(() => { + config.resetConfig(); + }); + + afterEach(() => { + config.resetConfig(); + }); + + Object.entries({ + 'has no getFloor': {}, + 'has getFloor that throws': { + getFloor: sinon.stub().callsFake(() => { throw new Error() }), + }, + 'returns invalid floor': { + getFloor: sinon.stub().callsFake(() => ({floor: NaN, currency: null})) + } + }).forEach(([t, req]) => { + it(`has no effect if bid ${t}`, () => { + const imp = {}; + setOrtbImpBidFloor(imp, {}, {}); + expect(imp).to.eql({}); + }) + }) + + it('sets bidfoor and bidfloorcur according to getFloor', () => { + const imp = {}; + const req = { + getFloor() { + return { + currency: 'EUR', + floor: '1.23' + } + } + }; + setOrtbImpBidFloor(imp, req, {}); + expect(imp).to.eql({ + bidfloor: 1.23, + bidfloorcur: 'EUR' + }) + }); + + Object.entries({ + 'missing currency': {floor: 1.23}, + 'missing floor': {currency: 'USD'}, + 'not a number': {floor: 'abc', currency: 'USD'} + }).forEach(([t, floor]) => { + it(`should not set bidfloor if floor is ${t}`, () => { + const imp = {}; + const req = { + getFloor: () => floor + } + setOrtbImpBidFloor(imp, req, {}); + expect(imp).to.eql({}); + }) + }) + + describe('asks for floor in currency', () => { + let req; + beforeEach(() => { + req = { + getFloor(opts) { + return { + floor: 1.23, + currency: opts.currency + } + } + } + }) + + it('from context.currency', () => { + const imp = {}; + setOrtbImpBidFloor(imp, req, {currency: 'JPY'}); + config.setConfig({ + currency: { + adServerCurrency: 'EUR' + } + }) + expect(imp.bidfloorcur).to.eql('JPY'); + }); + + it('from config', () => { + const imp = {}; + config.setConfig({ + currency: { + adServerCurrency: 'EUR' + } + }); + setOrtbImpBidFloor(imp, req, {}); + expect(imp.bidfloorcur).to.eql('EUR'); + }); + + it('defaults to USD', () => { + const imp = {}; + setOrtbImpBidFloor(imp, req, {}); + expect(imp.bidfloorcur).to.eql('USD'); + }) + }); + + it('asks for specific mediaType if context.mediaType is set', () => { + let reqMediaType; + const req = { + getFloor(opts) { + reqMediaType = opts.mediaType; + } + } + setOrtbImpBidFloor({}, req, {mediaType: 'banner'}); + expect(reqMediaType).to.eql('banner'); + }) +}); + +describe('setOrtbExtPrebidFloors', () => { + before(() => { + config.setConfig({floors: {}}); + }) + after(() => { + config.setConfig({floors: {enabled: false}}); + }); + + it('should set ext.prebid.floors.enabled to false', () => { + const req = {}; + setOrtbExtPrebidFloors(req); + expect(req.ext.prebid.floors.enabled).to.equal(false); + }) + + it('should respect fpd', () => { + const req = { + ext: { + prebid: { + floors: { + enabled: true + } + } + } + } + setOrtbExtPrebidFloors(req); + expect(req.ext.prebid.floors.enabled).to.equal(true); + }) +}) diff --git a/test/spec/ortbConverter/schain_spec.js b/test/spec/ortbConverter/schain_spec.js new file mode 100644 index 00000000000..8eeef445948 --- /dev/null +++ b/test/spec/ortbConverter/schain_spec.js @@ -0,0 +1,33 @@ +import {setOrtbSourceExtSchain} from '../../../modules/schain.js'; + +describe('pbjs - ortb source.ext.schain', () => { + it('sets schain from request', () => { + const req = {}; + setOrtbSourceExtSchain(req, {}, { + bidRequests: [{schain: {s: 'chain'}}] + }); + expect(req.source.ext.schain).to.eql({s: 'chain'}); + }); + + it('does not set it if missing', () => { + const req = {}; + setOrtbSourceExtSchain(req, {}, {bidRequests: [{}]}); + expect(req).to.eql({}); + }) + + it('does not set it if already in request', () => { + const req = { + source: { + ext: { + schain: {s: 'chain'} + } + } + } + setOrtbSourceExtSchain(req, {}, { + bidRequests: [{ + schain: {other: 'chain'} + }] + }); + expect(req.source.ext.schain).to.eql({s: 'chain'}); + }) +}); diff --git a/test/spec/ortbConverter/userId_spec.js b/test/spec/ortbConverter/userId_spec.js new file mode 100644 index 00000000000..0b1c8878edf --- /dev/null +++ b/test/spec/ortbConverter/userId_spec.js @@ -0,0 +1,21 @@ +import {setOrtbUserExtEids} from '../../../modules/userId/index.js'; + +describe('pbjs - ortb user eids', () => { + it('sets user.ext.eids from request', () => { + const req = {}; + setOrtbUserExtEids(req, {}, { + bidRequests: [ + { + userIdAsEids: {e: 'id'} + } + ] + }); + expect(req.user.ext.eids).to.eql({e: 'id'}); + }); + + it('has no effect if requests have no eids', () => { + const req = {}; + setOrtbUserExtEids(req, {}, [{}]); + expect(req).to.eql({}); + }) +}) diff --git a/test/spec/ortbConverter/usp_spec.js b/test/spec/ortbConverter/usp_spec.js new file mode 100644 index 00000000000..01ff689cd97 --- /dev/null +++ b/test/spec/ortbConverter/usp_spec.js @@ -0,0 +1,15 @@ +import {setOrtbUsp} from '../../../modules/consentManagementUsp.js'; + +describe('pbjs - ortb usp', () => { + it('sets regs.ext.us_privacy from bidderRequest', () => { + const req = {}; + setOrtbUsp(req, {uspConsent: '1NN'}); + expect(req.regs.ext.us_privacy).to.eql('1NN'); + }); + + it('does not set if missing', () => { + const req = {}; + setOrtbUsp(req, {}); + expect(req).to.eql({}); + }); +}) diff --git a/test/spec/ortbConverter/video_spec.js b/test/spec/ortbConverter/video_spec.js new file mode 100644 index 00000000000..8ac6d8b4d08 --- /dev/null +++ b/test/spec/ortbConverter/video_spec.js @@ -0,0 +1,189 @@ +import {fillVideoImp, fillVideoResponse, VALIDATIONS} from '../../../libraries/ortbConverter/processors/video.js'; +import {BANNER, VIDEO} from '../../../src/mediaTypes.js'; + +describe('pbjs -> ortb video conversion', () => { + [ + { + t: 'non-video request', + request: { + mediaTypes: { + banner: {} + } + }, + imp: {} + }, + { + t: 'instream video request', + request: { + mediaTypes: { + video: { + playerSize: [[1, 2]], + context: 'instream', + mimes: ['video/mp4'], + skip: 1, + } + } + }, + imp: { + video: { + w: 1, + h: 2, + mimes: ['video/mp4'], + skip: 1, + placement: 1, + }, + }, + }, + { + t: 'outstream video request', + request: { + mediaTypes: { + video: { + playerSize: [[1, 2]], + context: 'outstream', + mimes: ['video/mp4'], + skip: 1 + } + } + }, + imp: { + video: { + w: 1, + h: 2, + mimes: ['video/mp4'], + skip: 1, + }, + }, + }, + { + t: 'video request with explicit placement', + request: { + mediaTypes: { + video: { + playerSize: [[1, 2]], + placement: 'explicit' + } + } + }, + imp: { + video: { + w: 1, + h: 2, + placement: 'explicit', + } + } + }, + { + t: 'video request with multiple playerSizes', + request: { + mediaTypes: { + video: { + playerSize: [[1, 2], [3, 4]] + } + } + }, + imp: { + video: { + w: 1, + h: 2, + } + } + }, + { + t: 'video request with 2-tuple playerSize', + request: { + mediaTypes: { + video: { + playerSize: [1, 2] + } + } + }, + imp: { + video: { + w: 1, + h: 2, + } + } + }, + ].forEach(({t, request, imp}) => { + it(`can handle ${t}`, () => { + const actual = {}; + fillVideoImp(actual, request, {}); + expect(actual).to.eql(imp); + }); + }); + + it('should keep ortb2Imp.video', () => { + const imp = { + video: { + someParam: 'someValue' + } + }; + fillVideoImp(imp, {mediaTypes: {video: {playerSize: [[1, 2]]}}}, {}); + expect(imp.video.someParam).to.eql('someValue'); + }); + + it('does nothing is context.mediaType is set but is not VIDEO', () => { + const imp = {}; + fillVideoImp(imp, {mediaTypes: {video: {playerSize: [[1, 2]]}}}, {mediaType: BANNER}); + expect(imp).to.eql({}); + }); +}); + +describe('ortb -> pbjs video conversion', () => { + [ + { + t: 'non-video response', + seatbid: {}, + response: { + mediaType: BANNER + }, + expected: { + mediaType: BANNER + } + }, + { + t: 'simple video response', + seatbid: { + adm: 'mockAdm', + nurl: 'mockNurl' + }, + response: { + mediaType: VIDEO, + }, + context: { + imp: { + video: { + w: 1, + h: 2 + } + } + }, + expected: { + mediaType: VIDEO, + playerWidth: 1, + playerHeight: 2, + vastXml: 'mockAdm', + vastUrl: 'mockNurl' + } + }, + { + t: 'video response without playerSize', + seatbid: {}, + response: { + mediaType: VIDEO, + }, + context: { + imp: {} + }, + expected: { + mediaType: VIDEO + } + } + ].forEach(({t, seatbid, context, response, expected}) => { + it(`can handle ${t}`, () => { + fillVideoResponse(response, seatbid, context); + expect(response).to.eql(expected); + }) + }) +}) diff --git a/test/spec/utils_spec.js b/test/spec/utils_spec.js index 500f479355d..9199b259ad6 100644 --- a/test/spec/utils_spec.js +++ b/test/spec/utils_spec.js @@ -2,7 +2,7 @@ import { getAdServerTargeting } from 'test/fixtures/fixtures.js'; import { expect } from 'chai'; import CONSTANTS from 'src/constants.json'; import * as utils from 'src/utils.js'; -import {deepEqual, waitForElementToLoad} from 'src/utils.js'; +import {memoize, deepEqual, waitForElementToLoad} from 'src/utils.js'; var assert = require('assert'); @@ -1260,3 +1260,47 @@ describe('Utils', function () { }); }); }); + +describe('memoize', () => { + let fn; + + beforeEach(() => { + fn = sinon.stub().callsFake(function() { + return Array.from(arguments); + }); + }); + + it('delegates to fn', () => { + expect(memoize(fn)('one', 'two')).to.eql(['one', 'two']); + }); + + it('caches result after first call, if first argument is the same', () => { + const mem = memoize(fn); + mem('one', 'two'); + expect(mem('one', 'three')).to.eql(['one', 'two']); + expect(fn.callCount).to.equal(1); + }); + + it('delegates again when the first argument changes', () => { + const mem = memoize(fn); + mem('one', 'two'); + expect(mem('two', 'one')).to.eql(['two', 'one']); + expect(fn.callCount).to.eql(2); + }); + + it('can clear cache with .clear', () => { + const mem = memoize(fn); + mem('arg'); + mem.clear(); + expect(mem('arg')).to.eql(['arg']); + expect(fn.callCount).to.equal(2); + }); + + it('allows setting cache keys', () => { + const mem = memoize(fn, (...args) => args.join(',')) + mem('one', 'two'); + mem('one', 'three'); + expect(mem('one', 'three')).to.eql(['one', 'three']); + expect(fn.callCount).to.eql(2); + }) +}) From f2e8881dbd216de1b2d055bb4edeb15bcfa29637 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Oct 2022 12:23:56 -0700 Subject: [PATCH 053/367] Bump minimatch from 0.2.14 to 3.0.4 (#9143) Bumps [minimatch](https://github.com/isaacs/minimatch) from 0.2.14 to 3.0.4. - [Release notes](https://github.com/isaacs/minimatch/releases) - [Commits](https://github.com/isaacs/minimatch/compare/v0.2.14...v3.0.4) --- updated-dependencies: - dependency-name: minimatch dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 10025 +------------------------------------------- 1 file changed, 33 insertions(+), 9992 deletions(-) diff --git a/package-lock.json b/package-lock.json index 61d961b102e..e11da6fba7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2344,12 +2344,6 @@ "@types/node": "*" } }, - "node_modules/@types/linkify-it": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", - "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", - "dev": true - }, "node_modules/@types/lodash": { "version": "4.14.179", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz", @@ -2383,16 +2377,6 @@ "@types/lodash": "*" } }, - "node_modules/@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", - "dev": true, - "dependencies": { - "@types/linkify-it": "*", - "@types/mdurl": "*" - } - }, "node_modules/@types/mdast": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", @@ -3786,35 +3770,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/adm-zip": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.2.1.tgz", - "integrity": "sha512-J2LiZpRxcLsJm2IwoekNa6COwzEZnMwCJ3vxz0UCw2NYUH2WFi7svuDrVccq5KpBGmzGUgFa0L0FwEmKmu/rzQ==", - "dev": true, - "engines": { - "node": ">=0.3.0" - } - }, "node_modules/aes-decrypter": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz", @@ -3857,6 +3812,7 @@ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true, + "optional": true, "engines": { "node": ">=0.4.2" } @@ -4127,15 +4083,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -4267,12 +4214,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true - }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -4282,24 +4223,6 @@ "safer-buffer": "~2.1.0" } }, - "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dev": true, - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, "node_modules/assert": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", @@ -4348,27 +4271,6 @@ "node": ">=8" } }, - "node_modules/astw": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", - "integrity": "sha512-E/4z//dvN0lfr8zAx8hXeQ8o3nRoQaL/wqI7fAALEvh/40mnyUxfFB9MwyDHYKVDtS3cp3Pow5s96djZR5lkWw==", - "dev": true, - "dependencies": { - "acorn": "^4.0.3" - } - }, - "node_modules/astw/node_modules/acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -4983,12 +4885,6 @@ "node": ">=0.10.0" } }, - "node_modules/Base64": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz", - "integrity": "sha512-reGEWshDmTDQDsCec/HduOO9Wyj6yMOupMfhIf3ugN1TDlK2NQW4DDJSqNNtp380SNcvRfXtO8HSCQot0d0SMw==", - "dev": true - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -5045,69 +4941,6 @@ "tweetnacl": "^0.14.3" } }, - "node_modules/beefy": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/beefy/-/beefy-1.1.0.tgz", - "integrity": "sha512-olZqTbw6gnofdbG98uAKvG6O/AjV6WGuPsKpYF41VQK39sUYvulm86RssD1K/iVNkkSJ8cuYeheJ8Nk2gz16wA==", - "dev": true, - "dependencies": { - "chokidar": "0.8.1", - "colors": "~0.6.0-1", - "ignorepatterns": "1.0.1", - "mime": "~1.2.9", - "nopt": "~2.1.1", - "open": "0.0.3", - "portfinder": "~0.2.1", - "response-stream": "0.0.0", - "script-injector": "~0.1.0", - "sse-stream": "0.0.4", - "through": "~2.2.0" - }, - "bin": { - "beefy": "bin/beefy" - } - }, - "node_modules/beefy/node_modules/chokidar": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-0.8.1.tgz", - "integrity": "sha512-Bl/CteHnM5g3eKGPMkraZQW7Yzk2Gu87eE3jdaMfCNJP79sVa54M5KHStr3WtJl4vVoVSndVDws6IFLTmMa3Lw==", - "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", - "dev": true, - "hasInstallScript": true - }, - "node_modules/beefy/node_modules/colors": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", - "integrity": "sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/beefy/node_modules/mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", - "dev": true - }, - "node_modules/beefy/node_modules/nopt": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.1.2.tgz", - "integrity": "sha512-x8vXm7BZ2jE1Txrxh/hO74HTuYZQEbo8edoRcANgdZ4+PCV+pbjd/xdummkmjjC7LU5EjPzlu8zEq/oxWylnKA==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/beefy/node_modules/through": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", - "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", - "dev": true - }, "node_modules/beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", @@ -5210,12 +5043,6 @@ "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", "dev": true }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true - }, "node_modules/body": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", @@ -5286,20 +5113,6 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, - "node_modules/boom": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", - "integrity": "sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==", - "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", - "dev": true, - "optional": true, - "dependencies": { - "hoek": "0.9.x" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5322,581 +5135,12 @@ "node": ">=8" } }, - "node_modules/brfs": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/brfs/-/brfs-0.0.9.tgz", - "integrity": "sha512-5bjo0XG6pPGTFJsS4rtvP1vvwLp3UstdF062l10RKcfG60+izXak0DFcfQwMtBQNGlFm588mM2WvD02hJErVYg==", - "dev": true, - "dependencies": { - "escodegen": "0.0.17", - "falafel": "~0.1.6", - "through": "~2.2.0" - }, - "bin": { - "brfs": "bin/cmd.js" - } - }, - "node_modules/brfs/node_modules/escodegen": { - "version": "0.0.17", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-0.0.17.tgz", - "integrity": "sha512-muX87X0L2dvVJ4ZPKAJLQlcyg2qhl6ps8Ow8vOAcuoFIrZLtXNMGfjnD19LSTrZ1SBHQsI+tvD8YlsJqHhfXrw==", - "dev": true, - "dependencies": { - "esprima": "~1.0.2", - "estraverse": "~0.0.4" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=0.4.0" - }, - "optionalDependencies": { - "source-map": ">= 0.1.2" - } - }, - "node_modules/brfs/node_modules/esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/brfs/node_modules/estraverse": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-0.0.4.tgz", - "integrity": "sha512-21DfBCsFJGb3HZr0vEBH1Wk1tGSbbzA8I/xtSSoy/pRtupHv0OgBmObcNGXM3ec6/pOXTOOUYY9/5bfluzz0sw==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/brfs/node_modules/through": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", - "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", - "dev": true - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true - }, - "node_modules/browser-pack": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-3.2.0.tgz", - "integrity": "sha512-BHla5EbbxjNyLMFUMamVjeTY+q1QwHbrYNXlWOkw71QcBqAQF7maJyNh3OI/V0d5YyNdMYD6tiPhJB9ukBo99Q==", - "dev": true, - "dependencies": { - "combine-source-map": "~0.3.0", - "concat-stream": "~1.4.1", - "defined": "~0.0.0", - "JSONStream": "~0.8.4", - "through2": "~0.5.1", - "umd": "^2.1.0" - }, - "bin": { - "browser-pack": "bin/cmd.js" - } - }, - "node_modules/browser-pack/node_modules/concat-stream": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", - "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.9", - "typedarray": "~0.0.5" - } - }, - "node_modules/browser-pack/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/browser-pack/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/browser-pack/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/browser-pack/node_modules/through2": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", - "integrity": "sha512-zexCrAOTbjkBCXGyozn7hhS3aEaqdrc59mAD2E3dKYzV1vFuEGQ1hEDJN2oQMQFwy4he2zyLqPZV+AlfS8ZWJA==", - "dev": true, - "dependencies": { - "readable-stream": "~1.0.17", - "xtend": "~3.0.0" - } - }, - "node_modules/browser-pack/node_modules/through2/node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/browser-pack/node_modules/xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/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, - "dependencies": { - "resolve": "1.1.7" - } - }, - "node_modules/browser-resolve/node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", - "dev": true - }, "node_modules/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 }, - "node_modules/browserify": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-8.1.3.tgz", - "integrity": "sha512-0KKOkCQXCvP64qm73CtESE92pVnB5MkjA2W/Tmf+S4uPHVY4/SeCwO7wdr4mkke5ySoVyMqsOcMa5zo6uh9c9A==", - "dev": true, - "dependencies": { - "assert": "~1.3.0", - "browser-pack": "^3.2.0", - "browser-resolve": "^1.3.0", - "browserify-zlib": "~0.1.2", - "buffer": "^3.0.0", - "builtins": "~0.0.3", - "commondir": "0.0.1", - "concat-stream": "~1.4.1", - "console-browserify": "^1.1.0", - "constants-browserify": "~0.0.1", - "crypto-browserify": "^3.0.0", - "deep-equal": "~0.2.1", - "defined": "~0.0.0", - "deps-sort": "^1.3.5", - "domain-browser": "~1.1.0", - "duplexer2": "~0.0.2", - "events": "~1.0.0", - "glob": "^4.0.5", - "http-browserify": "^1.4.0", - "https-browserify": "~0.0.0", - "inherits": "~2.0.1", - "insert-module-globals": "^6.2.0", - "isarray": "0.0.1", - "JSONStream": "~0.8.3", - "labeled-stream-splicer": "^1.0.0", - "module-deps": "^3.6.3", - "os-browserify": "~0.1.1", - "parents": "^1.0.1", - "path-browserify": "~0.0.0", - "process": "^0.10.0", - "punycode": "~1.2.3", - "querystring-es3": "~0.2.0", - "readable-stream": "^1.0.33-1", - "resolve": "~0.7.1", - "shallow-copy": "0.0.1", - "shasum": "^1.0.0", - "shell-quote": "~0.0.1", - "stream-browserify": "^1.0.0", - "string_decoder": "~0.10.0", - "subarg": "^1.0.0", - "syntax-error": "^1.1.1", - "through2": "^1.0.0", - "timers-browserify": "^1.0.1", - "tty-browserify": "~0.0.0", - "umd": "~2.1.0", - "url": "~0.10.1", - "util": "~0.10.1", - "vm-browserify": "~0.0.1", - "xtend": "^3.0.0" - }, - "bin": { - "browserify": "bin/cmd.js" - } - }, - "node_modules/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, - "dependencies": { - "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" - } - }, - "node_modules/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, - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/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, - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dev": true, - "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "dev": true, - "dependencies": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "node_modules/browserify-sign/node_modules/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, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/browserify-sign/node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/browserify-zlib": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", - "integrity": "sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==", - "dev": true, - "dependencies": { - "pako": "~0.2.0" - } - }, - "node_modules/browserify/node_modules/assert": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.3.0.tgz", - "integrity": "sha512-5aKcpD+XnHpZ7EGxsuo6uoILNh0rvm0Ypa17GlkrF2CNSPhvdgi3ft9XsL2ajdVOI2I3xuGZnHvlXAeqTZYvXg==", - "dev": true, - "dependencies": { - "util": "0.10.3" - } - }, - "node_modules/browserify/node_modules/assert/node_modules/inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", - "dev": true - }, - "node_modules/browserify/node_modules/assert/node_modules/util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", - "dev": true, - "dependencies": { - "inherits": "2.0.1" - } - }, - "node_modules/browserify/node_modules/base64-js": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/browserify/node_modules/buffer": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.2.tgz", - "integrity": "sha512-c3M77NkHJxS0zx/ErxXhDLr1v3y2MDXPeTJPvLNOaIYJ4ymHBUFQ9EXzt9HYuqAJllMoNb/EZ8hIiulnQFAUuQ==", - "dev": true, - "dependencies": { - "base64-js": "0.0.8", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/browserify/node_modules/buffer/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/browserify/node_modules/commondir": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-0.0.1.tgz", - "integrity": "sha512-Ghe1LmLv3G3c0XJYu+c88MCRIPqWQ67qaqKY1KvuN4uPAjfUj+y4hvcpZ2kCPrjpRNyklW4dpAZZ8a7vOh50tg==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/browserify/node_modules/concat-stream": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", - "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.9", - "typedarray": "~0.0.5" - } - }, - "node_modules/browserify/node_modules/deep-equal": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", - "integrity": "sha512-FXgye2Jr6oEk01S7gmSrHrPEQ1ontR7wwl+nYiZ8h4SXlHVm0DYda74BIPcHz2s2qPz4+375IcAz1vsWLwddgQ==", - "dev": true - }, - "node_modules/browserify/node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "dev": true, - "dependencies": { - "readable-stream": "~1.1.9" - } - }, - "node_modules/browserify/node_modules/events": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/events/-/events-1.0.2.tgz", - "integrity": "sha512-XK19KwlDJo8XsceooxNDK1pObtcT44+Xte6V/jQc4a+fHq1qEouThyyX2ePmS0hS8RcCulmRxzg+T8jiLKAFFQ==", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/browserify/node_modules/glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha512-I0rTWUKSZKxPSIAIaqhSXTM/DiII6wame+rEC3cFA5Lqmr9YmdL7z6Hj9+bdWtTvoY1Su4/OiMLmb37Y7JzvJQ==", - "dev": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/browserify/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "node_modules/browserify/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/browserify/node_modules/minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", - "dev": true, - "dependencies": { - "brace-expansion": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/browserify/node_modules/process": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", - "integrity": "sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/browserify/node_modules/punycode": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.2.4.tgz", - "integrity": "sha512-h/vscxLPvI2l7k/0dFUKZ5I5TgMCJ/Pl+J6rw77PDuQM6UApf/GaRVkjv/YSm2k+fbp7Yw8dxsoe29DolT7h7w==", - "dev": true, - "engines": [ - "node", - "rhino" - ] - }, - "node_modules/browserify/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/browserify/node_modules/resolve": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.7.4.tgz", - "integrity": "sha512-zxmAcifDjKxmUbk7chQdKhDSn8ml08g+MYyU37xhEXBp+N81cfbYsm4e0Gn9jtLbAvbR8w8Ox09xqUZtPuCoeA==", - "dev": true - }, - "node_modules/browserify/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/browserify/node_modules/through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "dependencies": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, - "node_modules/browserify/node_modules/through2/node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/browserify/node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "dev": true, - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/browserify/node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", - "dev": true - }, - "node_modules/browserify/node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dev": true, - "dependencies": { - "inherits": "2.0.3" - } - }, - "node_modules/browserify/node_modules/xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, "node_modules/browserslist": { "version": "4.21.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", @@ -6083,12 +5327,6 @@ "node": ">=0.10" } }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "dev": true - }, "node_modules/buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", @@ -6098,12 +5336,6 @@ "node": ">=0.2.0" } }, - "node_modules/builtins": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-0.0.7.tgz", - "integrity": "sha512-T8uCGKc0/2aLVt6omt8JxDRBoWEMkku+wFesxnhxnt4NygVZG99zqxo7ciK8eebszceKamGoUiLdkXCgGQyrQw==", - "dev": true - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -6342,15 +5574,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -6369,28 +5592,6 @@ "node": ">=6" } }, - "node_modules/camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==", - "dev": true, - "dependencies": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/camelcase-keys/node_modules/camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/can-autoplay": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/can-autoplay/-/can-autoplay-3.0.2.tgz", @@ -6418,18 +5619,6 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, - "node_modules/catharsis": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", - "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", - "dev": true, - "dependencies": { - "lodash": "^4.17.15" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -6619,16 +5808,6 @@ "node": ">=6.0" } }, - "node_modules/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, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -6879,35 +6058,6 @@ "node": ">=0.1.90" } }, - "node_modules/combine-source-map": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.3.0.tgz", - "integrity": "sha512-HRKa6g9SC1xd6ifto8ay6SxvyHaaQ50/8NO1ZONXx2hsIF9t/52qXa7Eeivaf5KFOSowK7Nm8TkIL/VC4khdBA==", - "dev": true, - "dependencies": { - "convert-source-map": "~0.3.0", - "inline-source-map": "~0.3.0", - "source-map": "~0.1.31" - } - }, - "node_modules/combine-source-map/node_modules/convert-source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", - "integrity": "sha512-+4nRk0k3oEpwUB7/CalD7xE2z4VmtEnnq0GO2IPTkrooTrAhEsWvuLF5iWP1dXrwluki/azwXV1ve7gtYuPldg==", - "dev": true - }, - "node_modules/combine-source-map/node_modules/source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", - "dev": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -6930,15 +6080,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/commander": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.0.0.tgz", - "integrity": "sha512-qebjpyeaA/nJ4w3EO2cV2++/zEkccPnjWogzA2rff+Lk8ILI75vULeTmyd4wPxWdKwtP3J+G39IXVZadh0UHyw==", - "dev": true, - "engines": { - "node": ">= 0.6.x" - } - }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -7019,16 +6160,6 @@ "node": ">=0.10.0" } }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, "node_modules/connect": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", @@ -7068,18 +6199,6 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "node_modules/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 - }, - "node_modules/constants-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-0.0.1.tgz", - "integrity": "sha512-FL+diDS9AKR5BAA2M+GNk8lnH64tRE3zepTG9hucxc7o04LgCRhkQZhF7u/OKHZT8LLRT+sZEi9qFzXUchq9pA==", - "dev": true - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -7288,49 +6407,6 @@ "node": ">= 6" } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/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, - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/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, - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, "node_modules/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", @@ -7359,42 +6435,6 @@ "node": ">= 8" } }, - "node_modules/cryptiles": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", - "integrity": "sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==", - "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", - "dev": true, - "optional": true, - "dependencies": { - "boom": "0.4.x" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/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, - "dependencies": { - "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" - }, - "engines": { - "node": "*" - } - }, "node_modules/crypto-js": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", @@ -7432,37 +6472,6 @@ "node": ">=0.10.0" } }, - "node_modules/cssauron": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", - "integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==", - "dev": true, - "dependencies": { - "through": "X.X.X" - } - }, - "node_modules/ctype": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", - "integrity": "sha512-T6CEkoSV4q50zW3TlTHMbzy1E5+zlnNcY+yb7tWVYlTwPhx9LpnfAkd4wecpWknDyptp4k97LUZeInlf6jdzBg==", - "dev": true, - "optional": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", - "dev": true, - "dependencies": { - "array-find-index": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -7552,15 +6561,6 @@ "ms": "^2.1.1" } }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -7744,12 +6744,6 @@ "node": ">=0.10.0" } }, - "node_modules/defined": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", - "integrity": "sha512-zpqiCT8bODLu3QSmLLic8xJnYWBFjOSu/fBCm189oAiTtPq/PSanNACKZDS7kgSyCJY7P+IcODzlIogBK/9RBg==", - "dev": true - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -7767,80 +6761,6 @@ "node": ">= 0.6" } }, - "node_modules/deps-sort": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-1.3.9.tgz", - "integrity": "sha512-aEnmQuu/Hf5h8akL8QshYWzk9MVBg/JYMyNq/Lz68i69nR17tunjP6o/AC6Tn48c8ayzG6aeKs6OoFOtVCtvrQ==", - "dev": true, - "dependencies": { - "JSONStream": "^1.0.3", - "shasum": "^1.0.0", - "subarg": "^1.0.0", - "through2": "^1.0.0" - }, - "bin": { - "deps-sort": "bin/cmd.js" - } - }, - "node_modules/deps-sort/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/deps-sort/node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/deps-sort/node_modules/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, - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/deps-sort/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/deps-sort/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/deps-sort/node_modules/through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "dependencies": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -7850,16 +6770,6 @@ "node": ">=6" } }, - "node_modules/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, - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -7895,37 +6805,6 @@ "node": ">=0.10.0" } }, - "node_modules/detective": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", - "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", - "dev": true, - "dependencies": { - "acorn": "^5.2.1", - "defined": "^1.0.0" - } - }, - "node_modules/detective/node_modules/acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/detective/node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/devtools": { "version": "7.16.16", "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", @@ -7984,16 +6863,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, "node_modules/di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", @@ -8018,23 +6887,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/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, - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -8255,16 +7107,6 @@ "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", "dev": true }, - "node_modules/domain-browser": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", - "integrity": "sha512-fJ5MoHxe69h3E4/lJtFRhcWwLb04bhIBSfvCEMS1YDH+/9yEZTqBHTSTgch8nCP5tE5k2gdQEjodUqJzy7qJ9Q==", - "dev": true, - "engines": { - "node": ">=0.4", - "npm": ">=1.2" - } - }, "node_modules/dset": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz", @@ -8399,27 +7241,6 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.243.tgz", "integrity": "sha512-BgLD2gBX43OSXwlT01oYRRD5NIB4n3okTRxkzEAC6G0SZG4TTlyrWMjbOo0fajCwqwpRtMHXQNMjtRN6qpNtfw==" }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -8516,15 +7337,6 @@ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", "dev": true }, - "node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/errno": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", @@ -8666,20 +7478,6 @@ "es6-symbol": "^3.1.1" } }, - "node_modules/es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", - "dev": true, - "dependencies": { - "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" - } - }, "node_modules/es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", @@ -8701,29 +7499,6 @@ "es6-promise": "^4.0.3" } }, - "node_modules/es6-set": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", - "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "es6-iterator": "~2.0.3", - "es6-symbol": "^3.1.3", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-set/node_modules/type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", - "dev": true - }, "node_modules/es6-symbol": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", @@ -8862,21 +7637,6 @@ "node": ">= 0.8.0" } }, - "node_modules/escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==", - "dev": true, - "dependencies": { - "es6-map": "^0.1.3", - "es6-weak-map": "^2.0.1", - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/eslint": { "version": "7.32.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", @@ -9349,19 +8109,6 @@ "node": ">=0.10.0" } }, - "node_modules/esprima-fb": { - "version": "10001.1.0-dev-harmony-fb", - "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-10001.1.0-dev-harmony-fb.tgz", - "integrity": "sha512-z2dx3A/ZGNamsDjJS4FZPXnpoRCEkQXqouKBCOaJifyx4HkEVoSQ3YWFX18Scut1Aq9gnctzLWcWJgKkL0xNQw==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", @@ -9413,15 +8160,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse-fb": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.2.tgz", - "integrity": "sha512-wp3lfRrWy5EQD9TqesuYM1SKVP4ERT0cUatb4e8Vznf4K5IOpREhuyXZxGj3a9s9mvX5vGZKNHA4R9D4kp9Q9A==", - "dev": true, - "peerDependencies": { - "estraverse": "*" - } - }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -9491,16 +8229,6 @@ "node": ">=0.8.x" } }, - "node_modules/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, - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, "node_modules/execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -10000,31 +8728,6 @@ "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", "dev": true }, - "node_modules/falafel": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/falafel/-/falafel-0.1.6.tgz", - "integrity": "sha512-r1s3VwKzm6PB35MZmnfZoF6NTgSKRxf8How2lBsrDq81OsYXb/2fR8ysfURHCTlFpqJDQVA88iB70wFrFRYDsA==", - "dev": true, - "dependencies": { - "esprima": "~1.0.2" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/falafel/node_modules/esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", @@ -10156,58 +8859,6 @@ "node": ">=10" } }, - "node_modules/fileset": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", - "integrity": "sha512-aK3PFyHSwWsBJCarRxMRIXSGamfroi9ehG8f4e5A2n5nSlEVHe8y44jNTIN4+HdZSpK3FNV0EdihH1iDWTdnGg==", - "dev": true, - "dependencies": { - "glob": "5.x", - "minimatch": "2.x" - } - }, - "node_modules/fileset/node_modules/glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", - "dev": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/fileset/node_modules/minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", - "dev": true, - "dependencies": { - "brace-expansion": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/fill-keys": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA==", - "dev": true, - "dependencies": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -10451,23 +9102,6 @@ "node": ">= 0.12" } }, - "node_modules/formatio": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", - "integrity": "sha512-cPh7is6k3d8tIUh+pnXXuAbD/uhSXGgqLPw0UrYpv5lfdJ+MMMSjx40JNpqP7Top9Nt25YomWEiRmkHbOvkCaA==", - "deprecated": "This package is unmaintained. Use @sinonjs/formatio instead", - "dev": true, - "dependencies": { - "samsam": "~1.1" - } - }, - "node_modules/formatio/node_modules/samsam": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.3.tgz", - "integrity": "sha512-t9rCPskf50hZ53eH8Z+cSWD4LfJBac+8vSSuzi1Y2HzygyXxtAl0BaR3hr6iI6A+nFQbkmJNC/brQLNEeVnrmg==", - "deprecated": "This package has been deprecated in favour of @sinonjs/samsam", - "dev": true - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -10682,24 +9316,6 @@ "node": ">= 4.0.0" } }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dev": true, - "dependencies": { - "is-property": "^1.0.2" - } - }, - "node_modules/generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", - "dev": true, - "dependencies": { - "is-property": "^1.0.0" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -10760,15 +9376,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -10815,79 +9422,6 @@ "assert-plus": "^1.0.0" } }, - "node_modules/gh-got": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-1.1.0.tgz", - "integrity": "sha512-jo4rP5ugI6fZGjS0vmvHlM8P7EBA39p8to4r2i+LqYXxeg4M8qnPXiKaetDfH0YLXkO9Hfsa2mKIjMsGJwcdGQ==", - "dev": true, - "dependencies": { - "got": "^3.2.0", - "object-assign": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gh-got/node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/gh-got/node_modules/got": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/got/-/got-3.3.1.tgz", - "integrity": "sha512-7chPlc0pWHjvq7B6dEEXz4GphoDupOvBSSl6AwRsAJX7GPTZ+bturaZiIigX4Dp6KrAP67nvzuKkNc0SLA0DKg==", - "dev": true, - "dependencies": { - "duplexify": "^3.2.0", - "infinity-agent": "^2.0.0", - "is-redirect": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "nested-error-stacks": "^1.0.0", - "object-assign": "^3.0.0", - "prepend-http": "^1.0.0", - "read-all-stream": "^3.0.0", - "timed-out": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gh-got/node_modules/got/node_modules/object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gh-got/node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gh-got/node_modules/object-assign": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha512-CdsOUYIh5wIiozhJ3rLQgmUTgcyzFwZZrqhkKhODMoGtPKM+wt0h0CNIoauJWMsS9822EdzPsF/6mb4nLvPN5g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/git-up": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/git-up/-/git-up-6.0.0.tgz", @@ -10913,18 +9447,6 @@ "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==", "dev": true }, - "node_modules/github-url-from-git": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/github-url-from-git/-/github-url-from-git-1.5.0.tgz", - "integrity": "sha512-WWOec4aRI7YAykQ9+BHmzjyNlkfJFG8QLXnDTsLz/kZefq7qkzdfo4p6fkYYMIq1aj+gZcQs/1HQhQh3DPPxlQ==", - "dev": true - }, - "node_modules/github-url-from-username-repo": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/github-url-from-username-repo/-/github-url-from-username-repo-1.0.2.tgz", - "integrity": "sha512-Tj8CQqRoFVTglGdQ8FQmfq8gOOoOYZX7tnOKP8jq8Hdz2OTDhxvtlkLAbrqMYZ7X/YdaYQoUG1IBWxISBfqZ+Q==", - "dev": true - }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -12963,15 +11485,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha512-kaNz5OTAYYmt646Hkqw50/qyxP2vFnTVu5AQ1Zmk22Kk5+4Qx6BpO8+u7IKsML5fOsFk0ZT0AcCJNYwcvaLBvw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -13064,64 +11577,6 @@ "node": ">=0.10.0" } }, - "node_modules/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, - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash-base/node_modules/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, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/hash-base/node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/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, - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "node_modules/hast-util-is-element": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz", @@ -13181,23 +11636,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hawk": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", - "integrity": "sha512-am8sVA2bCJIw8fuuVcKvmmNnGFUGW8spTkVtj2fXTEZVkfN42bwFZFtDem57eFi+NSxurJB8EQ7Jd3uCHLn8Vw==", - "deprecated": "This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", - "dev": true, - "optional": true, - "dependencies": { - "boom": "0.4.x", - "cryptiles": "0.2.x", - "hoek": "0.9.x", - "sntp": "0.2.x" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -13216,28 +11654,6 @@ "node": ">=12.0.0" } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/hoek": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", - "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==", - "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -13275,147 +11691,6 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "node_modules/html-select": { - "version": "2.3.24", - "resolved": "https://registry.npmjs.org/html-select/-/html-select-2.3.24.tgz", - "integrity": "sha512-kQ+YZoVQ8Aux6bUqMVc0iufcZOv03+xYZ4J5v2beT5wkNrW/e2roZ8pnU4LunVOVBGFkbodFKR0TvuMkTdyrJQ==", - "dev": true, - "dependencies": { - "cssauron": "^1.1.0", - "duplexer2": "~0.0.2", - "inherits": "^2.0.1", - "minimist": "~0.0.8", - "readable-stream": "^1.0.27-1", - "split": "~0.3.0", - "stream-splicer": "^1.2.0", - "through2": "^1.0.0" - }, - "bin": { - "html-select": "bin/cmd.js" - } - }, - "node_modules/html-select/node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "dev": true, - "dependencies": { - "readable-stream": "~1.1.9" - } - }, - "node_modules/html-select/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/html-select/node_modules/minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", - "dev": true - }, - "node_modules/html-select/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/html-select/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/html-select/node_modules/through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "dependencies": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, - "node_modules/html-tokenize": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-1.2.5.tgz", - "integrity": "sha512-7sCme3w9Hiv/kfL6sO6ePTGAV5fY6P7WDZyOs0zfXXU8vsS1ps1CQfGe0J1yuAdcCnOJ9h66RLYX/e9Cife8yw==", - "dev": true, - "dependencies": { - "inherits": "~2.0.1", - "minimist": "~0.0.8", - "readable-stream": "~1.0.27-1", - "through2": "~0.4.1" - }, - "bin": { - "html-tokenize": "bin/cmd.js" - } - }, - "node_modules/html-tokenize/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/html-tokenize/node_modules/minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", - "dev": true - }, - "node_modules/html-tokenize/node_modules/object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==", - "dev": true - }, - "node_modules/html-tokenize/node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/html-tokenize/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/html-tokenize/node_modules/through2": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", - "integrity": "sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==", - "dev": true, - "dependencies": { - "readable-stream": "~1.0.17", - "xtend": "~2.1.1" - } - }, - "node_modules/html-tokenize/node_modules/xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", - "dev": true, - "dependencies": { - "object-keys": "~0.4.0" - }, - "engines": { - "node": ">=0.4" - } - }, "node_modules/html-void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", @@ -13426,16 +11701,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/http-browserify": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz", - "integrity": "sha512-Irf/LJXmE3cBzU1eaR4+NEX6bmVLqt1wkmDiA7kBwH7zmb0D8kBAXsDmQ88hhj/qv9iEZKlyGx/hrMcFi8sOHw==", - "dev": true, - "dependencies": { - "Base64": "~0.2.0", - "inherits": "~2.0.1" - } - }, "node_modules/http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -13505,12 +11770,6 @@ "node": ">=10.19.0" } }, - "node_modules/https-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", - "integrity": "sha512-EjDQFbgJr1vDD/175UJeSX3ncQ3+RUnCL5NkthQGHvF4VNHlzTy8ifJfTqz47qiPRqaFH58+CbuG3x51WuB1XQ==", - "dev": true - }, "node_modules/https-proxy-agent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", @@ -13564,15 +11823,6 @@ "node": ">= 4" } }, - "node_modules/ignorepatterns": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignorepatterns/-/ignorepatterns-1.0.1.tgz", - "integrity": "sha512-9bm+Wivwyocr88go3y04hpX3qdFs6EgsxrjjpcI9C2GAqxcWYVMJaS9h9KL8ftJk1xP/8NzPxfHk6K1X7p0CRQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -13607,36 +11857,12 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==", - "dev": true, - "dependencies": { - "repeating": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==", - "dev": true - }, "node_modules/individual": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz", "integrity": "sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g==", "dev": true }, - "node_modules/infinity-agent": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz", - "integrity": "sha512-CnfUJe5o2S9aAQWXGMhDZI4UL39MAJV3guOTfHHIdos4tuVHkl1j/J+1XLQn+CLIvqcpgQR/p+xXYXzcrhCe5w==", - "dev": true - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -13658,27 +11884,6 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "node_modules/inline-source-map": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.3.1.tgz", - "integrity": "sha512-RNlldBXZ7BBcVm3HjXIXiwKxih1lnuKbzeLBRDSB/qaqk8/g4JEZBjxpBQMhqEthQyGv7ycu8r/8PKGgBdIqrA==", - "dev": true, - "dependencies": { - "source-map": "~0.3.0" - } - }, - "node_modules/inline-source-map/node_modules/source-map": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz", - "integrity": "sha512-jz8leTIGS8+qJywWiO9mKza0hJxexdeIYXhDHw9avTQcXSNAGk3hiiRMpmI2Qf9dOrZDrDpgH9VNefzuacWC9A==", - "dev": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/inquirer": { "version": "8.1.5", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", @@ -13765,143 +11970,6 @@ "node": ">=8" } }, - "node_modules/insert-module-globals": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-6.6.3.tgz", - "integrity": "sha512-ryk8hTKUZCc300SPOOwx30WhE5oRUssPDVlIoO8vtoMNBy5HGeesVRl3HF7ra4ll42T0IdnwD9XR9svh6+RRhg==", - "dev": true, - "dependencies": { - "combine-source-map": "~0.6.1", - "concat-stream": "~1.4.1", - "is-buffer": "^1.1.0", - "JSONStream": "^1.0.3", - "lexical-scope": "^1.2.0", - "process": "~0.11.0", - "through2": "^1.0.0", - "xtend": "^4.0.0" - }, - "bin": { - "insert-module-globals": "bin/cmd.js" - } - }, - "node_modules/insert-module-globals/node_modules/combine-source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.6.1.tgz", - "integrity": "sha512-XKRNtuZRlVDTuSGKsfZpXYz80y0XDbYS4a+FzafTgmYHy/ckruFBx7Nd6WaQnFHVI3O6IseWVdXUvZutMpjSkQ==", - "dev": true, - "dependencies": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.5.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.4.2" - } - }, - "node_modules/insert-module-globals/node_modules/concat-stream": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", - "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.9", - "typedarray": "~0.0.5" - } - }, - "node_modules/insert-module-globals/node_modules/convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", - "dev": true - }, - "node_modules/insert-module-globals/node_modules/inline-source-map": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.5.0.tgz", - "integrity": "sha512-2WtHG0qX9OH9TVcxsLVfq3Tzr+qtL6PtWgoh0XAAKe4KkdA/57Q+OGJuRJHA4mZ2OZnkJ/ZAaXf9krLB12/nIg==", - "dev": true, - "dependencies": { - "source-map": "~0.4.0" - } - }, - "node_modules/insert-module-globals/node_modules/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 - }, - "node_modules/insert-module-globals/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/insert-module-globals/node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/insert-module-globals/node_modules/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, - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/insert-module-globals/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/insert-module-globals/node_modules/source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha512-Y8nIfcb1s/7DcobUz1yOO1GSp7gyL+D9zLHDehT7iRESqGSxjJ448Sg7rvfgsRJCnKLdSl11uGf0s9X80cH0/A==", - "dev": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/insert-module-globals/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/insert-module-globals/node_modules/through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "dependencies": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, "node_modules/internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -14272,25 +12340,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-my-ip-valid": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", - "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", - "dev": true - }, - "node_modules/is-my-json-valid": { - "version": "2.20.6", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", - "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", - "dev": true, - "dependencies": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^5.0.0", - "xtend": "^4.0.0" - } - }, "node_modules/is-nan": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", @@ -14373,15 +12422,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -14409,21 +12449,6 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", - "dev": true - }, - "node_modules/is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -14862,39 +12887,6 @@ "url": "https://bevry.me/fund" } }, - "node_modules/jade": { - "version": "0.26.3", - "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha512-mkk3vzUHFjzKjpCXeu+IjXeZD+QOTjUUdubgmHtHTDwvAO2ZTkMTTVrapts5CWz3JvJryh/4KWZpjeZrCepZ3A==", - "deprecated": "Jade has been renamed to pug, please install the latest version of pug instead of jade", - "dev": true, - "dependencies": { - "commander": "0.6.1", - "mkdirp": "0.3.0" - }, - "bin": { - "jade": "bin/jade" - } - }, - "node_modules/jade/node_modules/commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha512-0fLycpl1UMTGX257hRsu/arL/cUbcvQM4zMKwvLvzXtfdezIV4yotPS2dYtknF+NmEfWSoCEF6+hj9XLm/6hEw==", - "dev": true, - "engines": { - "node": ">= 0.4.x" - } - }, - "node_modules/jade/node_modules/mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/jake": { "version": "10.8.5", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", @@ -15249,12 +13241,6 @@ "node": ">= 10.13.0" } }, - "node_modules/jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", - "dev": true - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -15286,77 +13272,12 @@ "node": ">=4" } }, - "node_modules/js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", - "dev": true, - "dependencies": { - "xmlcreate": "^2.0.4" - } - }, "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, - "node_modules/jsdoc": { - "version": "3.6.11", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.11.tgz", - "integrity": "sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.9.4", - "@types/markdown-it": "^12.2.3", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "taffydb": "2.6.2", - "underscore": "~1.13.2" - }, - "bin": { - "jsdoc": "jsdoc.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/jsdoc/node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/jsdoc/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jsdoc/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -15386,15 +13307,6 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "node_modules/json-parse-helpfulerror": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", - "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==", - "dev": true, - "dependencies": { - "jju": "^1.1.0" - } - }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -15407,15 +13319,6 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "node_modules/json-stable-stringify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", - "integrity": "sha512-nKtD/Qxm7tWdZqJoldEC7fF0S41v0mWbeaXG3637stOWfyGxTgWTYE2wtfKmjzpvxv2MA2xzxsXOIiwUpkX6Qw==", - "dev": true, - "dependencies": { - "jsonify": "~0.0.0" - } - }, "node_modules/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", @@ -15451,65 +13354,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsonify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/jsonlint": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.3.tgz", - "integrity": "sha512-jMVTMzP+7gU/IyC6hvKyWpUU8tmTkK5b3BPNuMI9U8Sit+YAWLlZwB6Y6YrdCxfg2kNz05p3XY3Bmm4m26Nv3A==", - "dev": true, - "dependencies": { - "JSV": "^4.0.x", - "nomnom": "^1.5.x" - }, - "bin": { - "jsonlint": "lib/cli.js" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/jsonparse": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz", - "integrity": "sha512-fw7Q/8gFR8iSekUi9I+HqWIap6mywuoe7hQIg3buTVjuZgALKj4HAmm0X6f+TaL4c9NJbvyFQdaI2ppr5p6dnQ==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/JSONStream": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz", - "integrity": "sha512-l0NN3IcqrZfZBJp7JWDJIHsnPV7yzJWqsYxQzL8Fwdx1BmEMjLuvtYkv+P9pbvpyfP75/f4MeDZhWNU4is32uA==", - "dev": true, - "dependencies": { - "jsonparse": "0.0.5", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "index.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -15525,15 +13369,6 @@ "node": ">=0.6.0" } }, - "node_modules/JSV": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", - "integrity": "sha512-ZJ6wx9xaKJ3yFUhq5/sk82PJMuUyLk277I8mQeyDgCTjGdjWJIvPfaU5LIXaMuaN2UO1X3kZH4+lgphublZUHw==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/just-clone": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", @@ -15973,12 +13808,6 @@ "node": ">=10" } }, - "node_modules/kew": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/kew/-/kew-0.1.7.tgz", - "integrity": "sha512-TQRJfHoVm4f2exuRqjcpURhzGcC4GEIPyiLquo4mBfz0JgsVg19VeyTmKp6RKSOIhHQ6F4SgEhsnUlBduGV9Yw==", - "dev": true - }, "node_modules/keycode": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.1.tgz", @@ -16003,15 +13832,6 @@ "node": ">=0.10.0" } }, - "node_modules/klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.9" - } - }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -16043,23 +13863,6 @@ "url": "https://github.com/sindresorhus/ky?sponsor=1" } }, - "node_modules/labeled-stream-splicer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-1.0.2.tgz", - "integrity": "sha512-3KBjPRnXrYC5h2jEf/d6hO7Lcl+38QzRVTOyHA2sFzZVMYwsUFuejlrOMwAjmz13hVBr9ruDS1RwE4YEz8P58w==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "isarray": "~0.0.1", - "stream-splicer": "^1.1.0" - } - }, - "node_modules/labeled-stream-splicer/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, "node_modules/last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", @@ -16131,15 +13934,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lexical-scope": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", - "integrity": "sha512-ntJ8IcBCuKwudML7vAuT/L0aIMU0+9vO25K4CjLPYgzf1NZ0bAhJJBZrvkO+oUGgKcbdkH8UZdRsaEg+wULLRw==", - "dev": true, - "dependencies": { - "astw": "^2.0.0" - } - }, "node_modules/liftoff": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", @@ -16202,15 +13996,6 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, - "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" - } - }, "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -16311,87 +14096,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash._arraycopy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", - "integrity": "sha512-RHShTDnPKP7aWxlvXKiDT6IX2jCs6YZLCtNhOru/OX2Q/tzX295vVBK5oX1ECtN+2r86S0Ogy8ykP1sgCZAN0A==", - "dev": true - }, - "node_modules/lodash._arrayeach": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", - "integrity": "sha512-Mn7HidOVcl3mkQtbPsuKR0Fj0N6Q6DQB77CtYncZcJc0bx5qv2q4Gl6a0LC1AN+GSxpnBDNnK3CKEm9XNA4zqQ==", - "dev": true - }, - "node_modules/lodash._arraymap": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz", - "integrity": "sha512-IhRssF2bzQoFQ2Q5H1O52HuJY+OtcHDZekEhaMJ6RkUF+gpLlAsizSRsKp3Ho555ANRk69DFp5b4LOlym4S0bw==", - "dev": true - }, - "node_modules/lodash._baseassign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==", - "dev": true, - "dependencies": { - "lodash._basecopy": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, - "node_modules/lodash._baseclone": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", - "integrity": "sha512-1K0dntf2dFQ5my0WoGKkduewR6+pTNaqX03kvs45y7G5bzl4B3kTR4hDfJIc2aCQDeLyQHhS280tc814m1QC1Q==", - "dev": true, - "dependencies": { - "lodash._arraycopy": "^3.0.0", - "lodash._arrayeach": "^3.0.0", - "lodash._baseassign": "^3.0.0", - "lodash._basefor": "^3.0.0", - "lodash.isarray": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, "node_modules/lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", "dev": true }, - "node_modules/lodash._basedifference": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz", - "integrity": "sha512-4BcJlOv36b3v+kHdJWcgsDi96ns8neNLuDtbzzjW3+eh3XhFVmFPH2tu6GJK2e5eRYMQ8izHU35iAyNjRyDtCQ==", - "dev": true, - "dependencies": { - "lodash._baseindexof": "^3.0.0", - "lodash._cacheindexof": "^3.0.0", - "lodash._createcache": "^3.0.0" - } - }, - "node_modules/lodash._baseflatten": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz", - "integrity": "sha512-fESngZd+X4k+GbTxdMutf8ohQa0s3sJEHIcwtu4/LsIQ2JTDzdRxDCMQjW+ezzwRitLmHnacVVmosCbxifefbw==", - "dev": true, - "dependencies": { - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "node_modules/lodash._basefor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", - "integrity": "sha512-6bc3b8grkpMgDcVJv9JYZAk/mHgcqMljzm7OsbmcE2FGUMmmLQTPHlh/dFqR8LA0GQ7z4K67JSotVKu5058v1A==", - "dev": true - }, - "node_modules/lodash._baseindexof": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", - "integrity": "sha512-bSYo8Pc/f0qAkr8fPJydpJjtrHiSynYfYBjtANIgXv5xEf1WlTC63dIDlgu0s9dmTvzRu1+JJTxcIAHe+sH0FQ==", - "dev": true - }, "node_modules/lodash._basetostring": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", @@ -16404,38 +14114,6 @@ "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", "dev": true }, - "node_modules/lodash._bindcallback": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==", - "dev": true - }, - "node_modules/lodash._cacheindexof": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", - "integrity": "sha512-S8dUjWr7SUT/X6TBIQ/OYoCHo1Stu1ZRy6uMUSKqzFnZp5G5RyQizSm6kvxD2Ewyy6AVfMg4AToeZzKfF99T5w==", - "dev": true - }, - "node_modules/lodash._createassigner": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", - "integrity": "sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==", - "dev": true, - "dependencies": { - "lodash._bindcallback": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash.restparam": "^3.0.0" - } - }, - "node_modules/lodash._createcache": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", - "integrity": "sha512-ev5SP+iFpZOugyab/DEUQxUeZP5qyciVTlgQ1f4Vlw7VUcCD8fVnyIqVUEIaoFH9zjAqdgi69KiofzvVmda/ZQ==", - "dev": true, - "dependencies": { - "lodash._getnative": "^3.0.0" - } - }, "node_modules/lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", @@ -16448,22 +14126,6 @@ "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", "dev": true }, - "node_modules/lodash._pickbyarray": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz", - "integrity": "sha512-tHzBIfgugzI7HV0y8MJS1z/ryWDh8NyD6AV+so9vlplRnhD4qBuwoyDt7g241ad3F43YDFghCN+R3iaFd4Azvw==", - "dev": true - }, - "node_modules/lodash._pickbycallback": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz", - "integrity": "sha512-DVP27YmN0lB+j/Tgd/+gtxfmW/XihgWpQpHptBuwyp2fD9zEBRwwcnw6Qej16LUV8LRFuTqyoc0i6ON97d/C5w==", - "dev": true, - "dependencies": { - "lodash._basefor": "^3.0.0", - "lodash.keysin": "^3.0.0" - } - }, "node_modules/lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", @@ -16559,12 +14221,6 @@ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", "dev": true }, - "node_modules/lodash.istypedarray": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz", - "integrity": "sha512-lGWJ6N8AA3KSv+ZZxlTdn4f6A7kMfpJboeyvbFdE7IU9YAgweODqmOgdUHOA+c6lVWeVLysdaxciFXi+foVsWw==", - "dev": true - }, "node_modules/lodash.keys": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", @@ -16576,44 +14232,12 @@ "lodash.isarray": "^3.0.0" } }, - "node_modules/lodash.keysin": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", - "integrity": "sha512-YDB/5xkL3fBKFMDaC+cfGV00pbiJ6XoJIfRmBhv7aR6wWtbCW6IzkiWnTfkiHTF6ALD7ff83dAtB3OEaSoyQPg==", - "dev": true, - "dependencies": { - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "node_modules/lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==", - "dev": true - }, "node_modules/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 }, - "node_modules/lodash.omit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-3.1.0.tgz", - "integrity": "sha512-vC3fSzZDmPlwk+kCGYMQyUpPeRBgmOK/WrhmjlWVUjEch35gQR3iRbCV9rL7KgMHVeVhnq7A+TRrPvzvg67y9w==", - "dev": true, - "dependencies": { - "lodash._arraymap": "^3.0.0", - "lodash._basedifference": "^3.0.0", - "lodash._baseflatten": "^3.0.0", - "lodash._bindcallback": "^3.0.0", - "lodash._pickbyarray": "^3.0.0", - "lodash._pickbycallback": "^3.0.0", - "lodash.keysin": "^3.0.0", - "lodash.restparam": "^3.0.0" - } - }, "node_modules/lodash.pickby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", @@ -16651,16 +14275,6 @@ "lodash._reinterpolate": "^3.0.0" } }, - "node_modules/lodash.toplainobject": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz", - "integrity": "sha512-wMI0Ju1bvSmnBS3EcRRH/3zDnZOPpDtMtNDzbbNMKuTrEpALsf+sPyMeogmv63Y11qZQO7H1xFzohIEGRMjPYA==", - "dev": true, - "dependencies": { - "lodash._basecopy": "^3.0.0", - "lodash.keysin": "^3.0.0" - } - }, "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", @@ -16763,19 +14377,6 @@ "loose-envify": "cli.js" } }, - "node_modules/loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==", - "dev": true, - "dependencies": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/loupe": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", @@ -16908,38 +14509,6 @@ "node": ">=0.10.0" } }, - "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it-anchor": { - "version": "8.6.5", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.5.tgz", - "integrity": "sha512-PI1qEHHkTNWT+X6Ip9w+paonfIQ+QZP9sCeMYi47oqhH+EsW8CrJ8J7CzV19QVOj6il8ATGbK2nTECj22ZHGvQ==", - "dev": true, - "peerDependencies": { - "@types/markdown-it": "*", - "markdown-it": "*" - } - }, - "node_modules/markdown-it/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/markdown-table": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.2.tgz", @@ -16950,58 +14519,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/markdownlint": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.0.6.tgz", - "integrity": "sha512-2jxomIcTY+HWnrMWv7Q/T93d7yp4RXNGkoQXWq5II1TgyQj5pFDoB7HZSCX57ATk9zZTb1++jwXR3uHn6AKmew==", - "dev": true, - "dependencies": { - "markdown-it": "^4.2.2" - } - }, - "node_modules/markdownlint/node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "node_modules/markdownlint/node_modules/linkify-it": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz", - "integrity": "sha512-eGHwtlABkp1NOJSiKUNqBf3SYAS5jPHtvRXPAgNaQwTqmkTahjtiLH9NtxdR5IOPhNvwNMN/diswSfZKzUkhGg==", - "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" - } - }, - "node_modules/markdownlint/node_modules/markdown-it": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz", - "integrity": "sha512-Rl8dHHeLuAh3E72OPY0tY7CLvlxgHiLhlshIYswAAabAg4YDBLa6e/LTgNkkxBO2K61ESzoquPQFMw/iMrT1PA==", - "dev": true, - "dependencies": { - "argparse": "~1.0.2", - "entities": "~1.1.1", - "linkify-it": "~1.2.0", - "mdurl": "~1.0.0", - "uc.micro": "^1.0.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/marked": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz", - "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==", - "dev": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, "node_modules/marky": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.4.tgz", @@ -17050,17 +14567,6 @@ "node": ">=0.10.0" } }, - "node_modules/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, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "node_modules/mdast-util-definitions": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", @@ -17403,79 +14909,6 @@ "node": ">=4.3.0 <5.0.0 || >=5.10" } }, - "node_modules/meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/meow/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/meow/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/meow/node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", - "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/meow/node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", - "dev": true, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -18175,25 +15608,6 @@ "node": ">=0.10.0" } }, - "node_modules/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, - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, "node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -18252,18 +15666,6 @@ "dom-walk": "^0.1.0" } }, - "node_modules/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 - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -18353,111 +15755,6 @@ "url": "https://opencollective.com/mochajs" } }, - "node_modules/mocha-phantomjs": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/mocha-phantomjs/-/mocha-phantomjs-3.6.0.tgz", - "integrity": "sha512-siI6m2uw3Xyjruz9eEP8JTVHOtnOxdmnEqXM0IrOt3Nbw4oPJw6u8Q6MG6hqnbH9fJ3i60F3bYlmSEbgwuNsQw==", - "dev": true, - "dependencies": { - "commander": "~2.0.0", - "mocha": "~1.20.1" - }, - "bin": { - "mocha-phantomjs": "bin/mocha-phantomjs" - }, - "peerDependencies": { - "phantomjs": "1.9.1 - 1.9.7-15" - } - }, - "node_modules/mocha-phantomjs/node_modules/diff": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.7.tgz", - "integrity": "sha512-0bTLzyr1S59cPsgAD/lR+ivvHTbgPb+k/mUR6WGqma1J6QDU+kUegI8uQFuH/cMUNK7JGN3Tk1Y5Jf2MO85WrA==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/mocha-phantomjs/node_modules/glob": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", - "integrity": "sha512-WPaLsMHD1lYEqAmIQI6VOJSPwuBdGShDWnj1yUo0vQqEO809R8W3LM9OVU13CnnDhyv/EiNwOtxEW74SmrzS6w==", - "dev": true, - "dependencies": { - "graceful-fs": "~2.0.0", - "inherits": "2", - "minimatch": "~0.2.11" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha-phantomjs/node_modules/graceful-fs": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "integrity": "sha512-hcj/NTUWv+C3MbqrVb9F+aH6lvTwEHJdx2foBxlrVq5h6zE8Bfu4pv4CAAqbDcZrw/9Ak5lsRXlY9Ao8/F0Tuw==", - "deprecated": "please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/mocha-phantomjs/node_modules/growl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz", - "integrity": "sha512-VWv7s1EI41AG2LiCr7uAuxWikLDN1SQOuEUc37d/P34NAIIYgkvWYngNw0d9d9iCrDFL0SYCE9UQpxhIjjtuLg==", - "dev": true - }, - "node_modules/mocha-phantomjs/node_modules/lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==", - "dev": true - }, - "node_modules/mocha-phantomjs/node_modules/minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha512-zZ+Jy8lVWlvqqeM8iZB7w7KmQkoJn8djM585z88rywrEbzoqawVa9FR5p2hwD+y74nfuKOjmNvi9gtWJNLqHvA==", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", - "dev": true, - "dependencies": { - "lru-cache": "2", - "sigmund": "~1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha-phantomjs/node_modules/mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true - }, - "node_modules/mocha-phantomjs/node_modules/mocha": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.20.1.tgz", - "integrity": "sha512-25Nq3BuIYCy80uEix+hBlZcr/gnLzpcYqfsaPAxZm2qbMFmed8I3nP8N05KagK4BTkGYUvsRJ47istvRqFO8fw==", - "deprecated": "Mocha v1.x is no longer supported.", - "dev": true, - "dependencies": { - "commander": "2.0.0", - "debug": "*", - "diff": "1.0.7", - "glob": "3.2.3", - "growl": "1.7.x", - "jade": "0.26.3", - "mkdirp": "0.3.5" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 0.4.x" - } - }, "node_modules/mocha/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -18742,131 +16039,6 @@ "node": ">=10" } }, - "node_modules/module-deps": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-3.9.1.tgz", - "integrity": "sha512-EbWWlSGaCVidEsLsSzkY6l/jm0IcGDSQ8tGwtjM8joTrxqxP0om02Px9Np8D7FMZ/vZFdsOGbio+WqkKQxYuTA==", - "dev": true, - "dependencies": { - "browser-resolve": "^1.7.0", - "concat-stream": "~1.4.5", - "defined": "^1.0.0", - "detective": "^4.0.0", - "duplexer2": "0.0.2", - "inherits": "^2.0.1", - "JSONStream": "^1.0.3", - "parents": "^1.0.0", - "readable-stream": "^1.1.13", - "resolve": "^1.1.3", - "stream-combiner2": "~1.0.0", - "subarg": "^1.0.0", - "through2": "^1.0.0", - "xtend": "^4.0.0" - }, - "bin": { - "module-deps": "bin/cmd.js" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/module-deps/node_modules/concat-stream": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", - "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.9", - "typedarray": "~0.0.5" - } - }, - "node_modules/module-deps/node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/module-deps/node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "dev": true, - "dependencies": { - "readable-stream": "~1.1.9" - } - }, - "node_modules/module-deps/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/module-deps/node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/module-deps/node_modules/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, - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/module-deps/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/module-deps/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/module-deps/node_modules/through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "dependencies": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, - "node_modules/module-not-found-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha512-pEk4ECWQXV6z2zjhRZUongnLJNUeGQJ3w6OQ5ctGwD+i5o93qjRQUk2Rt6VdNeu3sEP0AB4LcfvdebpxBRVr4g==", - "dev": true - }, "node_modules/morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -19070,14 +16242,6 @@ "node": ">=0.10.0" } }, - "node_modules/natives": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", - "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", - "deprecated": "This module relies on Node.js's internals and will break at some point. Do not use it, and update to graceful-fs@4.x.", - "dev": true, - "optional": true - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -19107,15 +16271,6 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node_modules/nested-error-stacks": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", - "integrity": "sha512-o32anp9JA7oezPOFSfG2BBXSdHepOm5FpJvwxHWDtfJ3Bg3xdi68S6ijPlEOfUg6quxZWyvJM+8fHk1yMDKspA==", - "dev": true, - "dependencies": { - "inherits": "~2.0.1" - } - }, "node_modules/next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -19200,68 +16355,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, - "node_modules/node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==", - "deprecated": "Use uuid module instead", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/nomnom": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", - "integrity": "sha512-5s0JxqhDx9/rksG2BTMVN1enjWSvPidpoSgViZU4ZXULyTe+7jxcCRLB6f42Z0l1xYJpleCBtSyY6Lwg3uu5CQ==", - "deprecated": "Package no longer supported. Contact support@npmjs.com for more info.", - "dev": true, - "dependencies": { - "chalk": "~0.4.0", - "underscore": "~1.6.0" - } - }, - "node_modules/nomnom/node_modules/ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha512-3iF4FIKdxaVYT3JqQuY3Wat/T2t7TRbbQ94Fu50ZUCbLy4TFbTzr90NOHQodQkNqmeEGCw8WbeP78WNi6SKYUA==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/nomnom/node_modules/chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha512-sQfYDlfv2DGVtjdoQqxS0cEZDroyG8h6TamA6rvxwlrU5BaSLDx9xhatBYl2pxZ7gmpNaPFVwBtdGdu5rQ+tYQ==", - "dev": true, - "dependencies": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/nomnom/node_modules/strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha512-behete+3uqxecWlDAm5lmskaSaISA+ThQ4oNNBDTBJt0x2ppR6IPqfZNuj6BLaLJ/Sji4TPZlcRyOis8wXQTLg==", - "dev": true, - "bin": { - "strip-ansi": "cli.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/nomnom/node_modules/underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ==", - "dev": true - }, "node_modules/nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -19274,12 +16367,6 @@ "nopt": "bin/nopt.js" } }, - "node_modules/nopt-usage": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/nopt-usage/-/nopt-usage-0.1.0.tgz", - "integrity": "sha512-Tg2sISrWBbSsCRqpEMmdxn3KZfacrd0N2NYpZQIq0MHxGHMjwzYlxeB9pVIom/g7CBK28atDUQsTlOfG0wOsNA==", - "dev": true - }, "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -19334,43 +16421,6 @@ "node": ">= 0.10" } }, - "node_modules/npm-license": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/npm-license/-/npm-license-0.2.3.tgz", - "integrity": "sha512-Sm6zqTVReBGe1C5A3Vr7pqYFmawM3oF/MKhhk0LRAOZPEOygr96KkiJ5P0ZQMDP3F7HRW6zyy7gxIIos+6foww==", - "dev": true, - "dependencies": { - "mkdirp": "~0.5.0", - "nopt": "~3.0.1", - "nopt-usage": "^0.1.0", - "package-license": "~0.1.1", - "pkginfo": "^0.3.0", - "read-installed": "~3.1.3", - "treeify": "~1.0.1", - "underscore": "~1.4.4" - }, - "bin": { - "npm-license": "bin/npm-license" - } - }, - "node_modules/npm-license/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/npm-license/node_modules/underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==", - "dev": true - }, "node_modules/npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -19392,73 +16442,6 @@ "node": ">=4" } }, - "node_modules/npmconf": { - "version": "0.0.24", - "resolved": "https://registry.npmjs.org/npmconf/-/npmconf-0.0.24.tgz", - "integrity": "sha512-LX0bX+RmuBuEITg26i7+dx+d9cfYU+giB7eOiSkT5IwvuAzzIx02u4GXwSC3jsQMDMb/kXC57R8tybRSVYfbWw==", - "deprecated": "this package has been reintegrated into npm and is now out of date with respect to npm", - "dev": true, - "dependencies": { - "config-chain": "~1.1.1", - "inherits": "~1.0.0", - "ini": "~1.1.0", - "mkdirp": "~0.3.3", - "nopt": "2", - "once": "~1.1.1", - "osenv": "0.0.3", - "semver": "~1.1.0" - } - }, - "node_modules/npmconf/node_modules/inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha512-Al67oatbRSo3RV5hRqIoln6Y5yMVbJSIn4jEJNL7VCImzq/kLr7vvb6sFRJXqr8rpHc/2kJOM+y0sPKN47VdzA==", - "dev": true - }, - "node_modules/npmconf/node_modules/ini": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.1.0.tgz", - "integrity": "sha512-B6L/jfyFRcG2dqKiHggWnfby52Iy07iabE4F6srQAr/OmVKBRE5uU+B5MQ+nQ7NiYnjz93gENh1GhqHzpDgHgA==", - "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/npmconf/node_modules/mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true - }, - "node_modules/npmconf/node_modules/nopt": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz", - "integrity": "sha512-gIOTA/uJuhPwFqp+spY7VQ1satbnGlD+iQVZxI18K6hs8Evq4sX81Ml7BB5byP/LsbR2yBVtmvdEmhi7evJ6Aw==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/npmconf/node_modules/once": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/once/-/once-1.1.1.tgz", - "integrity": "sha512-frdJr++QKEg4+JylTX+NNLgSoO6M2pDNYOOXe4WGIYKKBADBI9nU3oa06y4D4FpAJ3obAsjExeBOnscYJB9Blw==", - "dev": true - }, - "node_modules/npmconf/node_modules/semver": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-1.1.4.tgz", - "integrity": "sha512-9causpLEkYDrfTz7cprleLz9dnlb0oKsKRHl33K92wJmXLhVc2dGlrQGJT/sjtLOAyuoQZl+ClI77+lnvzPSKg==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -19753,15 +16736,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/open": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/open/-/open-0.0.3.tgz", - "integrity": "sha512-Vm6nsJHcKV8kdOtHESAFAymOOf1VlKrttpwTqtLxvxRDIh8PSw4lWq5qk88QkAvNwnkv/1dNi2lvedhmam/ggw==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -19792,24 +16766,6 @@ "node": ">=4" } }, - "node_modules/optimist": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", - "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", - "dev": true, - "dependencies": { - "wordwrap": "~0.0.2" - } - }, - "node_modules/optimist/node_modules/wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -19936,12 +16892,6 @@ "readable-stream": "^2.0.1" } }, - "node_modules/os-browserify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz", - "integrity": "sha512-aZicJZccvxWOZ0Bja2eAch2L8RIJWBuRYmM8Gwl/JjNtRltH0Itcz4eH/ESyuIWfse8cc93ZCf0XrzhXK2HEDA==", - "dev": true - }, "node_modules/os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -19972,12 +16922,6 @@ "node": ">=0.10.0" } }, - "node_modules/osenv": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.0.3.tgz", - "integrity": "sha512-VBk1bfdaO4gh3OWO8LBuDY2alp0buL8YzQ6t13xyc8PQPrnUg5AgQvINQx3UkS4dom8UGCL597q4Y2+M4TPvmw==", - "dev": true - }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -20038,18 +16982,6 @@ "node": ">=4" } }, - "node_modules/package-license": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/package-license/-/package-license-0.1.2.tgz", - "integrity": "sha512-Q5zmx+M9ZJneMpYS6MlYL77gqeMYWuyErXMnQ/83WCztmYQD7Z0U9XGLvX9OKFFXwRj2NzdzlM0y9Jzcww2O1Q==", - "dev": true - }, - "node_modules/pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", - "dev": true - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -20062,28 +16994,6 @@ "node": ">=6" } }, - "node_modules/parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==", - "dev": true, - "dependencies": { - "path-platform": "~0.11.15" - } - }, - "node_modules/parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dev": true, - "dependencies": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", @@ -20181,12 +17091,6 @@ "node": ">=0.10.0" } }, - "node_modules/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 - }, "node_modules/path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", @@ -20211,12 +17115,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -20231,15 +17129,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "node_modules/path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", @@ -20307,22 +17196,6 @@ "through": "~2.3" } }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dev": true, - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -20335,239 +17208,6 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, - "node_modules/phantomjs": { - "version": "1.9.7-15", - "resolved": "https://registry.npmjs.org/phantomjs/-/phantomjs-1.9.7-15.tgz", - "integrity": "sha512-s4PSN1L0iVwgv9ZkrSKcfojyPAtwGWhXxjn2p1P/ljuw3cx+FW3hKP00x247mIYbKeKSMylOd4euDQOMpUIAsg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "adm-zip": "0.2.1", - "kew": "~0.1.7", - "mkdirp": "0.3.5", - "ncp": "0.4.2", - "npmconf": "0.0.24", - "progress": "^1.1.5", - "request": "2.36.0", - "request-progress": "^0.3.1", - "rimraf": "~2.2.2", - "which": "~1.0.5" - }, - "bin": { - "phantomjs": "bin/phantomjs" - } - }, - "node_modules/phantomjs/node_modules/asn1": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", - "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.4.9" - } - }, - "node_modules/phantomjs/node_modules/assert-plus": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", - "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/phantomjs/node_modules/async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==", - "dev": true, - "optional": true - }, - "node_modules/phantomjs/node_modules/aws-sign2": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", - "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", - "dev": true, - "optional": true, - "engines": { - "node": "*" - } - }, - "node_modules/phantomjs/node_modules/combined-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", - "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", - "dev": true, - "optional": true, - "dependencies": { - "delayed-stream": "0.0.5" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/phantomjs/node_modules/delayed-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", - "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/phantomjs/node_modules/forever-agent": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", - "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/phantomjs/node_modules/form-data": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", - "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", - "dev": true, - "optional": true, - "dependencies": { - "async": "~0.9.0", - "combined-stream": "~0.0.4", - "mime": "~1.2.11" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/phantomjs/node_modules/hawk": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.0.0.tgz", - "integrity": "sha512-Sg+VzrI7TjUomO0rjD6UXawsj50ykn5sB/xKNW/IenxzRVyw/wt9A2FLzYpGL/r0QG5hyXY8nLx/2m8UutoDcg==", - "deprecated": "This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", - "dev": true, - "optional": true, - "dependencies": { - "boom": "0.4.x", - "cryptiles": "0.2.x", - "hoek": "0.9.x", - "sntp": "0.2.x" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/phantomjs/node_modules/http-signature": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", - "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", - "dev": true, - "optional": true, - "dependencies": { - "asn1": "0.1.11", - "assert-plus": "^0.1.5", - "ctype": "0.5.3" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/phantomjs/node_modules/mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", - "dev": true - }, - "node_modules/phantomjs/node_modules/mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true - }, - "node_modules/phantomjs/node_modules/oauth-sign": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", - "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", - "dev": true, - "optional": true, - "engines": { - "node": "*" - } - }, - "node_modules/phantomjs/node_modules/progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/phantomjs/node_modules/qs": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", - "integrity": "sha512-kN+yNdAf29Jgp+AYHUmC7X4QdJPR8czuMWLNLc0aRxkQ7tB3vJQEONKKT9ou/rW7EbqVec11srC9q9BiVbcnHA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/phantomjs/node_modules/request": { - "version": "2.36.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.36.0.tgz", - "integrity": "sha512-iVii/ruMH9i8k++HYYPqi+nb1Pbgz7UOTGbFEiyhl7uDN8PhyFV2lGJa8XLIUS5tyt5scERcLkwqvCNF84Vv2Q==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "dependencies": { - "forever-agent": "~0.5.0", - "json-stringify-safe": "~5.0.0", - "mime": "~1.2.9", - "node-uuid": "~1.4.0", - "qs": "~0.6.0" - }, - "optionalDependencies": { - "aws-sign2": "~0.5.0", - "form-data": "~0.1.0", - "hawk": "~1.0.0", - "http-signature": "~0.10.0", - "oauth-sign": "~0.3.0", - "tough-cookie": ">=0.12.0", - "tunnel-agent": "~0.4.0" - } - }, - "node_modules/phantomjs/node_modules/rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", - "dev": true, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/phantomjs/node_modules/tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", - "dev": true, - "optional": true, - "engines": { - "node": "*" - } - }, - "node_modules/phantomjs/node_modules/which": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", - "dev": true, - "bin": { - "which": "bin/which" - } - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -20712,15 +17352,6 @@ "node": ">=8" } }, - "node_modules/pkginfo": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", - "integrity": "sha512-yO5feByMzAp96LtP58wvPKSbaKAi/1C4kV9XpTctr6EepnP6F33RBNOiVrdz9BrPA98U2BMFsTNHo44TWcbQ2A==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", @@ -20748,28 +17379,6 @@ "node": ">=0.10.0" } }, - "node_modules/portfinder": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-0.2.1.tgz", - "integrity": "sha512-U7dHe7mfMMP5cIwbqBHh/likunxAEiBsQLiThUWjyeRK6/C3um2uk+VGiekUW8q3h+s793gdNfagCM3aaXMeOg==", - "dev": true, - "dependencies": { - "mkdirp": "0.0.x" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/portfinder/node_modules/mkdirp": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.0.7.tgz", - "integrity": "sha512-r4Ml2CH2Kl4B0+Lwq1SVru0vjMxdtR+UEb938WTQcsnU+EJz8dUV/HY0LTZh466nUSljia9cvqW3LZLWs3l8LQ==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -20813,15 +17422,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", @@ -20927,12 +17527,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, "node_modules/protocols": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz", @@ -20957,23 +17551,6 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, - "node_modules/proxyquire": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-1.8.0.tgz", - "integrity": "sha512-mZZq4F50qaBkngvlf9paNfaSb5gtJ0mFPnBjda4NxCpXpMAaVfSLguRr9y2KXF6koOSBf4AanD2inuEQw3aCcA==", - "dev": true, - "dependencies": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.0", - "resolve": "~1.1.7" - } - }, - "node_modules/proxyquire/node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", - "dev": true - }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -21007,26 +17584,6 @@ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "dependencies": { - "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" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -21200,15 +17757,6 @@ "node": ">=0.4.x" } }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -21236,16 +17784,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/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, - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -21274,121 +17812,6 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "node_modules/read-all-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", - "integrity": "sha512-DI1drPHbmBcUDWrJ7ull/F2Qb8HkwBncVx8/RpKYFSIACYaVRQReISYPdZz/mt1y1+qMCOrfReTopERmaxtP6w==", - "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-installed": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-3.1.5.tgz", - "integrity": "sha512-XxD5VDz32T6rLCFfYElTif8/lkqcs9y51Gs2r30rAfT7LUGzJWaXLrwvn6fXkDsTzGcPr7Pj8CggOxwTxl/ozQ==", - "dev": true, - "dependencies": { - "debuglog": "^1.0.1", - "read-package-json": "1", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - }, - "optionalDependencies": { - "graceful-fs": "2 || 3" - } - }, - "node_modules/read-installed/node_modules/graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "optional": true, - "dependencies": { - "natives": "^1.1.3" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/read-installed/node_modules/semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-package-json": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-1.3.3.tgz", - "integrity": "sha512-9bayCl9cbXy3AL0qXhLQ0vliEgpzUVeLegSOrde3ujTHy2W18UsJiMUXEWkjbBB4ZnJzZPVuo2vAW62j4gY7gg==", - "dev": true, - "dependencies": { - "glob": "^5.0.3", - "json-parse-helpfulerror": "^1.0.2", - "normalize-package-data": "^1.0.0" - }, - "optionalDependencies": { - "graceful-fs": "2 || 3" - } - }, - "node_modules/read-package-json/node_modules/glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", - "dev": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/read-package-json/node_modules/graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "optional": true, - "dependencies": { - "natives": "^1.1.3" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/read-package-json/node_modules/normalize-package-data": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-1.0.3.tgz", - "integrity": "sha512-pyPVJAzFiaioifPIsJBEoKJ9YcPHz7UhckZ7wqhBztLLCu6NozkIDrN+frzrCwjXtfunXfaMWIDtcDhnbO8fWA==", - "dev": true, - "dependencies": { - "github-url-from-git": "^1.3.0", - "github-url-from-username-repo": "^1.0.0", - "semver": "2 || 3 || 4" - } - }, - "node_modules/read-package-json/node_modules/semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/read-pkg": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", @@ -21593,39 +18016,6 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "node_modules/readable-wrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/readable-wrap/-/readable-wrap-1.0.0.tgz", - "integrity": "sha512-/8n0Mr10S+HGKFygQ42Z40JIXwafPH3A72pwmlNClThgsImV5LJJiCue5Je1asxwY082sYxq/+kTxH6nTn0w3g==", - "dev": true, - "dependencies": { - "readable-stream": "^1.1.13-1" - } - }, - "node_modules/readable-wrap/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/readable-wrap/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/readable-wrap/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, "node_modules/readdir-glob": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", @@ -21635,18 +18025,6 @@ "minimatch": "^3.0.4" } }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "dev": true, - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -21659,46 +18037,6 @@ "node": ">=8.10.0" } }, - "node_modules/readline2": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz", - "integrity": "sha512-qs8GGG+hLGMaDOGjd+mDglDoYcHDkjIY7z5RU0/ApsGT0qypyrWskNeemUqD+UxIXiZoMYT5aLwGp4ehoyZhIg==", - "dev": true, - "dependencies": { - "mute-stream": "0.0.4", - "strip-ansi": "^2.0.1" - } - }, - "node_modules/readline2/node_modules/ansi-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", - "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readline2/node_modules/mute-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz", - "integrity": "sha512-amvrY4m/7oZamehMoFi1tbwU/kXbVvRTGM2S7F+PZi3n51Jx+9AcSQ3EQsag3tR+hS2higfgOP/Kl8kri/X52A==", - "dev": true - }, - "node_modules/readline2/node_modules/strip-ansi": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", - "integrity": "sha512-2h8q2CP3EeOhDJ+jd932PRMpa3/pOJFGoF22J1U/DNbEK2gSW2DqeF46VjCXsSQXhC+k/l8/gaaRBQKL6hUPfQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^1.0.0" - }, - "bin": { - "strip-ansi": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -21735,19 +18073,6 @@ "node": "*" } }, - "node_modules/redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==", - "dev": true, - "dependencies": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -22113,15 +18438,6 @@ "node": ">= 6" } }, - "node_modules/request-progress": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-0.3.1.tgz", - "integrity": "sha512-+IAgzH8yWAEgHjOOQzYEqRm0BpNlE6xFgsziGMiTxxMhrkBcCOe9bNWH7bDR+XtHToUMgCZlDgLqjk6cAP/+Ig==", - "dev": true, - "dependencies": { - "throttleit": "~0.0.2" - } - }, "node_modules/request/node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", @@ -22155,15 +18471,6 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, - "node_modules/requizzle": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", - "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -22227,12 +18534,6 @@ "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, - "node_modules/response-stream": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/response-stream/-/response-stream-0.0.0.tgz", - "integrity": "sha512-tWH3QWqkXv7AgYRXidIhPKO1SqPix2E0gM3x/vxf60LHQHWNS8AVrB3RnYexPAoo5dOc0bGzDlUgtsBvV3CWLA==", - "dev": true - }, "node_modules/responselike": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", @@ -22279,34 +18580,12 @@ "node": ">=0.12" } }, - "node_modules/rewire": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/rewire/-/rewire-2.5.2.tgz", - "integrity": "sha512-9wOlgRHTOzUv5dQO2XD2qWob+7yi/QXh7SSwLJW5wMAkAdkYuaCtcPuLAXUTllK0MjSvtpxUqAWMuSrrdt9VNw==", - "dev": true - }, "node_modules/rfdc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", "dev": true }, - "node_modules/rfile": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rfile/-/rfile-1.0.0.tgz", - "integrity": "sha512-aNeTpY8g6DYmqPvakau22B0SipQTskO8FtYXzn8qg4X4bN9ExIH8VAhq/L9w7N8HvESYeSSwk3e4GmW+rLLAxQ==", - "dev": true, - "dependencies": { - "callsite": "~1.0.0", - "resolve": "~0.3.0" - } - }, - "node_modules/rfile/node_modules/resolve": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.3.1.tgz", - "integrity": "sha512-mxx/I/wLjxtryDBtrrb0ZNzaYERVWaHpJ0W0Arm8N4l8b+jiX/U5yKcsj0zQpF9UuKN1uz80EUTOudON6OPuaQ==", - "dev": true - }, "node_modules/rgb2hex": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.5.tgz", @@ -22328,54 +18607,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/ruglify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ruglify/-/ruglify-1.0.0.tgz", - "integrity": "sha512-XfRj1YJdm/gnZNvmpQ5L+2YGRHglDGMPgJRbitgCxC3GzKVQF/t+ij1aNcNg2AnEXGtLHJDwoSWrAq3TUm0EVg==", - "dev": true, - "dependencies": { - "rfile": "~1.0", - "uglify-js": "~2.2" - } - }, - "node_modules/ruglify/node_modules/source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", - "dev": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ruglify/node_modules/uglify-js": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", - "integrity": "sha512-viLk+/8G0zm2aKt1JJAVcz5J/5ytdiNaIsKgrre3yvSUjwVG6ZUujGH7E2TiPigZUwLYCe7eaIUEP2Zka2VJPA==", - "dev": true, - "dependencies": { - "optimist": "~0.3.5", - "source-map": "~0.1.7" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -22394,12 +18625,6 @@ "individual": "^2.0.0" } }, - "node_modules/rx": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz", - "integrity": "sha512-u5qvfulb7NXoY/+OE28920WEgFi6aiDjf5iF9rA2f9tBXejLgTLd0WxkclvIQWjFFHfNJlb7pSTsrjgiDh+Uug==", - "dev": true - }, "node_modules/rxjs": { "version": "7.5.5", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", @@ -22502,17 +18727,6 @@ "ajv": "^6.9.1" } }, - "node_modules/script-injector": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/script-injector/-/script-injector-0.1.7.tgz", - "integrity": "sha512-0iW1D9UKsOPNUVBHvR76KePNS5TamEBN38bT5k7BqsXItsyV5oJTZbVsvOF3YS2xJ7GB7pszmgfDFJbIgHmrDQ==", - "dev": true, - "dependencies": { - "duplexer": "~0.1.1", - "through": "~2.3.4", - "trumpet": "~1.6.3" - } - }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -22760,35 +18974,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "node_modules/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, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/shallow-copy": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", - "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==", - "dev": true - }, - "node_modules/shasum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", - "integrity": "sha512-UTzHm/+AzKfO9RgPgRpDIuMSNie1ubXRaljjlhFMNGYoG7z+rm9AHLPMf70R7887xboDH9Q+5YQbWKObFHEAtw==", - "dev": true, - "dependencies": { - "json-stable-stringify": "~0.0.0", - "sha.js": "~2.4.4" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -22810,48 +18995,6 @@ "node": ">=8" } }, - "node_modules/shell-quote": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-0.0.1.tgz", - "integrity": "sha512-uEWz7wa9vnCi9w4mvKZMgbHFk3DCKjLQlZcy0tJxUH4NwZjRrPPHXAYIEt2TmJs600Dcgj0Z3fZLZKVPVdGNbQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha512-Ny0KN4dyT8ZSCE0frtcbAJGoM/HTArpyPkeli1/00aYfm0sbD/Gk/4x7N2DP9QKGpBsiQH7n6rpm1L79RtviEQ==", - "dev": true, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/shelljs-nodecli": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shelljs-nodecli/-/shelljs-nodecli-0.1.1.tgz", - "integrity": "sha512-/e+APCWKKW9A8YMHKgDzhWQ21zPuDLjn6ATBczxbp6uUeiCSwvw95ynKAjMsRd1yrd5dlCkMKJoc/Lpwrt2w+A==", - "dev": true, - "dependencies": { - "shelljs": "~0.2" - } - }, - "node_modules/shelljs-nodecli/node_modules/shelljs": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz", - "integrity": "sha512-LQiM15qPbSyzHDFfI4v7EVhjBXG5PUAKWVBnVMBXwdlQSHZtzKYeKGzDHBIqpenPrCsPWqBSOF5o7oSvSfX+CA==", - "dev": true, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -22866,12 +19009,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", - "dev": true - }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -22997,15 +19134,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -23211,20 +19339,6 @@ "urix": "^0.1.0" } }, - "node_modules/sntp": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", - "integrity": "sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==", - "deprecated": "This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", - "dev": true, - "optional": true, - "dependencies": { - "hoek": "0.9.x" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/socket.io": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", @@ -23421,21 +19535,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "node_modules/sse-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/sse-stream/-/sse-stream-0.0.4.tgz", - "integrity": "sha512-rnDUubW7a4CZAB5D0r2OtFU/zvY05MoNGHMX6deAYK0wWaizrNcHzimf+Nk5y0sqntGAPpWEnIopWrrAf2TBVg==", - "dev": true, - "dependencies": { - "through": "~2.2.7" - } - }, - "node_modules/sse-stream/node_modules/through": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", - "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", - "dev": true - }, "node_modules/sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", @@ -23592,40 +19691,6 @@ "node": ">= 0.6" } }, - "node_modules/stream-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-1.0.0.tgz", - "integrity": "sha512-e+V5xc4LlkOiRr64kZTUdb11exsbpSnwb9uwmXaHeDXCpfHg7vaefMJOxi21Pe74ZOqjZ87blBcqqpNAM4Ku0g==", - "dev": true, - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "^1.0.27-1" - } - }, - "node_modules/stream-browserify/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/stream-browserify/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/stream-browserify/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, "node_modules/stream-buffers": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", @@ -23644,80 +19709,6 @@ "duplexer": "~0.1.1" } }, - "node_modules/stream-combiner2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.0.2.tgz", - "integrity": "sha512-7DO1SfBVnyIyo9ytUjSyVojT5bp1ZY6h3pj7HUs6PwcRSd/r8mBOHbRwYC7nbHRakKzMKyNp5HWJRv4GgVherA==", - "dev": true, - "dependencies": { - "duplexer2": "~0.0.2", - "through2": "~0.5.1" - } - }, - "node_modules/stream-combiner2/node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "dev": true, - "dependencies": { - "readable-stream": "~1.1.9" - } - }, - "node_modules/stream-combiner2/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/stream-combiner2/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/stream-combiner2/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/stream-combiner2/node_modules/through2": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", - "integrity": "sha512-zexCrAOTbjkBCXGyozn7hhS3aEaqdrc59mAD2E3dKYzV1vFuEGQ1hEDJN2oQMQFwy4he2zyLqPZV+AlfS8ZWJA==", - "dev": true, - "dependencies": { - "readable-stream": "~1.0.17", - "xtend": "~3.0.0" - } - }, - "node_modules/stream-combiner2/node_modules/through2/node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/stream-combiner2/node_modules/xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, "node_modules/stream-exhaust": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", @@ -23730,54 +19721,6 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, - "node_modules/stream-splicer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-1.3.2.tgz", - "integrity": "sha512-nmUMEbdm/sZYqe9dZs7mqJvTYpunsDbIWI5FiBCMc/hMVd6vwzy+ITmo7C3gcLYqrn+uQ1w+EJwooWvJ997JAA==", - "dev": true, - "dependencies": { - "indexof": "0.0.1", - "inherits": "^2.0.1", - "isarray": "~0.0.1", - "readable-stream": "^1.1.13-1", - "readable-wrap": "^1.0.0", - "through2": "^1.0.0" - } - }, - "node_modules/stream-splicer/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/stream-splicer/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/stream-splicer/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/stream-splicer/node_modules/through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "dependencies": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, "node_modules/streamroller": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.4.tgz", @@ -23867,13 +19810,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/stringstream": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", - "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", - "dev": true, - "optional": true - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -23913,42 +19849,6 @@ "node": ">=0.10.0" } }, - "node_modules/strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==", - "dev": true, - "dependencies": { - "get-stdin": "^4.0.1" - }, - "bin": { - "strip-indent": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", - "dev": true, - "bin": { - "strip-json-comments": "cli.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", - "dev": true, - "dependencies": { - "minimist": "^1.1.0" - } - }, "node_modules/suffix": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", @@ -23994,15 +19894,6 @@ "es6-symbol": "^3.1.1" } }, - "node_modules/syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", - "dev": true, - "dependencies": { - "acorn-node": "^1.2.0" - } - }, "node_modules/table": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", @@ -24041,12 +19932,6 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, - "node_modules/taffydb": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", - "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", - "dev": true - }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -24298,12 +20183,6 @@ "url": "https://bevry.me/fund" } }, - "node_modules/throttleit": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", - "integrity": "sha512-HtlTFeyYs1elDM2txiIGsdXHaq8kffVaZH/QEBRbo95zQqzlsBx5ELKhkPOZVad9OK9oxzwx6UrQN8Vfh/+yag==", - "dev": true - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -24362,27 +20241,6 @@ "node": ">=0.10.0" } }, - "node_modules/timed-out": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", - "integrity": "sha512-pqqJOi1rF5zNs/ps4vmbE4SFCrM4iR7LW+GHAsHqO/EumqbIWceioevYLM5xZRgQSH6gFgL9J/uB7EcJhQ9niQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==", - "dev": true, - "dependencies": { - "process": "~0.11.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", @@ -24454,13 +20312,6 @@ "node": ">=4" } }, - "node_modules/to-iso-string": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", - "integrity": "sha512-oeHLgfWA7d0CPQa6h0+i5DAJZISz5un0d5SHPkw+Untclcvzv9T+AC3CvGXlZJdOlIbxbTfyyzlqCXc5hjpXYg==", - "deprecated": "to-iso-string has been deprecated, use @segment/to-iso-string instead.", - "dev": true - }, "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -24594,15 +20445,6 @@ "node": "*" } }, - "node_modules/treeify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.0.1.tgz", - "integrity": "sha512-i3MKN4nGEOuVAcd7s5MtAc2+QBExwcaRT/6/CzUSYVYwzM58bJ3H3wwCPu2PEAGjVPHjfIC/MPaXsxPGUk07cg==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -24613,15 +20455,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -24641,63 +20474,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/trumpet": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/trumpet/-/trumpet-1.6.6.tgz", - "integrity": "sha512-A4cn/zuq0AsxS5M8cD+7GUoIhOoK2qkcpFUwlpHnNOsTPzCq7FITZV9lg95ydupJcQRi/kFQzGIn7oN3kNp10w==", - "dev": true, - "dependencies": { - "duplexer2": "~0.0.2", - "html-select": "^2.3.5", - "html-tokenize": "^1.1.1", - "inherits": "^2.0.0", - "readable-stream": "^1.0.27-1", - "through2": "^1.0.0" - } - }, - "node_modules/trumpet/node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "dev": true, - "dependencies": { - "readable-stream": "~1.1.9" - } - }, - "node_modules/trumpet/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/trumpet/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/trumpet/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/trumpet/node_modules/through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "dependencies": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, "node_modules/tsconfig-paths": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz", @@ -24728,12 +20504,6 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "node_modules/tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "dev": true - }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -24809,6 +20579,20 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "node_modules/typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/typescript-compare": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", @@ -24849,12 +20633,6 @@ "node": "*" } }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, "node_modules/uglify-js": { "version": "3.15.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz", @@ -24868,93 +20646,6 @@ "node": ">=0.8.0" } }, - "node_modules/uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", - "dev": true - }, - "node_modules/umd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/umd/-/umd-2.1.0.tgz", - "integrity": "sha512-mEAJeceExHnblcAwN3BQtDPYOrTy4ALeBh6nQ9KW0cUCd0UU714jAfil2jvq09b67IizwJIiTVFOjE+/52Dyvw==", - "dev": true, - "dependencies": { - "rfile": "~1.0.0", - "ruglify": "~1.0.0", - "through": "~2.3.4", - "uglify-js": "~2.4.0" - }, - "bin": { - "umd": "bin/cli.js" - } - }, - "node_modules/umd/node_modules/async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==", - "dev": true - }, - "node_modules/umd/node_modules/camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/umd/node_modules/source-map": { - "version": "0.1.34", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz", - "integrity": "sha512-yfCwDj0vR9RTwt3pEzglgb3ZgmcXHt6DjG3bjJvzPwTL+5zDQ2MhmSzAcTy0GTiQuCiriSWXvWM1/NhKdXuoQA==", - "dev": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/umd/node_modules/uglify-js": { - "version": "2.4.24", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz", - "integrity": "sha512-tktIjwackfZLd893KGJmXc1hrRHH1vH9Po3xFh1XBjjeGAnN02xJ3SuoA+n1L29/ZaCA18KzCFlckS+vfPugiA==", - "dev": true, - "dependencies": { - "async": "~0.2.6", - "source-map": "0.1.34", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.5.4" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/umd/node_modules/wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/umd/node_modules/yargs": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz", - "integrity": "sha512-5j382E4xQSs71p/xZQsU1PtRA2HXPAjX0E0DkoGLxwNASMOKX6A9doV1NrZmj85u2Pjquz402qonBzz/yLPbPA==", - "dev": true, - "dependencies": { - "camelcase": "^1.0.2", - "decamelize": "^1.0.0", - "window-size": "0.1.0", - "wordwrap": "0.0.2" - } - }, "node_modules/unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", @@ -24989,21 +20680,6 @@ "node": ">=0.10.0" } }, - "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "dev": true - }, - "node_modules/underscore.string": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", - "integrity": "sha512-yxkabuCaIBnzfIvX3kBxQqCs0ar/bfJwDnFEHJUm/ZrRVhT3IItdRF5cZjARLzEnyQYtIUhsZ2LG2j3HidFOFQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/undertaker": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", @@ -25397,18 +21073,6 @@ "node": ">=0.10.0" } }, - "node_modules/user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha512-aggiKfEEubv3UwRNqTzLInZpAOmKzwdHqEBmW/hBA/mt99eg+b4VrX6i+IRLxU8+WJYfa33rGwRseg4eElUgsQ==", - "dev": true, - "bin": { - "user-home": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/util": { "version": "0.12.4", "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", @@ -25429,12 +21093,6 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "node_modules/util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "dev": true - }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -25861,15 +21519,6 @@ "node": ">= 0.10" } }, - "node_modules/vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha512-NyZNR3WDah+NPkjh/YmhuWSsT4a0mF0BJYgUmvrJ70zxjTXh5Y2Asobxlh0Nfs0PCFB5FVpRJft7NozAWFMwLQ==", - "dev": true, - "dependencies": { - "indexof": "0.0.1" - } - }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -25990,9 +21639,9 @@ } }, "node_modules/webdriverio/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -26430,15 +22079,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -26561,18 +22201,6 @@ } } }, - "node_modules/xml-escape": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz", - "integrity": "sha512-gCT82WbwOT9SBI/94j5i0tqHpjHIP/0kP11BS8s2wcBtdcFsDNLS9sLvA+C55fD3hpGhgnE/r7hfeBFkiMATjw==", - "dev": true - }, - "node_modules/xmlcreate": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "dev": true - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -26832,1003 +22460,11 @@ } }, "plugins/eslint": { + "name": "eslint-plugin-prebid", "version": "1.0.0", "integrity": "sha512-DH8lk8H4D+XCWtPm7C27IzzD4lkBHv49YTqOHeS/1mYCp4rn1j3NNNA1gl2q+CNYaAPSZDaS5DwRL/ErDP6O4Q==", "dev": true, - "dependencies": { - "chalk": "^1.0.0", - "concat-stream": "^1.4.6", - "debug": "^2.1.1", - "doctrine": "^0.6.2", - "escape-string-regexp": "^1.0.2", - "escope": "^3.2.0", - "espree": "^2.2.0", - "estraverse": "^4.1.0", - "estraverse-fb": "^1.3.1", - "globals": "^8.2.0", - "inquirer": "^0.8.2", - "is-my-json-valid": "^2.10.0", - "js-yaml": "^3.2.5", - "lodash.clonedeep": "^3.0.1", - "lodash.merge": "^3.3.2", - "lodash.omit": "^3.1.0", - "minimatch": "^2.0.1", - "mkdirp": "^0.5.0", - "object-assign": "^2.0.0", - "optionator": "^0.5.0", - "path-is-absolute": "^1.0.0", - "path-is-inside": "^1.0.1", - "strip-json-comments": "~1.0.1", - "text-table": "~0.2.0", - "user-home": "^1.0.0", - "xml-escape": "~1.0.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "devDependencies": { - "beefy": "^1.0.0", - "brfs": "0.0.9", - "browserify": "^8.1.3", - "chai": "^1.9.1", - "coveralls": "2.11.2", - "dateformat": "^1.0.8", - "esprima": "^2.4.1", - "esprima-fb": "^10001.1.0-dev-harmony-fb", - "gh-got": "^1.0.3", - "istanbul": "^0.3.5", - "jsdoc": "^3.3.0-beta1", - "jsonlint": "^1.6.2", - "markdownlint": "^0.0.6", - "mocha": "^2.1.0", - "mocha-phantomjs": "3.6.0", - "npm-license": "^0.2.3", - "phantomjs": "1.9.7-15", - "proxyquire": "^1.0.0", - "rewire": "^2.3.4", - "semver": "^4.1.0", - "shelljs": "^0.3.0", - "shelljs-nodecli": "~0.1.0", - "sinon": "1.14.1", - "through": "^2.3.6" - }, - "engines": { - "node": ">=0.10" - } - }, - "plugins/eslint/node_modules/ansi-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", - "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/argparse": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", - "integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==", - "dev": true, - "dependencies": { - "underscore": "~1.7.0", - "underscore.string": "~2.4.0" - } - }, - "plugins/eslint/node_modules/asn1": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", - "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.4.9" - } - }, - "plugins/eslint/node_modules/assert-plus": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", - "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.8" - } - }, - "plugins/eslint/node_modules/assertion-error": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.0.tgz", - "integrity": "sha512-g/gZV+G476cnmtYI+Ko9d5khxSoCSoom/EaNmmCfwpOvBXEJ18qwFrxfP1/CsIqk2no1sAKKwxndV0tP7ROOFQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/aws-sign2": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", - "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", - "dev": true, - "optional": true, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/chai": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-1.10.0.tgz", - "integrity": "sha512-E3L9M2SeQU1XagJkE9KJyTAXXHKJkJ1EsKkFp0Rl53lYa3mro2PVgYHNiCb2YRa2nUeyg7aqmI1EIcSBayNd5w==", - "dev": true, - "dependencies": { - "assertion-error": "1.0.0", - "deep-eql": "0.1.3" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "plugins/eslint/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/cli-width": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz", - "integrity": "sha512-eMU2akIeEIkCxGXUNmDnJq1KzOIiPnJ+rKqRe6hcxE3vIOPvpMrBYOn/Bl7zNlYJj/zQxXquAnozHUCf9Whnsg==", - "dev": true - }, - "plugins/eslint/node_modules/combined-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", - "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", - "dev": true, - "optional": true, - "dependencies": { - "delayed-stream": "0.0.5" - }, - "engines": { - "node": ">= 0.8" - } - }, - "plugins/eslint/node_modules/commander": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha512-CD452fnk0jQyk3NfnK+KkR/hUPoHt5pVaKHogtyyv3N0U4QfAal9W0/rXLOg/vVZgQKa7jdtXypKs1YAip11uQ==", - "dev": true, - "engines": { - "node": ">= 0.6.x" - } - }, - "plugins/eslint/node_modules/coveralls": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.11.2.tgz", - "integrity": "sha512-+OK2imSCDXSYaOyAxGVUmzDfDtCYLW+gtdDVpjvq99R5Dyry4Puj3EQ/4YnsxNc6RHsuhx3wIkHSBIRaJZY5YQ==", - "dev": true, - "dependencies": { - "js-yaml": "3.0.1", - "lcov-parse": "0.0.6", - "log-driver": "1.2.4", - "request": "2.40.0" - }, - "bin": { - "coveralls": "bin/coveralls.js" - }, - "engines": { - "node": ">=0.8.6" - } - }, - "plugins/eslint/node_modules/coveralls/node_modules/esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "plugins/eslint/node_modules/coveralls/node_modules/js-yaml": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.0.1.tgz", - "integrity": "sha512-dgxgLzZS9qLWAQd/wrVG8tOiRSBJq1Ss9gbd7+fdBhcia3efHjLLpPkcUhKOyVACxTEAgnao3RT1kj1otiW42g==", - "dev": true, - "dependencies": { - "argparse": "~ 0.1.11", - "esprima": "~ 1.0.2" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - }, - "engines": { - "node": ">= 0.6.0" - } - }, - "plugins/eslint/node_modules/dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha512-5sFRfAAmbHdIts+eKjR9kYJoF0ViCMVX9yqLu5A7S/v+nd077KgCITOMiirmyCBiZpKLDXbBOkYm6tu7rX/TKg==", - "dev": true, - "dependencies": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" - }, - "bin": { - "dateformat": "bin/cli.js" - }, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "plugins/eslint/node_modules/deep-eql": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", - "integrity": "sha512-6sEotTRGBFiNcqVoeHwnfopbSpi5NbH1VWJmYCVkmxMmaVTT0bUTrNaGyBwhgP4MZL012W/mkzIn3Da+iDYweg==", - "dev": true, - "dependencies": { - "type-detect": "0.1.1" - }, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/delayed-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", - "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.4.0" - } - }, - "plugins/eslint/node_modules/diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha512-VzVc42hMZbYU9Sx/ltb7KYuQ6pqAw+cbFWVy4XKdkuEL2CFaRLGEnISPs7YdzaUGpi+CpIqvRmu7hPQ4T7EQ5w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "plugins/eslint/node_modules/doctrine": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz", - "integrity": "sha512-FSGvDB23RFdm/Z2hEINXN1AcBW5I4YBqpGD/lScJV34vuOwrPFyLHN9bwCzLa6lUmqS6ipdp5XlVJRQ6yJ5iSA==", - "dev": true, - "dependencies": { - "esutils": "^1.1.6", - "isarray": "0.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/escodegen": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz", - "integrity": "sha512-2cd7+JUtUEmZVpGmfF9r+uRYXswJAkf85Ce8GvdBa7hSvdjY8hGo+rwC5syAgYzqHpfxNJzLntFjw6879yPbgQ==", - "dev": true, - "dependencies": { - "esprima": "^1.2.2", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.5.0" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=0.12.0" - }, - "optionalDependencies": { - "source-map": "~0.2.0" - } - }, - "plugins/eslint/node_modules/escodegen/node_modules/esprima": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", - "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "plugins/eslint/node_modules/escodegen/node_modules/estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/escodegen/node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/espree": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz", - "integrity": "sha512-HWJpgkL44cbjWiOTC9Pm34RZE57H1g9V4Ln9U14TUtiywFTLMMpMCtmQK5rkjbGBXigQT8bS3r45+Dt5+m0SZg==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/esprima": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz", - "integrity": "sha512-uM6hfS0/8ybNIj8SGRMdidPJy5uhWqWN/GIkyqnMAbCSL44yfFGLuBpRRCgOpBXBZt2OymQuM+IfahkqJq3DWw==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/esutils": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", - "integrity": "sha512-RG1ZkUT7iFJG9LSHr7KDuuMSlujfeTtMNIcInURxKAxhMtwQhI3NrQhz26gZQYlsYZQKzsnwtpKrFKj9K9Qu1A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/fast-levenshtein": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz", - "integrity": "sha512-hYsfI0s4lfQ2rHVFKXwAr/L/ZSbq9TZwgXtZqW7ANcn9o9GKvcbWxOnxx7jykXf/Ezv1V8TvaBEKcGK7DWKX5A==", - "dev": true - }, - "plugins/eslint/node_modules/figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/figures/node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/forever-agent": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", - "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==", - "dev": true, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/form-data": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", - "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", - "dev": true, - "optional": true, - "dependencies": { - "async": "~0.9.0", - "combined-stream": "~0.0.4", - "mime": "~1.2.11" - }, - "engines": { - "node": ">= 0.8" - } - }, - "plugins/eslint/node_modules/form-data/node_modules/async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==", - "dev": true, - "optional": true - }, - "plugins/eslint/node_modules/glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==", - "dev": true, - "dependencies": { - "inherits": "2", - "minimatch": "0.3" - }, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/glob/node_modules/minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA==", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", - "dev": true, - "dependencies": { - "lru-cache": "2", - "sigmund": "~1.0.0" - }, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/globals": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz", - "integrity": "sha512-IHCTKEGo42ICEkTZBADyl4HX06hVdFF4qdJdqOgaBe5X8RE1/MrvubetsEtGTcwjs46djFq0Gc3+5RgTsc3UoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha512-RTBwDHhNuOx4F0hqzItc/siXCasGfC4DeWcBamclWd+6jWtBaeB/SGbMkGf0eiQoW7ib8JpvOgnUsmgMHI3Mfw==", - "dev": true - }, - "plugins/eslint/node_modules/has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/http-signature": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", - "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", - "dev": true, - "optional": true, - "dependencies": { - "asn1": "0.1.11", - "assert-plus": "^0.1.5", - "ctype": "0.5.3" - }, - "engines": { - "node": ">=0.8" - } - }, - "plugins/eslint/node_modules/inquirer": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz", - "integrity": "sha512-+rksrtdqQ8do7yOsmP5YIgbSdbZYuCIrnfH5vjFYGAr1XgJpMksb3rFZMJ3jiKuUyDVEA4MVDYbkA3ribJn3Tg==", - "dev": true, - "dependencies": { - "ansi-regex": "^1.1.1", - "chalk": "^1.0.0", - "cli-width": "^1.0.1", - "figures": "^1.3.5", - "lodash": "^3.3.1", - "readline2": "^0.1.1", - "rx": "^2.4.3", - "through": "^2.3.6" - } - }, - "plugins/eslint/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "plugins/eslint/node_modules/istanbul": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz", - "integrity": "sha512-8H/jxiee2UqX/mviKkPoKQYMxU2t995FC5PwO4zjWeDPOozjoeKqxEyN62l9o5+UgzvYQbrKgQjjxhGON8FcMg==", - "deprecated": "This module is no longer maintained, try this instead:\n npm i nyc\nVisit https://istanbul.js.org/integrations for other alternatives.", - "dev": true, - "dependencies": { - "abbrev": "1.0.x", - "async": "1.x", - "escodegen": "1.7.x", - "esprima": "2.5.x", - "fileset": "0.2.x", - "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" - }, - "bin": { - "istanbul": "lib/cli.js" - } - }, - "plugins/eslint/node_modules/istanbul/node_modules/supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", - "dev": true, - "dependencies": { - "has-flag": "^1.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "plugins/eslint/node_modules/lcov-parse": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.6.tgz", - "integrity": "sha512-chuBQJZiBq28YUM6Yr3tf3h5Lxhb+DvhbxxSNpsHURSXiZXOzp49phiWG2pKHboOehJDujivwNQGRP8mAErMvQ==", - "dev": true - }, - "plugins/eslint/node_modules/levn": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz", - "integrity": "sha512-mvp+NO++YH0B+e8cC/SvJxk6k5Z9Ngd3iXuz7tmT8vZCyQZj/5SI1GkFOiZGGPkm5wWGI9SUrqiAfPq7BJH+0w==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.0", - "type-check": "~0.3.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "plugins/eslint/node_modules/lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==", - "dev": true - }, - "plugins/eslint/node_modules/lodash.clonedeep": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", - "integrity": "sha512-I8MpGh5z+6OixDAAb21teLSZDmqVPjlq02Q7ZFrbn2xnQHYYuJf6on/94SWpF/p0s3p/cEv/53ro4AhDOfCR0g==", - "dev": true, - "dependencies": { - "lodash._baseclone": "^3.0.0", - "lodash._bindcallback": "^3.0.0" - } - }, - "plugins/eslint/node_modules/lodash.isplainobject": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz", - "integrity": "sha512-P4wZnho5curNqeEq/x292Pb57e1v+woR7DJ84DURelKB46lby8aDEGVobSaYtzHdQBWQrJSdxcCwjlGOvvdIyg==", - "dev": true, - "dependencies": { - "lodash._basefor": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.keysin": "^3.0.0" - } - }, - "plugins/eslint/node_modules/lodash.merge": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz", - "integrity": "sha512-ZgGZpRhWLjivGUbjtApZR4HyLv/UAyoYqESVYkK4aLBJVHRrbFpG+GNnE9JPijliME4LkKM0SFI/WyOiBiv1+w==", - "dev": true, - "dependencies": { - "lodash._arraycopy": "^3.0.0", - "lodash._arrayeach": "^3.0.0", - "lodash._createassigner": "^3.0.0", - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0", - "lodash.isplainobject": "^3.0.0", - "lodash.istypedarray": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.keysin": "^3.0.0", - "lodash.toplainobject": "^3.0.0" - } - }, - "plugins/eslint/node_modules/log-driver": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.4.tgz", - "integrity": "sha512-QmyGbAcBbHk8ysCGtT6FQ+LZML6+EeT0NdotCJGu72kNhknXtdso1G/NI0r7j45whFYNTU15XMW+JGOvGX07QQ==", - "dev": true, - "engines": { - "node": ">=0.8.6" - } - }, - "plugins/eslint/node_modules/lolex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.1.0.tgz", - "integrity": "sha512-wGZrF3AlAWxG2j+6NyyttZ/UVxW8o/F+q01IUGuf2PiEIAUG9av/vpBS5TQHTQtzPmPJB4CZWjwyGR4C4aX83w==", - "dev": true - }, - "plugins/eslint/node_modules/lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==", - "dev": true - }, - "plugins/eslint/node_modules/mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", - "dev": true, - "optional": true - }, - "plugins/eslint/node_modules/mime-types": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz", - "integrity": "sha512-echfutj/t5SoTL4WZpqjA1DCud1XO0WQF3/GJ48YBmc4ZMhCK77QA6Z/w6VTQERLKuJ4drze3kw2TUT8xZXVNw==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "plugins/eslint/node_modules/minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", - "dev": true, - "dependencies": { - "brace-expansion": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "plugins/eslint/node_modules/mocha": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", - "integrity": "sha512-jNt2iEk9FPmZLzL+sm4FNyOIDYXf2wUU6L4Cc8OIKK/kzgMHKPi4YhTZqG4bW4kQVdIv6wutDybRhXfdnujA1Q==", - "dev": true, - "dependencies": { - "commander": "2.3.0", - "debug": "2.2.0", - "diff": "1.4.0", - "escape-string-regexp": "1.0.2", - "glob": "3.2.11", - "growl": "1.9.2", - "jade": "0.26.3", - "mkdirp": "0.5.1", - "supports-color": "1.2.0", - "to-iso-string": "0.0.2" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 0.8.x" - } - }, - "plugins/eslint/node_modules/mocha/node_modules/debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha512-X0rGvJcskG1c3TgSCPqHJ0XJgwlcvOC7elJ5Y0hYuKBZoVqWpAMfLOeIh2UI/DCQ5ruodIjvsugZtjUYUw2pUw==", - "dev": true, - "dependencies": { - "ms": "0.7.1" - } - }, - "plugins/eslint/node_modules/mocha/node_modules/escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha512-cQpUid7bdTUnFin8S7BnNdOk+/eDqQmKgCANSyd/jAhrKEvxUvr9VQ8XZzXiOtest8NLfk3FSBZzwvemZNQ6Vg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "plugins/eslint/node_modules/mocha/node_modules/minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", - "dev": true - }, - "plugins/eslint/node_modules/mocha/node_modules/mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true, - "dependencies": { - "minimist": "0.0.8" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "plugins/eslint/node_modules/mocha/node_modules/ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha512-lRLiIR9fSNpnP6TC4v8+4OU7oStC01esuNowdQ34L+Gk8e5Puoc88IqJ+XAY/B3Mn2ZKis8l8HX90oU8ivzUHg==", - "dev": true - }, - "plugins/eslint/node_modules/mocha/node_modules/supports-color": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "integrity": "sha512-mS5xsnjTh5b7f2DM6bch6lR582UCOTphzINlZnDsfpIRrwI6r58rb6YSSGsdexkm8qw2bBVO2ID2fnJOTuLiPA==", - "dev": true, - "bin": { - "supports-color": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "plugins/eslint/node_modules/oauth-sign": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", - "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", - "dev": true, - "optional": true, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/object-assign": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha512-CdsOUYIh5wIiozhJ3rLQgmUTgcyzFwZZrqhkKhODMoGtPKM+wt0h0CNIoauJWMsS9822EdzPsF/6mb4nLvPN5g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/optionator": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", - "integrity": "sha512-jUr7aBk/kCInAEsl+qxuw4ORpe458atDKXNLhyvPUD4NfnsJsbAViX1b9nb/0rS62lO8cIFd1VoiaXLQ+MybOw==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.2", - "fast-levenshtein": "~1.0.0", - "levn": "~0.2.5", - "prelude-ls": "~1.1.1", - "type-check": "~0.3.1", - "wordwrap": "~0.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "plugins/eslint/node_modules/optionator/node_modules/wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "plugins/eslint/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "plugins/eslint/node_modules/qs": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz", - "integrity": "sha512-tHuOP9TN/1VmDM/ylApGK1QF3PSIP8I6bHDEfoKNQeViREQ/sfu1bAUrA1hoDun8p8Tpm7jcsz47g+3PiGoYdg==", - "dev": true - }, - "plugins/eslint/node_modules/request": { - "version": "2.40.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz", - "integrity": "sha512-waNoGB4Z7bPn+lgqPk7l7hhze4Vd68jKccnwLeS7vr9GMxz0iWQbYTbBNWzfIk87Urx7V44pu29qjF/omej+Fw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "dependencies": { - "forever-agent": "~0.5.0", - "json-stringify-safe": "~5.0.0", - "mime-types": "~1.0.1", - "node-uuid": "~1.4.0", - "qs": "~1.0.0" - }, - "optionalDependencies": { - "aws-sign2": "~0.5.0", - "form-data": "~0.1.0", - "hawk": "1.1.1", - "http-signature": "~0.10.0", - "oauth-sign": "~0.3.0", - "stringstream": "~0.0.4", - "tough-cookie": ">=0.12.0", - "tunnel-agent": "~0.4.0" - } - }, - "plugins/eslint/node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", - "dev": true - }, - "plugins/eslint/node_modules/semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "plugins/eslint/node_modules/sinon": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.14.1.tgz", - "integrity": "sha512-cysrMyrriLwSn5Ye82xTCAVVS6Q6XLxlZE3jtPb4IFng2npN3lQWQ5Uyaud6cRpzztbEy2sbJkrDSbIl6OKUCA==", - "dev": true, - "dependencies": { - "formatio": "1.1.1", - "lolex": "1.1.0", - "util": ">=0.10.3 <1" - }, - "engines": { - "node": ">=0.1.103" - } - }, - "plugins/eslint/node_modules/source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", - "dev": true, - "optional": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "plugins/eslint/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "plugins/eslint/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "plugins/eslint/node_modules/tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", - "dev": true, - "optional": true, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "plugins/eslint/node_modules/type-detect": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", - "integrity": "sha512-5rqszGVwYgBoDkIm2oUtvkfZMQ0vk29iDMU0W2qCa3rG0vPDNczCMT4hV/bLBgLg8k8ri6+u3Zbt+S/14eMzlA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "plugins/eslint/node_modules/underscore": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==", - "dev": true - }, - "plugins/eslint/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } + "license": "Apache-2.0" } }, "dependencies": { @@ -29455,12 +24091,6 @@ "@types/node": "*" } }, - "@types/linkify-it": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", - "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", - "dev": true - }, "@types/lodash": { "version": "4.14.179", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz", @@ -29494,16 +24124,6 @@ "@types/lodash": "*" } }, - "@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", - "dev": true, - "requires": { - "@types/linkify-it": "*", - "@types/mdurl": "*" - } - }, "@types/mdast": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", @@ -30642,29 +25262,6 @@ "dev": true, "requires": {} }, - "acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "requires": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "adm-zip": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.2.1.tgz", - "integrity": "sha512-J2LiZpRxcLsJm2IwoekNa6COwzEZnMwCJ3vxz0UCw2NYUH2WFi7svuDrVccq5KpBGmzGUgFa0L0FwEmKmu/rzQ==", - "dev": true - }, "aes-decrypter": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz", @@ -30699,7 +25296,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true + "dev": true, + "optional": true }, "ansi-colors": { "version": "4.1.1", @@ -30903,12 +25501,6 @@ "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", "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": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", - "dev": true - }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -31008,12 +25600,6 @@ "es-abstract": "^1.19.0" } }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true - }, "asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -31023,26 +25609,6 @@ "safer-buffer": "~2.1.0" } }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, "assert": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", @@ -31079,23 +25645,6 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, - "astw": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", - "integrity": "sha512-E/4z//dvN0lfr8zAx8hXeQ8o3nRoQaL/wqI7fAALEvh/40mnyUxfFB9MwyDHYKVDtS3cp3Pow5s96djZR5lkWw==", - "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": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", - "dev": true - } - } - }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -31622,12 +26171,6 @@ } } }, - "Base64": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz", - "integrity": "sha512-reGEWshDmTDQDsCec/HduOO9Wyj6yMOupMfhIf3ugN1TDlK2NQW4DDJSqNNtp380SNcvRfXtO8HSCQot0d0SMw==", - "dev": true - }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -31664,60 +26207,6 @@ "tweetnacl": "^0.14.3" } }, - "beefy": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/beefy/-/beefy-1.1.0.tgz", - "integrity": "sha512-olZqTbw6gnofdbG98uAKvG6O/AjV6WGuPsKpYF41VQK39sUYvulm86RssD1K/iVNkkSJ8cuYeheJ8Nk2gz16wA==", - "dev": true, - "requires": { - "chokidar": "0.8.1", - "colors": "~0.6.0-1", - "ignorepatterns": "1.0.1", - "mime": "~1.2.9", - "nopt": "~2.1.1", - "open": "0.0.3", - "portfinder": "~0.2.1", - "response-stream": "0.0.0", - "script-injector": "~0.1.0", - "sse-stream": "0.0.4", - "through": "~2.2.0" - }, - "dependencies": { - "chokidar": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-0.8.1.tgz", - "integrity": "sha512-Bl/CteHnM5g3eKGPMkraZQW7Yzk2Gu87eE3jdaMfCNJP79sVa54M5KHStr3WtJl4vVoVSndVDws6IFLTmMa3Lw==", - "dev": true - }, - "colors": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", - "integrity": "sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==", - "dev": true - }, - "mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", - "dev": true - }, - "nopt": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.1.2.tgz", - "integrity": "sha512-x8vXm7BZ2jE1Txrxh/hO74HTuYZQEbo8edoRcANgdZ4+PCV+pbjd/xdummkmjjC7LU5EjPzlu8zEq/oxWylnKA==", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "through": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", - "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", - "dev": true - } - } - }, "beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", @@ -31798,12 +26287,6 @@ "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", "dev": true }, - "bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true - }, "body": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", @@ -31872,16 +26355,6 @@ } } }, - "boom": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", - "integrity": "sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==", - "dev": true, - "optional": true, - "requires": { - "hoek": "0.9.x" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -31901,518 +26374,12 @@ "fill-range": "^7.0.1" } }, - "brfs": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/brfs/-/brfs-0.0.9.tgz", - "integrity": "sha512-5bjo0XG6pPGTFJsS4rtvP1vvwLp3UstdF062l10RKcfG60+izXak0DFcfQwMtBQNGlFm588mM2WvD02hJErVYg==", - "dev": true, - "requires": { - "escodegen": "0.0.17", - "falafel": "~0.1.6", - "through": "~2.2.0" - }, - "dependencies": { - "escodegen": { - "version": "0.0.17", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-0.0.17.tgz", - "integrity": "sha512-muX87X0L2dvVJ4ZPKAJLQlcyg2qhl6ps8Ow8vOAcuoFIrZLtXNMGfjnD19LSTrZ1SBHQsI+tvD8YlsJqHhfXrw==", - "dev": true, - "requires": { - "esprima": "~1.0.2", - "estraverse": "~0.0.4", - "source-map": ">= 0.1.2" - } - }, - "esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", - "dev": true - }, - "estraverse": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-0.0.4.tgz", - "integrity": "sha512-21DfBCsFJGb3HZr0vEBH1Wk1tGSbbzA8I/xtSSoy/pRtupHv0OgBmObcNGXM3ec6/pOXTOOUYY9/5bfluzz0sw==", - "dev": true - }, - "through": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", - "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", - "dev": true - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true - }, - "browser-pack": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-3.2.0.tgz", - "integrity": "sha512-BHla5EbbxjNyLMFUMamVjeTY+q1QwHbrYNXlWOkw71QcBqAQF7maJyNh3OI/V0d5YyNdMYD6tiPhJB9ukBo99Q==", - "dev": true, - "requires": { - "combine-source-map": "~0.3.0", - "concat-stream": "~1.4.1", - "defined": "~0.0.0", - "JSONStream": "~0.8.4", - "through2": "~0.5.1", - "umd": "^2.1.0" - }, - "dependencies": { - "concat-stream": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", - "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.9", - "typedarray": "~0.0.5" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "through2": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", - "integrity": "sha512-zexCrAOTbjkBCXGyozn7hhS3aEaqdrc59mAD2E3dKYzV1vFuEGQ1hEDJN2oQMQFwy4he2zyLqPZV+AlfS8ZWJA==", - "dev": true, - "requires": { - "readable-stream": "~1.0.17", - "xtend": "~3.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - } - } - }, - "xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", - "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": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", - "dev": true - } - } - }, "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": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-8.1.3.tgz", - "integrity": "sha512-0KKOkCQXCvP64qm73CtESE92pVnB5MkjA2W/Tmf+S4uPHVY4/SeCwO7wdr4mkke5ySoVyMqsOcMa5zo6uh9c9A==", - "dev": true, - "requires": { - "assert": "~1.3.0", - "browser-pack": "^3.2.0", - "browser-resolve": "^1.3.0", - "browserify-zlib": "~0.1.2", - "buffer": "^3.0.0", - "builtins": "~0.0.3", - "commondir": "0.0.1", - "concat-stream": "~1.4.1", - "console-browserify": "^1.1.0", - "constants-browserify": "~0.0.1", - "crypto-browserify": "^3.0.0", - "deep-equal": "~0.2.1", - "defined": "~0.0.0", - "deps-sort": "^1.3.5", - "domain-browser": "~1.1.0", - "duplexer2": "~0.0.2", - "events": "~1.0.0", - "glob": "^4.0.5", - "http-browserify": "^1.4.0", - "https-browserify": "~0.0.0", - "inherits": "~2.0.1", - "insert-module-globals": "^6.2.0", - "isarray": "0.0.1", - "JSONStream": "~0.8.3", - "labeled-stream-splicer": "^1.0.0", - "module-deps": "^3.6.3", - "os-browserify": "~0.1.1", - "parents": "^1.0.1", - "path-browserify": "~0.0.0", - "process": "^0.10.0", - "punycode": "~1.2.3", - "querystring-es3": "~0.2.0", - "readable-stream": "^1.0.33-1", - "resolve": "~0.7.1", - "shallow-copy": "0.0.1", - "shasum": "^1.0.0", - "shell-quote": "~0.0.1", - "stream-browserify": "^1.0.0", - "string_decoder": "~0.10.0", - "subarg": "^1.0.0", - "syntax-error": "^1.1.1", - "through2": "^1.0.0", - "timers-browserify": "^1.0.1", - "tty-browserify": "~0.0.0", - "umd": "~2.1.0", - "url": "~0.10.1", - "util": "~0.10.1", - "vm-browserify": "~0.0.1", - "xtend": "^3.0.0" - }, - "dependencies": { - "assert": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.3.0.tgz", - "integrity": "sha512-5aKcpD+XnHpZ7EGxsuo6uoILNh0rvm0Ypa17GlkrF2CNSPhvdgi3ft9XsL2ajdVOI2I3xuGZnHvlXAeqTZYvXg==", - "dev": true, - "requires": { - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", - "dev": true - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", - "dev": true, - "requires": { - "inherits": "2.0.1" - } - } - } - }, - "base64-js": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", - "dev": true - }, - "buffer": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.2.tgz", - "integrity": "sha512-c3M77NkHJxS0zx/ErxXhDLr1v3y2MDXPeTJPvLNOaIYJ4ymHBUFQ9EXzt9HYuqAJllMoNb/EZ8hIiulnQFAUuQ==", - "dev": true, - "requires": { - "base64-js": "0.0.8", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - } - } - }, - "commondir": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-0.0.1.tgz", - "integrity": "sha512-Ghe1LmLv3G3c0XJYu+c88MCRIPqWQ67qaqKY1KvuN4uPAjfUj+y4hvcpZ2kCPrjpRNyklW4dpAZZ8a7vOh50tg==", - "dev": true - }, - "concat-stream": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", - "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.9", - "typedarray": "~0.0.5" - } - }, - "deep-equal": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", - "integrity": "sha512-FXgye2Jr6oEk01S7gmSrHrPEQ1ontR7wwl+nYiZ8h4SXlHVm0DYda74BIPcHz2s2qPz4+375IcAz1vsWLwddgQ==", - "dev": true - }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "dev": true, - "requires": { - "readable-stream": "~1.1.9" - } - }, - "events": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/events/-/events-1.0.2.tgz", - "integrity": "sha512-XK19KwlDJo8XsceooxNDK1pObtcT44+Xte6V/jQc4a+fHq1qEouThyyX2ePmS0hS8RcCulmRxzg+T8jiLKAFFQ==", - "dev": true - }, - "glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha512-I0rTWUKSZKxPSIAIaqhSXTM/DiII6wame+rEC3cFA5Lqmr9YmdL7z6Hj9+bdWtTvoY1Su4/OiMLmb37Y7JzvJQ==", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", - "dev": true, - "requires": { - "brace-expansion": "^1.0.0" - } - }, - "process": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", - "integrity": "sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA==", - "dev": true - }, - "punycode": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.2.4.tgz", - "integrity": "sha512-h/vscxLPvI2l7k/0dFUKZ5I5TgMCJ/Pl+J6rw77PDuQM6UApf/GaRVkjv/YSm2k+fbp7Yw8dxsoe29DolT7h7w==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "resolve": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.7.4.tgz", - "integrity": "sha512-zxmAcifDjKxmUbk7chQdKhDSn8ml08g+MYyU37xhEXBp+N81cfbYsm4e0Gn9jtLbAvbR8w8Ox09xqUZtPuCoeA==", - "dev": true - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "requires": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - }, - "dependencies": { - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - } - } - }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "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": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", - "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" - } - }, - "xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", - "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.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dev": true, - "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "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.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "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" - } - }, - "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 - } - } - }, - "browserify-zlib": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", - "integrity": "sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==", - "dev": true, - "requires": { - "pako": "~0.2.0" - } - }, "browserslist": { "version": "4.21.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", @@ -32549,24 +26516,12 @@ "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", "dev": true }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "dev": true - }, "buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", "dev": true }, - "builtins": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-0.0.7.tgz", - "integrity": "sha512-T8uCGKc0/2aLVt6omt8JxDRBoWEMkku+wFesxnhxnt4NygVZG99zqxo7ciK8eebszceKamGoUiLdkXCgGQyrQw==", - "dev": true - }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -32749,12 +26704,6 @@ "get-intrinsic": "^1.0.2" } }, - "callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", - "dev": true - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -32767,24 +26716,6 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==", - "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": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==", - "dev": true - } - } - }, "can-autoplay": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/can-autoplay/-/can-autoplay-3.0.2.tgz", @@ -32802,15 +26733,6 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, - "catharsis": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", - "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, "ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -32944,16 +26866,6 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "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" - } - }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -33156,34 +27068,6 @@ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, - "combine-source-map": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.3.0.tgz", - "integrity": "sha512-HRKa6g9SC1xd6ifto8ay6SxvyHaaQ50/8NO1ZONXx2hsIF9t/52qXa7Eeivaf5KFOSowK7Nm8TkIL/VC4khdBA==", - "dev": true, - "requires": { - "convert-source-map": "~0.3.0", - "inline-source-map": "~0.3.0", - "source-map": "~0.1.31" - }, - "dependencies": { - "convert-source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", - "integrity": "sha512-+4nRk0k3oEpwUB7/CalD7xE2z4VmtEnnq0GO2IPTkrooTrAhEsWvuLF5iWP1dXrwluki/azwXV1ve7gtYuPldg==", - "dev": true - }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -33199,12 +27083,6 @@ "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==", "dev": true }, - "commander": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.0.0.tgz", - "integrity": "sha512-qebjpyeaA/nJ4w3EO2cV2++/zEkccPnjWogzA2rff+Lk8ILI75vULeTmyd4wPxWdKwtP3J+G39IXVZadh0UHyw==", - "dev": true - }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -33277,16 +27155,6 @@ } } }, - "config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, "connect": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", @@ -33322,18 +27190,6 @@ "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": "0.0.1", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-0.0.1.tgz", - "integrity": "sha512-FL+diDS9AKR5BAA2M+GNk8lnH64tRE3zepTG9hucxc7o04LgCRhkQZhF7u/OKHZT8LLRT+sZEi9qFzXUchq9pA==", - "dev": true - }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -33482,51 +27338,6 @@ } } }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, - "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", @@ -33552,35 +27363,6 @@ "which": "^2.0.1" } }, - "cryptiles": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", - "integrity": "sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==", - "dev": true, - "optional": true, - "requires": { - "boom": "0.4.x" - } - }, - "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", @@ -33617,31 +27399,6 @@ "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=", "dev": true }, - "cssauron": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", - "integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==", - "dev": true, - "requires": { - "through": "X.X.X" - } - }, - "ctype": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", - "integrity": "sha512-T6CEkoSV4q50zW3TlTHMbzy1E5+zlnNcY+yb7tWVYlTwPhx9LpnfAkd4wecpWknDyptp4k97LUZeInlf6jdzBg==", - "dev": true, - "optional": true - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", - "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", @@ -33716,12 +27473,6 @@ } } }, - "debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "dev": true - }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -33860,12 +27611,6 @@ "isobject": "^3.0.1" } }, - "defined": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", - "integrity": "sha512-zpqiCT8bODLu3QSmLLic8xJnYWBFjOSu/fBCm189oAiTtPq/PSanNACKZDS7kgSyCJY7P+IcODzlIogBK/9RBg==", - "dev": true - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -33877,86 +27622,12 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, - "deps-sort": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-1.3.9.tgz", - "integrity": "sha512-aEnmQuu/Hf5h8akL8QshYWzk9MVBg/JYMyNq/Lz68i69nR17tunjP6o/AC6Tn48c8ayzG6aeKs6OoFOtVCtvrQ==", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "shasum": "^1.0.0", - "subarg": "^1.0.0", - "through2": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true - }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "requires": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, "dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "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", @@ -33980,30 +27651,6 @@ "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" - }, - "dependencies": { - "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true - }, - "defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "dev": true - } - } - }, "devtools": { "version": "7.16.16", "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", @@ -34045,16 +27692,6 @@ "integrity": "sha512-myh3hSFp0YWa2GED11PmbLhV4dv9RdO7YUz27XJrbQLnP5bMbZL6dfOOILTHO57yH0kX5GfuOZBsg/4NamfPvQ==", "dev": true }, - "dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, "di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", @@ -34073,25 +27710,6 @@ "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", "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.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, "dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -34267,12 +27885,6 @@ "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", "dev": true }, - "domain-browser": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", - "integrity": "sha512-fJ5MoHxe69h3E4/lJtFRhcWwLb04bhIBSfvCEMS1YDH+/9yEZTqBHTSTgch8nCP5tE5k2gdQEjodUqJzy7qJ9Q==", - "dev": true - }, "dset": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz", @@ -34394,29 +28006,6 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.243.tgz", "integrity": "sha512-BgLD2gBX43OSXwlT01oYRRD5NIB4n3okTRxkzEAC6G0SZG4TTlyrWMjbOo0fajCwqwpRtMHXQNMjtRN6qpNtfw==" }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -34495,12 +28084,6 @@ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", "dev": true }, - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true - }, "errno": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", @@ -34617,20 +28200,6 @@ "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": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", - "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-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", @@ -34652,28 +28221,6 @@ "es6-promise": "^4.0.3" } }, - "es6-set": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", - "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", - "dev": true, - "requires": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "es6-iterator": "~2.0.3", - "es6-symbol": "^3.1.3", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "dependencies": { - "type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", - "dev": true - } - } - }, "es6-symbol": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", @@ -34781,18 +28328,6 @@ } } }, - "escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==", - "dev": true, - "requires": { - "es6-map": "^0.1.3", - "es6-weak-map": "^2.0.1", - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, "eslint": { "version": "7.32.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", @@ -35072,785 +28607,7 @@ } }, "eslint-plugin-prebid": { - "version": "file:plugins/eslint", - "requires": { - "beefy": "^1.0.0", - "brfs": "0.0.9", - "browserify": "^8.1.3", - "chai": "^1.9.1", - "chalk": "^1.0.0", - "concat-stream": "^1.4.6", - "coveralls": "2.11.2", - "dateformat": "^1.0.8", - "debug": "^2.1.1", - "doctrine": "^0.6.2", - "escape-string-regexp": "^1.0.2", - "escope": "^3.2.0", - "espree": "^2.2.0", - "esprima": "^2.4.1", - "esprima-fb": "^10001.1.0-dev-harmony-fb", - "estraverse": "^4.1.0", - "estraverse-fb": "^1.3.1", - "gh-got": "^1.0.3", - "globals": "^8.2.0", - "inquirer": "^0.8.2", - "is-my-json-valid": "^2.10.0", - "istanbul": "^0.3.5", - "js-yaml": "^3.2.5", - "jsdoc": "^3.3.0-beta1", - "jsonlint": "^1.6.2", - "lodash.clonedeep": "^3.0.1", - "lodash.merge": "^3.3.2", - "lodash.omit": "^3.1.0", - "markdownlint": "^0.0.6", - "minimatch": "^2.0.1", - "mkdirp": "^0.5.0", - "mocha": "^2.1.0", - "mocha-phantomjs": "3.6.0", - "npm-license": "^0.2.3", - "object-assign": "^2.0.0", - "optionator": "^0.5.0", - "path-is-absolute": "^1.0.0", - "path-is-inside": "^1.0.1", - "phantomjs": "1.9.7-15", - "proxyquire": "^1.0.0", - "rewire": "^2.3.4", - "semver": "^4.1.0", - "shelljs": "^0.3.0", - "shelljs-nodecli": "~0.1.0", - "sinon": "1.14.1", - "strip-json-comments": "~1.0.1", - "text-table": "~0.2.0", - "through": "^2.3.6", - "user-home": "^1.0.0", - "xml-escape": "~1.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", - "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true - }, - "argparse": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", - "integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==", - "dev": true, - "requires": { - "underscore": "~1.7.0", - "underscore.string": "~2.4.0" - } - }, - "asn1": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", - "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", - "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", - "dev": true, - "optional": true - }, - "assertion-error": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.0.tgz", - "integrity": "sha512-g/gZV+G476cnmtYI+Ko9d5khxSoCSoom/EaNmmCfwpOvBXEJ18qwFrxfP1/CsIqk2no1sAKKwxndV0tP7ROOFQ==", - "dev": true - }, - "aws-sign2": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", - "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", - "dev": true, - "optional": true - }, - "chai": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-1.10.0.tgz", - "integrity": "sha512-E3L9M2SeQU1XagJkE9KJyTAXXHKJkJ1EsKkFp0Rl53lYa3mro2PVgYHNiCb2YRa2nUeyg7aqmI1EIcSBayNd5w==", - "dev": true, - "requires": { - "assertion-error": "1.0.0", - "deep-eql": "0.1.3" - } - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "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" - } - }, - "cli-width": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz", - "integrity": "sha512-eMU2akIeEIkCxGXUNmDnJq1KzOIiPnJ+rKqRe6hcxE3vIOPvpMrBYOn/Bl7zNlYJj/zQxXquAnozHUCf9Whnsg==", - "dev": true - }, - "combined-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", - "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", - "dev": true, - "optional": true, - "requires": { - "delayed-stream": "0.0.5" - } - }, - "commander": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha512-CD452fnk0jQyk3NfnK+KkR/hUPoHt5pVaKHogtyyv3N0U4QfAal9W0/rXLOg/vVZgQKa7jdtXypKs1YAip11uQ==", - "dev": true - }, - "coveralls": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.11.2.tgz", - "integrity": "sha512-+OK2imSCDXSYaOyAxGVUmzDfDtCYLW+gtdDVpjvq99R5Dyry4Puj3EQ/4YnsxNc6RHsuhx3wIkHSBIRaJZY5YQ==", - "dev": true, - "requires": { - "js-yaml": "3.0.1", - "lcov-parse": "0.0.6", - "log-driver": "1.2.4", - "request": "2.40.0" - }, - "dependencies": { - "esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", - "dev": true - }, - "js-yaml": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.0.1.tgz", - "integrity": "sha512-dgxgLzZS9qLWAQd/wrVG8tOiRSBJq1Ss9gbd7+fdBhcia3efHjLLpPkcUhKOyVACxTEAgnao3RT1kj1otiW42g==", - "dev": true, - "requires": { - "argparse": "~ 0.1.11", - "esprima": "~ 1.0.2" - } - } - } - }, - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha512-5sFRfAAmbHdIts+eKjR9kYJoF0ViCMVX9yqLu5A7S/v+nd077KgCITOMiirmyCBiZpKLDXbBOkYm6tu7rX/TKg==", - "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==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-eql": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", - "integrity": "sha512-6sEotTRGBFiNcqVoeHwnfopbSpi5NbH1VWJmYCVkmxMmaVTT0bUTrNaGyBwhgP4MZL012W/mkzIn3Da+iDYweg==", - "dev": true, - "requires": { - "type-detect": "0.1.1" - } - }, - "delayed-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", - "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", - "dev": true, - "optional": true - }, - "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha512-VzVc42hMZbYU9Sx/ltb7KYuQ6pqAw+cbFWVy4XKdkuEL2CFaRLGEnISPs7YdzaUGpi+CpIqvRmu7hPQ4T7EQ5w==", - "dev": true - }, - "doctrine": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz", - "integrity": "sha512-FSGvDB23RFdm/Z2hEINXN1AcBW5I4YBqpGD/lScJV34vuOwrPFyLHN9bwCzLa6lUmqS6ipdp5XlVJRQ6yJ5iSA==", - "dev": true, - "requires": { - "esutils": "^1.1.6", - "isarray": "0.0.1" - } - }, - "escodegen": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz", - "integrity": "sha512-2cd7+JUtUEmZVpGmfF9r+uRYXswJAkf85Ce8GvdBa7hSvdjY8hGo+rwC5syAgYzqHpfxNJzLntFjw6879yPbgQ==", - "dev": true, - "requires": { - "esprima": "^1.2.2", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.5.0", - "source-map": "~0.2.0" - }, - "dependencies": { - "esprima": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", - "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", - "dev": true - }, - "estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", - "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 - } - } - }, - "espree": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz", - "integrity": "sha512-HWJpgkL44cbjWiOTC9Pm34RZE57H1g9V4Ln9U14TUtiywFTLMMpMCtmQK5rkjbGBXigQT8bS3r45+Dt5+m0SZg==", - "dev": true - }, - "esprima": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz", - "integrity": "sha512-uM6hfS0/8ybNIj8SGRMdidPJy5uhWqWN/GIkyqnMAbCSL44yfFGLuBpRRCgOpBXBZt2OymQuM+IfahkqJq3DWw==", - "dev": true - }, - "esutils": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", - "integrity": "sha512-RG1ZkUT7iFJG9LSHr7KDuuMSlujfeTtMNIcInURxKAxhMtwQhI3NrQhz26gZQYlsYZQKzsnwtpKrFKj9K9Qu1A==", - "dev": true - }, - "fast-levenshtein": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz", - "integrity": "sha512-hYsfI0s4lfQ2rHVFKXwAr/L/ZSbq9TZwgXtZqW7ANcn9o9GKvcbWxOnxx7jykXf/Ezv1V8TvaBEKcGK7DWKX5A==", - "dev": true - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "dependencies": { - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true - } - } - }, - "forever-agent": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", - "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==", - "dev": true - }, - "form-data": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", - "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", - "dev": true, - "optional": true, - "requires": { - "async": "~0.9.0", - "combined-stream": "~0.0.4", - "mime": "~1.2.11" - }, - "dependencies": { - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==", - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==", - "dev": true, - "requires": { - "inherits": "2", - "minimatch": "0.3" - }, - "dependencies": { - "minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA==", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - } - } - }, - "globals": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz", - "integrity": "sha512-IHCTKEGo42ICEkTZBADyl4HX06hVdFF4qdJdqOgaBe5X8RE1/MrvubetsEtGTcwjs46djFq0Gc3+5RgTsc3UoQ==", - "dev": true - }, - "growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha512-RTBwDHhNuOx4F0hqzItc/siXCasGfC4DeWcBamclWd+6jWtBaeB/SGbMkGf0eiQoW7ib8JpvOgnUsmgMHI3Mfw==", - "dev": true - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", - "dev": true - }, - "http-signature": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", - "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", - "dev": true, - "optional": true, - "requires": { - "asn1": "0.1.11", - "assert-plus": "^0.1.5", - "ctype": "0.5.3" - } - }, - "inquirer": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz", - "integrity": "sha512-+rksrtdqQ8do7yOsmP5YIgbSdbZYuCIrnfH5vjFYGAr1XgJpMksb3rFZMJ3jiKuUyDVEA4MVDYbkA3ribJn3Tg==", - "dev": true, - "requires": { - "ansi-regex": "^1.1.1", - "chalk": "^1.0.0", - "cli-width": "^1.0.1", - "figures": "^1.3.5", - "lodash": "^3.3.1", - "readline2": "^0.1.1", - "rx": "^2.4.3", - "through": "^2.3.6" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "istanbul": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz", - "integrity": "sha512-8H/jxiee2UqX/mviKkPoKQYMxU2t995FC5PwO4zjWeDPOozjoeKqxEyN62l9o5+UgzvYQbrKgQjjxhGON8FcMg==", - "dev": true, - "requires": { - "abbrev": "1.0.x", - "async": "1.x", - "escodegen": "1.7.x", - "esprima": "2.5.x", - "fileset": "0.2.x", - "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": { - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, - "lcov-parse": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.6.tgz", - "integrity": "sha512-chuBQJZiBq28YUM6Yr3tf3h5Lxhb+DvhbxxSNpsHURSXiZXOzp49phiWG2pKHboOehJDujivwNQGRP8mAErMvQ==", - "dev": true - }, - "levn": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz", - "integrity": "sha512-mvp+NO++YH0B+e8cC/SvJxk6k5Z9Ngd3iXuz7tmT8vZCyQZj/5SI1GkFOiZGGPkm5wWGI9SUrqiAfPq7BJH+0w==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.0", - "type-check": "~0.3.1" - } - }, - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==", - "dev": true - }, - "lodash.clonedeep": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", - "integrity": "sha512-I8MpGh5z+6OixDAAb21teLSZDmqVPjlq02Q7ZFrbn2xnQHYYuJf6on/94SWpF/p0s3p/cEv/53ro4AhDOfCR0g==", - "dev": true, - "requires": { - "lodash._baseclone": "^3.0.0", - "lodash._bindcallback": "^3.0.0" - } - }, - "lodash.isplainobject": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz", - "integrity": "sha512-P4wZnho5curNqeEq/x292Pb57e1v+woR7DJ84DURelKB46lby8aDEGVobSaYtzHdQBWQrJSdxcCwjlGOvvdIyg==", - "dev": true, - "requires": { - "lodash._basefor": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.keysin": "^3.0.0" - } - }, - "lodash.merge": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz", - "integrity": "sha512-ZgGZpRhWLjivGUbjtApZR4HyLv/UAyoYqESVYkK4aLBJVHRrbFpG+GNnE9JPijliME4LkKM0SFI/WyOiBiv1+w==", - "dev": true, - "requires": { - "lodash._arraycopy": "^3.0.0", - "lodash._arrayeach": "^3.0.0", - "lodash._createassigner": "^3.0.0", - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0", - "lodash.isplainobject": "^3.0.0", - "lodash.istypedarray": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.keysin": "^3.0.0", - "lodash.toplainobject": "^3.0.0" - } - }, - "log-driver": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.4.tgz", - "integrity": "sha512-QmyGbAcBbHk8ysCGtT6FQ+LZML6+EeT0NdotCJGu72kNhknXtdso1G/NI0r7j45whFYNTU15XMW+JGOvGX07QQ==", - "dev": true - }, - "lolex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.1.0.tgz", - "integrity": "sha512-wGZrF3AlAWxG2j+6NyyttZ/UVxW8o/F+q01IUGuf2PiEIAUG9av/vpBS5TQHTQtzPmPJB4CZWjwyGR4C4aX83w==", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==", - "dev": true - }, - "mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", - "dev": true, - "optional": true - }, - "mime-types": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz", - "integrity": "sha512-echfutj/t5SoTL4WZpqjA1DCud1XO0WQF3/GJ48YBmc4ZMhCK77QA6Z/w6VTQERLKuJ4drze3kw2TUT8xZXVNw==", - "dev": true - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", - "dev": true, - "requires": { - "brace-expansion": "^1.0.0" - } - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, - "mocha": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", - "integrity": "sha512-jNt2iEk9FPmZLzL+sm4FNyOIDYXf2wUU6L4Cc8OIKK/kzgMHKPi4YhTZqG4bW4kQVdIv6wutDybRhXfdnujA1Q==", - "dev": true, - "requires": { - "commander": "2.3.0", - "debug": "2.2.0", - "diff": "1.4.0", - "escape-string-regexp": "1.0.2", - "glob": "3.2.11", - "growl": "1.9.2", - "jade": "0.26.3", - "mkdirp": "0.5.1", - "supports-color": "1.2.0", - "to-iso-string": "0.0.2" - }, - "dependencies": { - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha512-X0rGvJcskG1c3TgSCPqHJ0XJgwlcvOC7elJ5Y0hYuKBZoVqWpAMfLOeIh2UI/DCQ5ruodIjvsugZtjUYUw2pUw==", - "dev": true, - "requires": { - "ms": "0.7.1" - } - }, - "escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha512-cQpUid7bdTUnFin8S7BnNdOk+/eDqQmKgCANSyd/jAhrKEvxUvr9VQ8XZzXiOtest8NLfk3FSBZzwvemZNQ6Vg==", - "dev": true - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha512-lRLiIR9fSNpnP6TC4v8+4OU7oStC01esuNowdQ34L+Gk8e5Puoc88IqJ+XAY/B3Mn2ZKis8l8HX90oU8ivzUHg==", - "dev": true - }, - "supports-color": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "integrity": "sha512-mS5xsnjTh5b7f2DM6bch6lR582UCOTphzINlZnDsfpIRrwI6r58rb6YSSGsdexkm8qw2bBVO2ID2fnJOTuLiPA==", - "dev": true - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "oauth-sign": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", - "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", - "dev": true, - "optional": true - }, - "object-assign": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha512-CdsOUYIh5wIiozhJ3rLQgmUTgcyzFwZZrqhkKhODMoGtPKM+wt0h0CNIoauJWMsS9822EdzPsF/6mb4nLvPN5g==", - "dev": true - }, - "optionator": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", - "integrity": "sha512-jUr7aBk/kCInAEsl+qxuw4ORpe458atDKXNLhyvPUD4NfnsJsbAViX1b9nb/0rS62lO8cIFd1VoiaXLQ+MybOw==", - "dev": true, - "requires": { - "deep-is": "~0.1.2", - "fast-levenshtein": "~1.0.0", - "levn": "~0.2.5", - "prelude-ls": "~1.1.1", - "type-check": "~0.3.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", - "dev": true - } - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "qs": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz", - "integrity": "sha512-tHuOP9TN/1VmDM/ylApGK1QF3PSIP8I6bHDEfoKNQeViREQ/sfu1bAUrA1hoDun8p8Tpm7jcsz47g+3PiGoYdg==", - "dev": true - }, - "request": { - "version": "2.40.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz", - "integrity": "sha512-waNoGB4Z7bPn+lgqPk7l7hhze4Vd68jKccnwLeS7vr9GMxz0iWQbYTbBNWzfIk87Urx7V44pu29qjF/omej+Fw==", - "dev": true, - "requires": { - "aws-sign2": "~0.5.0", - "forever-agent": "~0.5.0", - "form-data": "~0.1.0", - "hawk": "1.1.1", - "http-signature": "~0.10.0", - "json-stringify-safe": "~5.0.0", - "mime-types": "~1.0.1", - "node-uuid": "~1.4.0", - "oauth-sign": "~0.3.0", - "qs": "~1.0.0", - "stringstream": "~0.0.4", - "tough-cookie": ">=0.12.0", - "tunnel-agent": "~0.4.0" - } - }, - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", - "dev": true - }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", - "dev": true - }, - "sinon": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.14.1.tgz", - "integrity": "sha512-cysrMyrriLwSn5Ye82xTCAVVS6Q6XLxlZE3jtPb4IFng2npN3lQWQ5Uyaud6cRpzztbEy2sbJkrDSbIl6OKUCA==", - "dev": true, - "requires": { - "formatio": "1.1.1", - "lolex": "1.1.0", - "util": ">=0.10.3 <1" - } - }, - "source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", - "dev": true, - "optional": true, - "requires": { - "amdefine": ">=0.0.4" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "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": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true - } - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", - "dev": true, - "optional": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-detect": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", - "integrity": "sha512-5rqszGVwYgBoDkIm2oUtvkfZMQ0vk29iDMU0W2qCa3rG0vPDNczCMT4hV/bLBgLg8k8ri6+u3Zbt+S/14eMzlA==", - "dev": true - }, - "underscore": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==", - "dev": true - }, - "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" - } - } - } + "version": "file:plugins/eslint" }, "eslint-plugin-promise": { "version": "5.2.0", @@ -35924,12 +28681,6 @@ "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", "dev": true }, - "esprima-fb": { - "version": "10001.1.0-dev-harmony-fb", - "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-10001.1.0-dev-harmony-fb.tgz", - "integrity": "sha512-z2dx3A/ZGNamsDjJS4FZPXnpoRCEkQXqouKBCOaJifyx4HkEVoSQ3YWFX18Scut1Aq9gnctzLWcWJgKkL0xNQw==", - "dev": true - }, "esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", @@ -35970,13 +28721,6 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, - "estraverse-fb": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.2.tgz", - "integrity": "sha512-wp3lfRrWy5EQD9TqesuYM1SKVP4ERT0cUatb4e8Vznf4K5IOpREhuyXZxGj3a9s9mvX5vGZKNHA4R9D4kp9Q9A==", - "dev": true, - "requires": {} - }, "estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -36039,16 +28783,6 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "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" - } - }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -36454,23 +29188,6 @@ "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", "dev": true }, - "falafel": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/falafel/-/falafel-0.1.6.tgz", - "integrity": "sha512-r1s3VwKzm6PB35MZmnfZoF6NTgSKRxf8How2lBsrDq81OsYXb/2fR8ysfURHCTlFpqJDQVA88iB70wFrFRYDsA==", - "dev": true, - "requires": { - "esprima": "~1.0.2" - }, - "dependencies": { - "esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", - "dev": true - } - } - }, "fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", @@ -36582,50 +29299,6 @@ } } }, - "fileset": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", - "integrity": "sha512-aK3PFyHSwWsBJCarRxMRIXSGamfroi9ehG8f4e5A2n5nSlEVHe8y44jNTIN4+HdZSpK3FNV0EdihH1iDWTdnGg==", - "dev": true, - "requires": { - "glob": "5.x", - "minimatch": "2.x" - }, - "dependencies": { - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", - "dev": true, - "requires": { - "brace-expansion": "^1.0.0" - } - } - } - }, - "fill-keys": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA==", - "dev": true, - "requires": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - } - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -36814,23 +29487,6 @@ "mime-types": "^2.1.12" } }, - "formatio": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", - "integrity": "sha512-cPh7is6k3d8tIUh+pnXXuAbD/uhSXGgqLPw0UrYpv5lfdJ+MMMSjx40JNpqP7Top9Nt25YomWEiRmkHbOvkCaA==", - "dev": true, - "requires": { - "samsam": "~1.1" - }, - "dependencies": { - "samsam": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.3.tgz", - "integrity": "sha512-t9rCPskf50hZ53eH8Z+cSWD4LfJBac+8vSSuzi1Y2HzygyXxtAl0BaR3hr6iI6A+nFQbkmJNC/brQLNEeVnrmg==", - "dev": true - } - } - }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -37010,24 +29666,6 @@ "globule": "^1.0.0" } }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dev": true, - "requires": { - "is-property": "^1.0.2" - } - }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", - "dev": true, - "requires": { - "is-property": "^1.0.0" - } - }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -37067,12 +29705,6 @@ "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", "dev": true }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", - "dev": true - }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -37107,68 +29739,6 @@ "assert-plus": "^1.0.0" } }, - "gh-got": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-1.1.0.tgz", - "integrity": "sha512-jo4rP5ugI6fZGjS0vmvHlM8P7EBA39p8to4r2i+LqYXxeg4M8qnPXiKaetDfH0YLXkO9Hfsa2mKIjMsGJwcdGQ==", - "dev": true, - "requires": { - "got": "^3.2.0", - "object-assign": "^2.0.0" - }, - "dependencies": { - "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" - } - }, - "got": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/got/-/got-3.3.1.tgz", - "integrity": "sha512-7chPlc0pWHjvq7B6dEEXz4GphoDupOvBSSl6AwRsAJX7GPTZ+bturaZiIigX4Dp6KrAP67nvzuKkNc0SLA0DKg==", - "dev": true, - "requires": { - "duplexify": "^3.2.0", - "infinity-agent": "^2.0.0", - "is-redirect": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "nested-error-stacks": "^1.0.0", - "object-assign": "^3.0.0", - "prepend-http": "^1.0.0", - "read-all-stream": "^3.0.0", - "timed-out": "^2.0.0" - }, - "dependencies": { - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", - "dev": true - } - } - }, - "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 - }, - "object-assign": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha512-CdsOUYIh5wIiozhJ3rLQgmUTgcyzFwZZrqhkKhODMoGtPKM+wt0h0CNIoauJWMsS9822EdzPsF/6mb4nLvPN5g==", - "dev": true - } - } - }, "git-up": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/git-up/-/git-up-6.0.0.tgz", @@ -37194,18 +29764,6 @@ "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==", "dev": true }, - "github-url-from-git": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/github-url-from-git/-/github-url-from-git-1.5.0.tgz", - "integrity": "sha512-WWOec4aRI7YAykQ9+BHmzjyNlkfJFG8QLXnDTsLz/kZefq7qkzdfo4p6fkYYMIq1aj+gZcQs/1HQhQh3DPPxlQ==", - "dev": true - }, - "github-url-from-username-repo": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/github-url-from-username-repo/-/github-url-from-username-repo-1.0.2.tgz", - "integrity": "sha512-Tj8CQqRoFVTglGdQ8FQmfq8gOOoOYZX7tnOKP8jq8Hdz2OTDhxvtlkLAbrqMYZ7X/YdaYQoUG1IBWxISBfqZ+Q==", - "dev": true - }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -38870,12 +31428,6 @@ "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", "dev": true }, - "has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha512-kaNz5OTAYYmt646Hkqw50/qyxP2vFnTVu5AQ1Zmk22Kk5+4Qx6BpO8+u7IKsML5fOsFk0ZT0AcCJNYwcvaLBvw==", - "dev": true - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -38943,46 +31495,6 @@ } } }, - "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": { - "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" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "hast-util-is-element": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz", @@ -39026,19 +31538,6 @@ "integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==", "dev": true }, - "hawk": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", - "integrity": "sha512-am8sVA2bCJIw8fuuVcKvmmNnGFUGW8spTkVtj2fXTEZVkfN42bwFZFtDem57eFi+NSxurJB8EQ7Jd3uCHLn8Vw==", - "dev": true, - "optional": true, - "requires": { - "boom": "0.4.x", - "cryptiles": "0.2.x", - "hoek": "0.9.x", - "sntp": "0.2.x" - } - }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -39051,24 +31550,6 @@ "integrity": "sha512-ig1eqDzJaB0pqEvlPVIpSSyMaO92bH1N2rJpLMN/nX396wTpDA4Eq0uK+7I/2XG17pFaaKE0kjV/XPeGt7Evjw==", "dev": true }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "hoek": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", - "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==", - "dev": true, - "optional": true - }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -39100,158 +31581,12 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "html-select": { - "version": "2.3.24", - "resolved": "https://registry.npmjs.org/html-select/-/html-select-2.3.24.tgz", - "integrity": "sha512-kQ+YZoVQ8Aux6bUqMVc0iufcZOv03+xYZ4J5v2beT5wkNrW/e2roZ8pnU4LunVOVBGFkbodFKR0TvuMkTdyrJQ==", - "dev": true, - "requires": { - "cssauron": "^1.1.0", - "duplexer2": "~0.0.2", - "inherits": "^2.0.1", - "minimist": "~0.0.8", - "readable-stream": "^1.0.27-1", - "split": "~0.3.0", - "stream-splicer": "^1.2.0", - "through2": "^1.0.0" - }, - "dependencies": { - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "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": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "requires": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, - "html-tokenize": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-1.2.5.tgz", - "integrity": "sha512-7sCme3w9Hiv/kfL6sO6ePTGAV5fY6P7WDZyOs0zfXXU8vsS1ps1CQfGe0J1yuAdcCnOJ9h66RLYX/e9Cife8yw==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "minimist": "~0.0.8", - "readable-stream": "~1.0.27-1", - "through2": "~0.4.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", - "dev": true - }, - "object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "through2": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", - "integrity": "sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==", - "dev": true, - "requires": { - "readable-stream": "~1.0.17", - "xtend": "~2.1.1" - } - }, - "xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", - "dev": true, - "requires": { - "object-keys": "~0.4.0" - } - } - } - }, "html-void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==", "dev": true }, - "http-browserify": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz", - "integrity": "sha512-Irf/LJXmE3cBzU1eaR4+NEX6bmVLqt1wkmDiA7kBwH7zmb0D8kBAXsDmQ88hhj/qv9iEZKlyGx/hrMcFi8sOHw==", - "dev": true, - "requires": { - "Base64": "~0.2.0", - "inherits": "~2.0.1" - } - }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -39308,12 +31643,6 @@ "resolve-alpn": "^1.0.0" } }, - "https-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", - "integrity": "sha512-EjDQFbgJr1vDD/175UJeSX3ncQ3+RUnCL5NkthQGHvF4VNHlzTy8ifJfTqz47qiPRqaFH58+CbuG3x51WuB1XQ==", - "dev": true - }, "https-proxy-agent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", @@ -39344,12 +31673,6 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, - "ignorepatterns": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignorepatterns/-/ignorepatterns-1.0.1.tgz", - "integrity": "sha512-9bm+Wivwyocr88go3y04hpX3qdFs6EgsxrjjpcI9C2GAqxcWYVMJaS9h9KL8ftJk1xP/8NzPxfHk6K1X7p0CRQ==", - "dev": true - }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -39374,33 +31697,12 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==", - "dev": true - }, "individual": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz", "integrity": "sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g==", "dev": true }, - "infinity-agent": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz", - "integrity": "sha512-CnfUJe5o2S9aAQWXGMhDZI4UL39MAJV3guOTfHHIdos4tuVHkl1j/J+1XLQn+CLIvqcpgQR/p+xXYXzcrhCe5w==", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -39422,26 +31724,6 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "inline-source-map": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.3.1.tgz", - "integrity": "sha512-RNlldBXZ7BBcVm3HjXIXiwKxih1lnuKbzeLBRDSB/qaqk8/g4JEZBjxpBQMhqEthQyGv7ycu8r/8PKGgBdIqrA==", - "dev": true, - "requires": { - "source-map": "~0.3.0" - }, - "dependencies": { - "source-map": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz", - "integrity": "sha512-jz8leTIGS8+qJywWiO9mKza0hJxexdeIYXhDHw9avTQcXSNAGk3hiiRMpmI2Qf9dOrZDrDpgH9VNefzuacWC9A==", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, "inquirer": { "version": "8.1.5", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", @@ -39509,127 +31791,6 @@ } } }, - "insert-module-globals": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-6.6.3.tgz", - "integrity": "sha512-ryk8hTKUZCc300SPOOwx30WhE5oRUssPDVlIoO8vtoMNBy5HGeesVRl3HF7ra4ll42T0IdnwD9XR9svh6+RRhg==", - "dev": true, - "requires": { - "combine-source-map": "~0.6.1", - "concat-stream": "~1.4.1", - "is-buffer": "^1.1.0", - "JSONStream": "^1.0.3", - "lexical-scope": "^1.2.0", - "process": "~0.11.0", - "through2": "^1.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "combine-source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.6.1.tgz", - "integrity": "sha512-XKRNtuZRlVDTuSGKsfZpXYz80y0XDbYS4a+FzafTgmYHy/ckruFBx7Nd6WaQnFHVI3O6IseWVdXUvZutMpjSkQ==", - "dev": true, - "requires": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.5.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.4.2" - } - }, - "concat-stream": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", - "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.9", - "typedarray": "~0.0.5" - } - }, - "convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", - "dev": true - }, - "inline-source-map": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.5.0.tgz", - "integrity": "sha512-2WtHG0qX9OH9TVcxsLVfq3Tzr+qtL6PtWgoh0XAAKe4KkdA/57Q+OGJuRJHA4mZ2OZnkJ/ZAaXf9krLB12/nIg==", - "dev": true, - "requires": { - "source-map": "~0.4.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 - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true - }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha512-Y8nIfcb1s/7DcobUz1yOO1GSp7gyL+D9zLHDehT7iRESqGSxjJ448Sg7rvfgsRJCnKLdSl11uGf0s9X80cH0/A==", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "requires": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, "internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -39883,25 +32044,6 @@ "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", "dev": true }, - "is-my-ip-valid": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", - "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", - "dev": true - }, - "is-my-json-valid": { - "version": "2.20.6", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", - "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", - "dev": true, - "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^5.0.0", - "xtend": "^4.0.0" - } - }, "is-nan": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", @@ -39959,12 +32101,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true - }, "is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -39983,18 +32119,6 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", - "dev": true - }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==", - "dev": true - }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -40324,30 +32448,6 @@ "textextensions": "^3.2.0" } }, - "jade": { - "version": "0.26.3", - "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha512-mkk3vzUHFjzKjpCXeu+IjXeZD+QOTjUUdubgmHtHTDwvAO2ZTkMTTVrapts5CWz3JvJryh/4KWZpjeZrCepZ3A==", - "dev": true, - "requires": { - "commander": "0.6.1", - "mkdirp": "0.3.0" - }, - "dependencies": { - "commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha512-0fLycpl1UMTGX257hRsu/arL/cUbcvQM4zMKwvLvzXtfdezIV4yotPS2dYtknF+NmEfWSoCEF6+hj9XLm/6hEw==", - "dev": true - }, - "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==", - "dev": true - } - } - }, "jake": { "version": "10.8.5", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", @@ -40614,12 +32714,6 @@ "supports-color": "^8.0.0" } }, - "jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", - "dev": true - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -40643,64 +32737,12 @@ } } }, - "js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", - "dev": true, - "requires": { - "xmlcreate": "^2.0.4" - } - }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, - "jsdoc": { - "version": "3.6.11", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.11.tgz", - "integrity": "sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==", - "dev": true, - "requires": { - "@babel/parser": "^7.9.4", - "@types/markdown-it": "^12.2.3", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "taffydb": "2.6.2", - "underscore": "~1.13.2" - }, - "dependencies": { - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - } - } - }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -40724,15 +32766,6 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "json-parse-helpfulerror": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", - "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==", - "dev": true, - "requires": { - "jju": "^1.1.0" - } - }, "json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -40745,15 +32778,6 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "json-stable-stringify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", - "integrity": "sha512-nKtD/Qxm7tWdZqJoldEC7fF0S41v0mWbeaXG3637stOWfyGxTgWTYE2wtfKmjzpvxv2MA2xzxsXOIiwUpkX6Qw==", - "dev": true, - "requires": { - "jsonify": "~0.0.0" - } - }, "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", @@ -40781,44 +32805,6 @@ "universalify": "^2.0.0" } }, - "jsonify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", - "dev": true - }, - "jsonlint": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.3.tgz", - "integrity": "sha512-jMVTMzP+7gU/IyC6hvKyWpUU8tmTkK5b3BPNuMI9U8Sit+YAWLlZwB6Y6YrdCxfg2kNz05p3XY3Bmm4m26Nv3A==", - "dev": true, - "requires": { - "JSV": "^4.0.x", - "nomnom": "^1.5.x" - } - }, - "jsonparse": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz", - "integrity": "sha512-fw7Q/8gFR8iSekUi9I+HqWIap6mywuoe7hQIg3buTVjuZgALKj4HAmm0X6f+TaL4c9NJbvyFQdaI2ppr5p6dnQ==", - "dev": true - }, - "jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "dev": true - }, - "JSONStream": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz", - "integrity": "sha512-l0NN3IcqrZfZBJp7JWDJIHsnPV7yzJWqsYxQzL8Fwdx1BmEMjLuvtYkv+P9pbvpyfP75/f4MeDZhWNU4is32uA==", - "dev": true, - "requires": { - "jsonparse": "0.0.5", - "through": ">=2.2.7 <3" - } - }, "jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -40831,12 +32817,6 @@ "verror": "1.10.0" } }, - "JSV": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", - "integrity": "sha512-ZJ6wx9xaKJ3yFUhq5/sk82PJMuUyLk277I8mQeyDgCTjGdjWJIvPfaU5LIXaMuaN2UO1X3kZH4+lgphublZUHw==", - "dev": true - }, "just-clone": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", @@ -41193,12 +33173,6 @@ "webpack-merge": "^4.1.5" } }, - "kew": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/kew/-/kew-0.1.7.tgz", - "integrity": "sha512-TQRJfHoVm4f2exuRqjcpURhzGcC4GEIPyiLquo4mBfz0JgsVg19VeyTmKp6RKSOIhHQ6F4SgEhsnUlBduGV9Yw==", - "dev": true - }, "keycode": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.1.tgz", @@ -41220,15 +33194,6 @@ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true }, - "klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, "kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -41251,25 +33216,6 @@ "integrity": "sha512-01TBSOqlHmLfcQhHseugGHLxPtU03OyZWaLDWt5MfzCkijG6xWFvAQPhKVn0cR2MMjYvBP9keQ8A3+rQEhLO5g==", "dev": true }, - "labeled-stream-splicer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-1.0.2.tgz", - "integrity": "sha512-3KBjPRnXrYC5h2jEf/d6hO7Lcl+38QzRVTOyHA2sFzZVMYwsUFuejlrOMwAjmz13hVBr9ruDS1RwE4YEz8P58w==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "isarray": "~0.0.1", - "stream-splicer": "^1.1.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - } - } - }, "last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", @@ -41323,15 +33269,6 @@ "type-check": "~0.4.0" } }, - "lexical-scope": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", - "integrity": "sha512-ntJ8IcBCuKwudML7vAuT/L0aIMU0+9vO25K4CjLPYgzf1NZ0bAhJJBZrvkO+oUGgKcbdkH8UZdRsaEg+wULLRw==", - "dev": true, - "requires": { - "astw": "^2.0.0" - } - }, "liftoff": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", @@ -41392,15 +33329,6 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, "listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -41482,87 +33410,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash._arraycopy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", - "integrity": "sha512-RHShTDnPKP7aWxlvXKiDT6IX2jCs6YZLCtNhOru/OX2Q/tzX295vVBK5oX1ECtN+2r86S0Ogy8ykP1sgCZAN0A==", - "dev": true - }, - "lodash._arrayeach": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", - "integrity": "sha512-Mn7HidOVcl3mkQtbPsuKR0Fj0N6Q6DQB77CtYncZcJc0bx5qv2q4Gl6a0LC1AN+GSxpnBDNnK3CKEm9XNA4zqQ==", - "dev": true - }, - "lodash._arraymap": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz", - "integrity": "sha512-IhRssF2bzQoFQ2Q5H1O52HuJY+OtcHDZekEhaMJ6RkUF+gpLlAsizSRsKp3Ho555ANRk69DFp5b4LOlym4S0bw==", - "dev": true - }, - "lodash._baseassign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, - "lodash._baseclone": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", - "integrity": "sha512-1K0dntf2dFQ5my0WoGKkduewR6+pTNaqX03kvs45y7G5bzl4B3kTR4hDfJIc2aCQDeLyQHhS280tc814m1QC1Q==", - "dev": true, - "requires": { - "lodash._arraycopy": "^3.0.0", - "lodash._arrayeach": "^3.0.0", - "lodash._baseassign": "^3.0.0", - "lodash._basefor": "^3.0.0", - "lodash.isarray": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, "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._basedifference": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz", - "integrity": "sha512-4BcJlOv36b3v+kHdJWcgsDi96ns8neNLuDtbzzjW3+eh3XhFVmFPH2tu6GJK2e5eRYMQ8izHU35iAyNjRyDtCQ==", - "dev": true, - "requires": { - "lodash._baseindexof": "^3.0.0", - "lodash._cacheindexof": "^3.0.0", - "lodash._createcache": "^3.0.0" - } - }, - "lodash._baseflatten": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz", - "integrity": "sha512-fESngZd+X4k+GbTxdMutf8ohQa0s3sJEHIcwtu4/LsIQ2JTDzdRxDCMQjW+ezzwRitLmHnacVVmosCbxifefbw==", - "dev": true, - "requires": { - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "lodash._basefor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", - "integrity": "sha512-6bc3b8grkpMgDcVJv9JYZAk/mHgcqMljzm7OsbmcE2FGUMmmLQTPHlh/dFqR8LA0GQ7z4K67JSotVKu5058v1A==", - "dev": true - }, - "lodash._baseindexof": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", - "integrity": "sha512-bSYo8Pc/f0qAkr8fPJydpJjtrHiSynYfYBjtANIgXv5xEf1WlTC63dIDlgu0s9dmTvzRu1+JJTxcIAHe+sH0FQ==", - "dev": true - }, "lodash._basetostring": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", @@ -41575,38 +33428,6 @@ "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", "dev": true }, - "lodash._bindcallback": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==", - "dev": true - }, - "lodash._cacheindexof": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", - "integrity": "sha512-S8dUjWr7SUT/X6TBIQ/OYoCHo1Stu1ZRy6uMUSKqzFnZp5G5RyQizSm6kvxD2Ewyy6AVfMg4AToeZzKfF99T5w==", - "dev": true - }, - "lodash._createassigner": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", - "integrity": "sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==", - "dev": true, - "requires": { - "lodash._bindcallback": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash.restparam": "^3.0.0" - } - }, - "lodash._createcache": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", - "integrity": "sha512-ev5SP+iFpZOugyab/DEUQxUeZP5qyciVTlgQ1f4Vlw7VUcCD8fVnyIqVUEIaoFH9zjAqdgi69KiofzvVmda/ZQ==", - "dev": true, - "requires": { - "lodash._getnative": "^3.0.0" - } - }, "lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", @@ -41619,22 +33440,6 @@ "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", "dev": true }, - "lodash._pickbyarray": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz", - "integrity": "sha512-tHzBIfgugzI7HV0y8MJS1z/ryWDh8NyD6AV+so9vlplRnhD4qBuwoyDt7g241ad3F43YDFghCN+R3iaFd4Azvw==", - "dev": true - }, - "lodash._pickbycallback": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz", - "integrity": "sha512-DVP27YmN0lB+j/Tgd/+gtxfmW/XihgWpQpHptBuwyp2fD9zEBRwwcnw6Qej16LUV8LRFuTqyoc0i6ON97d/C5w==", - "dev": true, - "requires": { - "lodash._basefor": "^3.0.0", - "lodash.keysin": "^3.0.0" - } - }, "lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", @@ -41730,12 +33535,6 @@ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", "dev": true }, - "lodash.istypedarray": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz", - "integrity": "sha512-lGWJ6N8AA3KSv+ZZxlTdn4f6A7kMfpJboeyvbFdE7IU9YAgweODqmOgdUHOA+c6lVWeVLysdaxciFXi+foVsWw==", - "dev": true - }, "lodash.keys": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", @@ -41747,44 +33546,12 @@ "lodash.isarray": "^3.0.0" } }, - "lodash.keysin": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", - "integrity": "sha512-YDB/5xkL3fBKFMDaC+cfGV00pbiJ6XoJIfRmBhv7aR6wWtbCW6IzkiWnTfkiHTF6ALD7ff83dAtB3OEaSoyQPg==", - "dev": true, - "requires": { - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==", - "dev": true - }, "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.omit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-3.1.0.tgz", - "integrity": "sha512-vC3fSzZDmPlwk+kCGYMQyUpPeRBgmOK/WrhmjlWVUjEch35gQR3iRbCV9rL7KgMHVeVhnq7A+TRrPvzvg67y9w==", - "dev": true, - "requires": { - "lodash._arraymap": "^3.0.0", - "lodash._basedifference": "^3.0.0", - "lodash._baseflatten": "^3.0.0", - "lodash._bindcallback": "^3.0.0", - "lodash._pickbyarray": "^3.0.0", - "lodash._pickbycallback": "^3.0.0", - "lodash.keysin": "^3.0.0", - "lodash.restparam": "^3.0.0" - } - }, "lodash.pickby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", @@ -41822,16 +33589,6 @@ "lodash._reinterpolate": "^3.0.0" } }, - "lodash.toplainobject": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz", - "integrity": "sha512-wMI0Ju1bvSmnBS3EcRRH/3zDnZOPpDtMtNDzbbNMKuTrEpALsf+sPyMeogmv63Y11qZQO7H1xFzohIEGRMjPYA==", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash.keysin": "^3.0.0" - } - }, "lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", @@ -41911,16 +33668,6 @@ "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": "sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==", - "dev": true, - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - } - }, "loupe": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", @@ -42028,85 +33775,12 @@ "object-visit": "^1.0.0" } }, - "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "dev": true, - "requires": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - } - } - }, - "markdown-it-anchor": { - "version": "8.6.5", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.5.tgz", - "integrity": "sha512-PI1qEHHkTNWT+X6Ip9w+paonfIQ+QZP9sCeMYi47oqhH+EsW8CrJ8J7CzV19QVOj6il8ATGbK2nTECj22ZHGvQ==", - "dev": true, - "requires": {} - }, "markdown-table": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.2.tgz", "integrity": "sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==", "dev": true }, - "markdownlint": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.0.6.tgz", - "integrity": "sha512-2jxomIcTY+HWnrMWv7Q/T93d7yp4RXNGkoQXWq5II1TgyQj5pFDoB7HZSCX57ATk9zZTb1++jwXR3uHn6AKmew==", - "dev": true, - "requires": { - "markdown-it": "^4.2.2" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "linkify-it": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz", - "integrity": "sha512-eGHwtlABkp1NOJSiKUNqBf3SYAS5jPHtvRXPAgNaQwTqmkTahjtiLH9NtxdR5IOPhNvwNMN/diswSfZKzUkhGg==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "markdown-it": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz", - "integrity": "sha512-Rl8dHHeLuAh3E72OPY0tY7CLvlxgHiLhlshIYswAAabAg4YDBLa6e/LTgNkkxBO2K61ESzoquPQFMw/iMrT1PA==", - "dev": true, - "requires": { - "argparse": "~1.0.2", - "entities": "~1.1.1", - "linkify-it": "~1.2.0", - "mdurl": "~1.0.0", - "uc.micro": "^1.0.0" - } - } - } - }, - "marked": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz", - "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==", - "dev": true - }, "marky": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.4.tgz", @@ -42148,17 +33822,6 @@ } } }, - "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-definitions": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", @@ -42425,66 +34088,6 @@ "readable-stream": "^2.0.1" } }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", - "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": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "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": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", - "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": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - } - } - }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -42925,24 +34528,6 @@ } } }, - "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.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, "mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -42983,18 +34568,6 @@ "dom-walk": "^0.1.0" } }, - "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": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -43262,190 +34835,6 @@ } } }, - "mocha-phantomjs": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/mocha-phantomjs/-/mocha-phantomjs-3.6.0.tgz", - "integrity": "sha512-siI6m2uw3Xyjruz9eEP8JTVHOtnOxdmnEqXM0IrOt3Nbw4oPJw6u8Q6MG6hqnbH9fJ3i60F3bYlmSEbgwuNsQw==", - "dev": true, - "requires": { - "commander": "~2.0.0", - "mocha": "~1.20.1" - }, - "dependencies": { - "diff": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.7.tgz", - "integrity": "sha512-0bTLzyr1S59cPsgAD/lR+ivvHTbgPb+k/mUR6WGqma1J6QDU+kUegI8uQFuH/cMUNK7JGN3Tk1Y5Jf2MO85WrA==", - "dev": true - }, - "glob": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", - "integrity": "sha512-WPaLsMHD1lYEqAmIQI6VOJSPwuBdGShDWnj1yUo0vQqEO809R8W3LM9OVU13CnnDhyv/EiNwOtxEW74SmrzS6w==", - "dev": true, - "requires": { - "graceful-fs": "~2.0.0", - "inherits": "2", - "minimatch": "~0.2.11" - } - }, - "graceful-fs": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "integrity": "sha512-hcj/NTUWv+C3MbqrVb9F+aH6lvTwEHJdx2foBxlrVq5h6zE8Bfu4pv4CAAqbDcZrw/9Ak5lsRXlY9Ao8/F0Tuw==", - "dev": true - }, - "growl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz", - "integrity": "sha512-VWv7s1EI41AG2LiCr7uAuxWikLDN1SQOuEUc37d/P34NAIIYgkvWYngNw0d9d9iCrDFL0SYCE9UQpxhIjjtuLg==", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==", - "dev": true - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha512-zZ+Jy8lVWlvqqeM8iZB7w7KmQkoJn8djM585z88rywrEbzoqawVa9FR5p2hwD+y74nfuKOjmNvi9gtWJNLqHvA==", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - }, - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", - "dev": true - }, - "mocha": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.20.1.tgz", - "integrity": "sha512-25Nq3BuIYCy80uEix+hBlZcr/gnLzpcYqfsaPAxZm2qbMFmed8I3nP8N05KagK4BTkGYUvsRJ47istvRqFO8fw==", - "dev": true, - "requires": { - "commander": "2.0.0", - "debug": "*", - "diff": "1.0.7", - "glob": "3.2.3", - "growl": "1.7.x", - "jade": "0.26.3", - "mkdirp": "0.3.5" - } - } - } - }, - "module-deps": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-3.9.1.tgz", - "integrity": "sha512-EbWWlSGaCVidEsLsSzkY6l/jm0IcGDSQ8tGwtjM8joTrxqxP0om02Px9Np8D7FMZ/vZFdsOGbio+WqkKQxYuTA==", - "dev": true, - "requires": { - "browser-resolve": "^1.7.0", - "concat-stream": "~1.4.5", - "defined": "^1.0.0", - "detective": "^4.0.0", - "duplexer2": "0.0.2", - "inherits": "^2.0.1", - "JSONStream": "^1.0.3", - "parents": "^1.0.0", - "readable-stream": "^1.1.13", - "resolve": "^1.1.3", - "stream-combiner2": "~1.0.0", - "subarg": "^1.0.0", - "through2": "^1.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "concat-stream": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.11.tgz", - "integrity": "sha512-X3JMh8+4je3U1cQpG87+f9lXHDrqcb2MVLg9L7o8b1UZ0DzhRrUpdn65ttzu10PpJPPI3MQNkis+oha6TSA9Mw==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.9", - "typedarray": "~0.0.5" - } - }, - "defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "dev": true - }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "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": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true - }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "requires": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, - "module-not-found-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha512-pEk4ECWQXV6z2zjhRZUongnLJNUeGQJ3w6OQ5ctGwD+i5o93qjRQUk2Rt6VdNeu3sEP0AB4LcfvdebpxBRVr4g==", - "dev": true - }, "morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -43618,13 +35007,6 @@ } } }, - "natives": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", - "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", - "dev": true, - "optional": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -43648,15 +35030,6 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "nested-error-stacks": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", - "integrity": "sha512-o32anp9JA7oezPOFSfG2BBXSdHepOm5FpJvwxHWDtfJ3Bg3xdi68S6ijPlEOfUg6quxZWyvJM+8fHk1yMDKspA==", - "dev": true, - "requires": { - "inherits": "~2.0.1" - } - }, "next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -43732,53 +35105,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, - "node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==", - "dev": true - }, - "nomnom": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", - "integrity": "sha512-5s0JxqhDx9/rksG2BTMVN1enjWSvPidpoSgViZU4ZXULyTe+7jxcCRLB6f42Z0l1xYJpleCBtSyY6Lwg3uu5CQ==", - "dev": true, - "requires": { - "chalk": "~0.4.0", - "underscore": "~1.6.0" - }, - "dependencies": { - "ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha512-3iF4FIKdxaVYT3JqQuY3Wat/T2t7TRbbQ94Fu50ZUCbLy4TFbTzr90NOHQodQkNqmeEGCw8WbeP78WNi6SKYUA==", - "dev": true - }, - "chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha512-sQfYDlfv2DGVtjdoQqxS0cEZDroyG8h6TamA6rvxwlrU5BaSLDx9xhatBYl2pxZ7gmpNaPFVwBtdGdu5rQ+tYQ==", - "dev": true, - "requires": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" - } - }, - "strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha512-behete+3uqxecWlDAm5lmskaSaISA+ThQ4oNNBDTBJt0x2ppR6IPqfZNuj6BLaLJ/Sji4TPZlcRyOis8wXQTLg==", - "dev": true - }, - "underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ==", - "dev": true - } - } - }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -43788,12 +35114,6 @@ "abbrev": "1" } }, - "nopt-usage": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/nopt-usage/-/nopt-usage-0.1.0.tgz", - "integrity": "sha512-Tg2sISrWBbSsCRqpEMmdxn3KZfacrd0N2NYpZQIq0MHxGHMjwzYlxeB9pVIom/g7CBK28atDUQsTlOfG0wOsNA==", - "dev": true - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -43835,39 +35155,6 @@ "once": "^1.3.2" } }, - "npm-license": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/npm-license/-/npm-license-0.2.3.tgz", - "integrity": "sha512-Sm6zqTVReBGe1C5A3Vr7pqYFmawM3oF/MKhhk0LRAOZPEOygr96KkiJ5P0ZQMDP3F7HRW6zyy7gxIIos+6foww==", - "dev": true, - "requires": { - "mkdirp": "~0.5.0", - "nopt": "~3.0.1", - "nopt-usage": "^0.1.0", - "package-license": "~0.1.1", - "pkginfo": "^0.3.0", - "read-installed": "~3.1.3", - "treeify": "~1.0.1", - "underscore": "~1.4.4" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, - "underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==", - "dev": true - } - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -43885,63 +35172,6 @@ } } }, - "npmconf": { - "version": "0.0.24", - "resolved": "https://registry.npmjs.org/npmconf/-/npmconf-0.0.24.tgz", - "integrity": "sha512-LX0bX+RmuBuEITg26i7+dx+d9cfYU+giB7eOiSkT5IwvuAzzIx02u4GXwSC3jsQMDMb/kXC57R8tybRSVYfbWw==", - "dev": true, - "requires": { - "config-chain": "~1.1.1", - "inherits": "~1.0.0", - "ini": "~1.1.0", - "mkdirp": "~0.3.3", - "nopt": "2", - "once": "~1.1.1", - "osenv": "0.0.3", - "semver": "~1.1.0" - }, - "dependencies": { - "inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha512-Al67oatbRSo3RV5hRqIoln6Y5yMVbJSIn4jEJNL7VCImzq/kLr7vvb6sFRJXqr8rpHc/2kJOM+y0sPKN47VdzA==", - "dev": true - }, - "ini": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.1.0.tgz", - "integrity": "sha512-B6L/jfyFRcG2dqKiHggWnfby52Iy07iabE4F6srQAr/OmVKBRE5uU+B5MQ+nQ7NiYnjz93gENh1GhqHzpDgHgA==", - "dev": true - }, - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", - "dev": true - }, - "nopt": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz", - "integrity": "sha512-gIOTA/uJuhPwFqp+spY7VQ1satbnGlD+iQVZxI18K6hs8Evq4sX81Ml7BB5byP/LsbR2yBVtmvdEmhi7evJ6Aw==", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "once": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/once/-/once-1.1.1.tgz", - "integrity": "sha512-frdJr++QKEg4+JylTX+NNLgSoO6M2pDNYOOXe4WGIYKKBADBI9nU3oa06y4D4FpAJ3obAsjExeBOnscYJB9Blw==", - "dev": true - }, - "semver": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-1.1.4.tgz", - "integrity": "sha512-9causpLEkYDrfTz7cprleLz9dnlb0oKsKRHl33K92wJmXLhVc2dGlrQGJT/sjtLOAyuoQZl+ClI77+lnvzPSKg==", - "dev": true - } - } - }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -44159,12 +35389,6 @@ "mimic-fn": "^2.1.0" } }, - "open": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/open/-/open-0.0.3.tgz", - "integrity": "sha512-Vm6nsJHcKV8kdOtHESAFAymOOf1VlKrttpwTqtLxvxRDIh8PSw4lWq5qk88QkAvNwnkv/1dNi2lvedhmam/ggw==", - "dev": true - }, "opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -44188,23 +35412,6 @@ } } }, - "optimist": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", - "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", - "dev": true, - "requires": { - "wordwrap": "~0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", - "dev": true - } - } - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -44300,12 +35507,6 @@ "readable-stream": "^2.0.1" } }, - "os-browserify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz", - "integrity": "sha512-aZicJZccvxWOZ0Bja2eAch2L8RIJWBuRYmM8Gwl/JjNtRltH0Itcz4eH/ESyuIWfse8cc93ZCf0XrzhXK2HEDA==", - "dev": true - }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -44327,12 +35528,6 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, - "osenv": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.0.3.tgz", - "integrity": "sha512-VBk1bfdaO4gh3OWO8LBuDY2alp0buL8YzQ6t13xyc8PQPrnUg5AgQvINQx3UkS4dom8UGCL597q4Y2+M4TPvmw==", - "dev": true - }, "p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -44375,18 +35570,6 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, - "package-license": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/package-license/-/package-license-0.1.2.tgz", - "integrity": "sha512-Q5zmx+M9ZJneMpYS6MlYL77gqeMYWuyErXMnQ/83WCztmYQD7Z0U9XGLvX9OKFFXwRj2NzdzlM0y9Jzcww2O1Q==", - "dev": true - }, - "pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", - "dev": true - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -44396,28 +35579,6 @@ "callsites": "^3.0.0" } }, - "parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==", - "dev": true, - "requires": { - "path-platform": "~0.11.15" - } - }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dev": true, - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, "parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", @@ -44491,12 +35652,6 @@ "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", @@ -44515,12 +35670,6 @@ "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": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -44532,12 +35681,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==", - "dev": true - }, "path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", @@ -44592,19 +35735,6 @@ "through": "~2.3" } }, - "pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "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" - } - }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -44617,184 +35747,6 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, - "phantomjs": { - "version": "1.9.7-15", - "resolved": "https://registry.npmjs.org/phantomjs/-/phantomjs-1.9.7-15.tgz", - "integrity": "sha512-s4PSN1L0iVwgv9ZkrSKcfojyPAtwGWhXxjn2p1P/ljuw3cx+FW3hKP00x247mIYbKeKSMylOd4euDQOMpUIAsg==", - "dev": true, - "requires": { - "adm-zip": "0.2.1", - "kew": "~0.1.7", - "mkdirp": "0.3.5", - "ncp": "0.4.2", - "npmconf": "0.0.24", - "progress": "^1.1.5", - "request": "2.36.0", - "request-progress": "^0.3.1", - "rimraf": "~2.2.2", - "which": "~1.0.5" - }, - "dependencies": { - "asn1": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", - "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", - "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", - "dev": true, - "optional": true - }, - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==", - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", - "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", - "dev": true, - "optional": true - }, - "combined-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", - "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", - "dev": true, - "optional": true, - "requires": { - "delayed-stream": "0.0.5" - } - }, - "delayed-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", - "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", - "dev": true, - "optional": true - }, - "forever-agent": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", - "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==", - "dev": true - }, - "form-data": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", - "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", - "dev": true, - "optional": true, - "requires": { - "async": "~0.9.0", - "combined-stream": "~0.0.4", - "mime": "~1.2.11" - } - }, - "hawk": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.0.0.tgz", - "integrity": "sha512-Sg+VzrI7TjUomO0rjD6UXawsj50ykn5sB/xKNW/IenxzRVyw/wt9A2FLzYpGL/r0QG5hyXY8nLx/2m8UutoDcg==", - "dev": true, - "optional": true, - "requires": { - "boom": "0.4.x", - "cryptiles": "0.2.x", - "hoek": "0.9.x", - "sntp": "0.2.x" - } - }, - "http-signature": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", - "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", - "dev": true, - "optional": true, - "requires": { - "asn1": "0.1.11", - "assert-plus": "^0.1.5", - "ctype": "0.5.3" - } - }, - "mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", - "dev": true - }, - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", - "dev": true - }, - "oauth-sign": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", - "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", - "dev": true, - "optional": true - }, - "progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", - "dev": true - }, - "qs": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", - "integrity": "sha512-kN+yNdAf29Jgp+AYHUmC7X4QdJPR8czuMWLNLc0aRxkQ7tB3vJQEONKKT9ou/rW7EbqVec11srC9q9BiVbcnHA==", - "dev": true - }, - "request": { - "version": "2.36.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.36.0.tgz", - "integrity": "sha512-iVii/ruMH9i8k++HYYPqi+nb1Pbgz7UOTGbFEiyhl7uDN8PhyFV2lGJa8XLIUS5tyt5scERcLkwqvCNF84Vv2Q==", - "dev": true, - "requires": { - "aws-sign2": "~0.5.0", - "forever-agent": "~0.5.0", - "form-data": "~0.1.0", - "hawk": "~1.0.0", - "http-signature": "~0.10.0", - "json-stringify-safe": "~5.0.0", - "mime": "~1.2.9", - "node-uuid": "~1.4.0", - "oauth-sign": "~0.3.0", - "qs": "~0.6.0", - "tough-cookie": ">=0.12.0", - "tunnel-agent": "~0.4.0" - } - }, - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", - "dev": true - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", - "dev": true, - "optional": true - }, - "which": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", - "dev": true - } - } - }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -44896,12 +35848,6 @@ } } }, - "pkginfo": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", - "integrity": "sha512-yO5feByMzAp96LtP58wvPKSbaKAi/1C4kV9XpTctr6EepnP6F33RBNOiVrdz9BrPA98U2BMFsTNHo44TWcbQ2A==", - "dev": true - }, "plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", @@ -44925,23 +35871,6 @@ } } }, - "portfinder": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-0.2.1.tgz", - "integrity": "sha512-U7dHe7mfMMP5cIwbqBHh/likunxAEiBsQLiThUWjyeRK6/C3um2uk+VGiekUW8q3h+s793gdNfagCM3aaXMeOg==", - "dev": true, - "requires": { - "mkdirp": "0.0.x" - }, - "dependencies": { - "mkdirp": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.0.7.tgz", - "integrity": "sha512-r4Ml2CH2Kl4B0+Lwq1SVru0vjMxdtR+UEb938WTQcsnU+EJz8dUV/HY0LTZh466nUSljia9cvqW3LZLWs3l8LQ==", - "dev": true - } - } - }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -44966,12 +35895,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", - "dev": true - }, "pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", @@ -45042,12 +35965,6 @@ "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==", "dev": true }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, "protocols": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz", @@ -45069,25 +35986,6 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, - "proxyquire": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-1.8.0.tgz", - "integrity": "sha512-mZZq4F50qaBkngvlf9paNfaSb5gtJ0mFPnBjda4NxCpXpMAaVfSLguRr9y2KXF6koOSBf4AanD2inuEQw3aCcA==", - "dev": true, - "requires": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.0", - "resolve": "~1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", - "dev": true - } - } - }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -45115,28 +36013,6 @@ "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.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -45271,12 +36147,6 @@ "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": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", - "dev": true - }, "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -45298,16 +36168,6 @@ "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", @@ -45330,103 +36190,6 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "read-all-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", - "integrity": "sha512-DI1drPHbmBcUDWrJ7ull/F2Qb8HkwBncVx8/RpKYFSIACYaVRQReISYPdZz/mt1y1+qMCOrfReTopERmaxtP6w==", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0", - "readable-stream": "^2.0.0" - } - }, - "read-installed": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-3.1.5.tgz", - "integrity": "sha512-XxD5VDz32T6rLCFfYElTif8/lkqcs9y51Gs2r30rAfT7LUGzJWaXLrwvn6fXkDsTzGcPr7Pj8CggOxwTxl/ozQ==", - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "graceful-fs": "2 || 3", - "read-package-json": "1", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - }, - "dependencies": { - "graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "optional": true, - "requires": { - "natives": "^1.1.3" - } - }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", - "dev": true - } - } - }, - "read-package-json": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-1.3.3.tgz", - "integrity": "sha512-9bayCl9cbXy3AL0qXhLQ0vliEgpzUVeLegSOrde3ujTHy2W18UsJiMUXEWkjbBB4ZnJzZPVuo2vAW62j4gY7gg==", - "dev": true, - "requires": { - "glob": "^5.0.3", - "graceful-fs": "2 || 3", - "json-parse-helpfulerror": "^1.0.2", - "normalize-package-data": "^1.0.0" - }, - "dependencies": { - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "optional": true, - "requires": { - "natives": "^1.1.3" - } - }, - "normalize-package-data": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-1.0.3.tgz", - "integrity": "sha512-pyPVJAzFiaioifPIsJBEoKJ9YcPHz7UhckZ7wqhBztLLCu6NozkIDrN+frzrCwjXtfunXfaMWIDtcDhnbO8fWA==", - "dev": true, - "requires": { - "github-url-from-git": "^1.3.0", - "github-url-from-username-repo": "^1.0.0", - "semver": "2 || 3 || 4" - } - }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ==", - "dev": true - } - } - }, "read-pkg": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", @@ -45568,41 +36331,6 @@ } } }, - "readable-wrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/readable-wrap/-/readable-wrap-1.0.0.tgz", - "integrity": "sha512-/8n0Mr10S+HGKFygQ42Z40JIXwafPH3A72pwmlNClThgsImV5LJJiCue5Je1asxwY082sYxq/+kTxH6nTn0w3g==", - "dev": true, - "requires": { - "readable-stream": "^1.1.13-1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - } - } - }, "readdir-glob": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", @@ -45612,18 +36340,6 @@ "minimatch": "^3.0.4" } }, - "readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -45633,39 +36349,6 @@ "picomatch": "^2.2.1" } }, - "readline2": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz", - "integrity": "sha512-qs8GGG+hLGMaDOGjd+mDglDoYcHDkjIY7z5RU0/ApsGT0qypyrWskNeemUqD+UxIXiZoMYT5aLwGp4ehoyZhIg==", - "dev": true, - "requires": { - "mute-stream": "0.0.4", - "strip-ansi": "^2.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", - "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", - "dev": true - }, - "mute-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz", - "integrity": "sha512-amvrY4m/7oZamehMoFi1tbwU/kXbVvRTGM2S7F+PZi3n51Jx+9AcSQ3EQsag3tR+hS2higfgOP/Kl8kri/X52A==", - "dev": true - }, - "strip-ansi": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", - "integrity": "sha512-2h8q2CP3EeOhDJ+jd932PRMpa3/pOJFGoF22J1U/DNbEK2gSW2DqeF46VjCXsSQXhC+k/l8/gaaRBQKL6hUPfQ==", - "dev": true, - "requires": { - "ansi-regex": "^1.0.0" - } - } - } - }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -45695,16 +36378,6 @@ } } }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==", - "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - } - }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -46004,15 +36677,6 @@ } } }, - "request-progress": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-0.3.1.tgz", - "integrity": "sha512-+IAgzH8yWAEgHjOOQzYEqRm0BpNlE6xFgsziGMiTxxMhrkBcCOe9bNWH7bDR+XtHToUMgCZlDgLqjk6cAP/+Ig==", - "dev": true, - "requires": { - "throttleit": "~0.0.2" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -46031,15 +36695,6 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, - "requizzle": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", - "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -46087,12 +36742,6 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, - "response-stream": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/response-stream/-/response-stream-0.0.0.tgz", - "integrity": "sha512-tWH3QWqkXv7AgYRXidIhPKO1SqPix2E0gM3x/vxf60LHQHWNS8AVrB3RnYexPAoo5dOc0bGzDlUgtsBvV3CWLA==", - "dev": true - }, "responselike": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", @@ -46135,36 +36784,12 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, - "rewire": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/rewire/-/rewire-2.5.2.tgz", - "integrity": "sha512-9wOlgRHTOzUv5dQO2XD2qWob+7yi/QXh7SSwLJW5wMAkAdkYuaCtcPuLAXUTllK0MjSvtpxUqAWMuSrrdt9VNw==", - "dev": true - }, "rfdc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", "dev": true }, - "rfile": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rfile/-/rfile-1.0.0.tgz", - "integrity": "sha512-aNeTpY8g6DYmqPvakau22B0SipQTskO8FtYXzn8qg4X4bN9ExIH8VAhq/L9w7N8HvESYeSSwk3e4GmW+rLLAxQ==", - "dev": true, - "requires": { - "callsite": "~1.0.0", - "resolve": "~0.3.0" - }, - "dependencies": { - "resolve": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.3.1.tgz", - "integrity": "sha512-mxx/I/wLjxtryDBtrrb0ZNzaYERVWaHpJ0W0Arm8N4l8b+jiX/U5yKcsj0zQpF9UuKN1uz80EUTOudON6OPuaQ==", - "dev": true - } - } - }, "rgb2hex": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.5.tgz", @@ -46180,47 +36805,6 @@ "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" - } - }, - "ruglify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ruglify/-/ruglify-1.0.0.tgz", - "integrity": "sha512-XfRj1YJdm/gnZNvmpQ5L+2YGRHglDGMPgJRbitgCxC3GzKVQF/t+ij1aNcNg2AnEXGtLHJDwoSWrAq3TUm0EVg==", - "dev": true, - "requires": { - "rfile": "~1.0", - "uglify-js": "~2.2" - }, - "dependencies": { - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - }, - "uglify-js": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", - "integrity": "sha512-viLk+/8G0zm2aKt1JJAVcz5J/5ytdiNaIsKgrre3yvSUjwVG6ZUujGH7E2TiPigZUwLYCe7eaIUEP2Zka2VJPA==", - "dev": true, - "requires": { - "optimist": "~0.3.5", - "source-map": "~0.1.7" - } - } - } - }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -46236,12 +36820,6 @@ "individual": "^2.0.0" } }, - "rx": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz", - "integrity": "sha512-u5qvfulb7NXoY/+OE28920WEgFi6aiDjf5iF9rA2f9tBXejLgTLd0WxkclvIQWjFFHfNJlb7pSTsrjgiDh+Uug==", - "dev": true - }, "rxjs": { "version": "7.5.5", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", @@ -46331,17 +36909,6 @@ } } }, - "script-injector": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/script-injector/-/script-injector-0.1.7.tgz", - "integrity": "sha512-0iW1D9UKsOPNUVBHvR76KePNS5TamEBN38bT5k7BqsXItsyV5oJTZbVsvOF3YS2xJ7GB7pszmgfDFJbIgHmrDQ==", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "through": "~2.3.4", - "trumpet": "~1.6.3" - } - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -46551,32 +37118,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "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" - } - }, - "shallow-copy": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", - "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==", - "dev": true - }, - "shasum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", - "integrity": "sha512-UTzHm/+AzKfO9RgPgRpDIuMSNie1ubXRaljjlhFMNGYoG7z+rm9AHLPMf70R7887xboDH9Q+5YQbWKObFHEAtw==", - "dev": true, - "requires": { - "json-stable-stringify": "~0.0.0", - "sha.js": "~2.4.4" - } - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -46592,35 +37133,6 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "shell-quote": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-0.0.1.tgz", - "integrity": "sha512-uEWz7wa9vnCi9w4mvKZMgbHFk3DCKjLQlZcy0tJxUH4NwZjRrPPHXAYIEt2TmJs600Dcgj0Z3fZLZKVPVdGNbQ==", - "dev": true - }, - "shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha512-Ny0KN4dyT8ZSCE0frtcbAJGoM/HTArpyPkeli1/00aYfm0sbD/Gk/4x7N2DP9QKGpBsiQH7n6rpm1L79RtviEQ==", - "dev": true - }, - "shelljs-nodecli": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shelljs-nodecli/-/shelljs-nodecli-0.1.1.tgz", - "integrity": "sha512-/e+APCWKKW9A8YMHKgDzhWQ21zPuDLjn6ATBczxbp6uUeiCSwvw95ynKAjMsRd1yrd5dlCkMKJoc/Lpwrt2w+A==", - "dev": true, - "requires": { - "shelljs": "~0.2" - }, - "dependencies": { - "shelljs": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz", - "integrity": "sha512-LQiM15qPbSyzHDFfI4v7EVhjBXG5PUAKWVBnVMBXwdlQSHZtzKYeKGzDHBIqpenPrCsPWqBSOF5o7oSvSfX+CA==", - "dev": true - } - } - }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -46632,12 +37144,6 @@ "object-inspect": "^1.9.0" } }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", - "dev": true - }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -46736,12 +37242,6 @@ } } }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", - "dev": true - }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -46917,16 +37417,6 @@ } } }, - "sntp": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", - "integrity": "sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==", - "dev": true, - "optional": true, - "requires": { - "hoek": "0.9.x" - } - }, "socket.io": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", @@ -47092,23 +37582,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sse-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/sse-stream/-/sse-stream-0.0.4.tgz", - "integrity": "sha512-rnDUubW7a4CZAB5D0r2OtFU/zvY05MoNGHMX6deAYK0wWaizrNcHzimf+Nk5y0sqntGAPpWEnIopWrrAf2TBVg==", - "dev": true, - "requires": { - "through": "~2.2.7" - }, - "dependencies": { - "through": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", - "integrity": "sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg==", - "dev": true - } - } - }, "sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", @@ -47232,42 +37705,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, - "stream-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-1.0.0.tgz", - "integrity": "sha512-e+V5xc4LlkOiRr64kZTUdb11exsbpSnwb9uwmXaHeDXCpfHg7vaefMJOxi21Pe74ZOqjZ87blBcqqpNAM4Ku0g==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^1.0.27-1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - } - } - }, "stream-buffers": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", @@ -47283,81 +37720,6 @@ "duplexer": "~0.1.1" } }, - "stream-combiner2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.0.2.tgz", - "integrity": "sha512-7DO1SfBVnyIyo9ytUjSyVojT5bp1ZY6h3pj7HUs6PwcRSd/r8mBOHbRwYC7nbHRakKzMKyNp5HWJRv4GgVherA==", - "dev": true, - "requires": { - "duplexer2": "~0.0.2", - "through2": "~0.5.1" - }, - "dependencies": { - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "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": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "through2": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", - "integrity": "sha512-zexCrAOTbjkBCXGyozn7hhS3aEaqdrc59mAD2E3dKYzV1vFuEGQ1hEDJN2oQMQFwy4he2zyLqPZV+AlfS8ZWJA==", - "dev": true, - "requires": { - "readable-stream": "~1.0.17", - "xtend": "~3.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - } - } - }, - "xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", - "dev": true - } - } - }, "stream-exhaust": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", @@ -47370,56 +37732,6 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, - "stream-splicer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-1.3.2.tgz", - "integrity": "sha512-nmUMEbdm/sZYqe9dZs7mqJvTYpunsDbIWI5FiBCMc/hMVd6vwzy+ITmo7C3gcLYqrn+uQ1w+EJwooWvJ997JAA==", - "dev": true, - "requires": { - "indexof": "0.0.1", - "inherits": "^2.0.1", - "isarray": "~0.0.1", - "readable-stream": "^1.1.13-1", - "readable-wrap": "^1.0.0", - "through2": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "requires": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, "streamroller": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.4.tgz", @@ -47495,13 +37807,6 @@ "character-entities-legacy": "^3.0.0" } }, - "stringstream": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", - "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", - "dev": true, - "optional": true - }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -47529,30 +37834,6 @@ "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": "sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==", - "dev": true, - "requires": { - "get-stdin": "^4.0.1" - } - }, - "strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", - "dev": true - }, - "subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", - "dev": true, - "requires": { - "minimist": "^1.1.0" - } - }, "suffix": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", @@ -47583,15 +37864,6 @@ "es6-symbol": "^3.1.1" } }, - "syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", - "dev": true, - "requires": { - "acorn-node": "^1.2.0" - } - }, "table": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", @@ -47625,12 +37897,6 @@ } } }, - "taffydb": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", - "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", - "dev": true - }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -47819,12 +38085,6 @@ "integrity": "sha512-mk82dS8eRABNbeVJrEiN5/UMSCliINAuz8mkUwH4SwslkNP//gbEzlWNS5au0z5Dpx40SQxzqZevZkn+WYJ9Dw==", "dev": true }, - "throttleit": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", - "integrity": "sha512-HtlTFeyYs1elDM2txiIGsdXHaq8kffVaZH/QEBRbo95zQqzlsBx5ELKhkPOZVad9OK9oxzwx6UrQN8Vfh/+yag==", - "dev": true - }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -47881,21 +38141,6 @@ "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", "dev": true }, - "timed-out": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", - "integrity": "sha512-pqqJOi1rF5zNs/ps4vmbE4SFCrM4iR7LW+GHAsHqO/EumqbIWceioevYLM5xZRgQSH6gFgL9J/uB7EcJhQ9niQ==", - "dev": true - }, - "timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==", - "dev": true, - "requires": { - "process": "~0.11.0" - } - }, "timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", @@ -47960,12 +38205,6 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, - "to-iso-string": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", - "integrity": "sha512-oeHLgfWA7d0CPQa6h0+i5DAJZISz5un0d5SHPkw+Untclcvzv9T+AC3CvGXlZJdOlIbxbTfyyzlqCXc5hjpXYg==", - "dev": true - }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -48075,24 +38314,12 @@ "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", "dev": true }, - "treeify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.0.1.tgz", - "integrity": "sha512-i3MKN4nGEOuVAcd7s5MtAc2+QBExwcaRT/6/CzUSYVYwzM58bJ3H3wwCPu2PEAGjVPHjfIC/MPaXsxPGUk07cg==", - "dev": true - }, "trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", "dev": true }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==", - "dev": true - }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -48105,65 +38332,6 @@ "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", "dev": true }, - "trumpet": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/trumpet/-/trumpet-1.6.6.tgz", - "integrity": "sha512-A4cn/zuq0AsxS5M8cD+7GUoIhOoK2qkcpFUwlpHnNOsTPzCq7FITZV9lg95ydupJcQRi/kFQzGIn7oN3kNp10w==", - "dev": true, - "requires": { - "duplexer2": "~0.0.2", - "html-select": "^2.3.5", - "html-tokenize": "^1.1.1", - "inherits": "^2.0.0", - "readable-stream": "^1.0.27-1", - "through2": "^1.0.0" - }, - "dependencies": { - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", - "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": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", - "dev": true, - "requires": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, "tsconfig-paths": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz", @@ -48193,12 +38361,6 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "dev": true - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -48256,6 +38418,13 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true, + "peer": true + }, "typescript-compare": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", @@ -48283,12 +38452,6 @@ "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", "dev": true }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, "uglify-js": { "version": "3.15.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz", @@ -48296,77 +38459,6 @@ "dev": true, "optional": true }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", - "dev": true - }, - "umd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/umd/-/umd-2.1.0.tgz", - "integrity": "sha512-mEAJeceExHnblcAwN3BQtDPYOrTy4ALeBh6nQ9KW0cUCd0UU714jAfil2jvq09b67IizwJIiTVFOjE+/52Dyvw==", - "dev": true, - "requires": { - "rfile": "~1.0.0", - "ruglify": "~1.0.0", - "through": "~2.3.4", - "uglify-js": "~2.4.0" - }, - "dependencies": { - "async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==", - "dev": true - }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", - "dev": true - }, - "source-map": { - "version": "0.1.34", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz", - "integrity": "sha512-yfCwDj0vR9RTwt3pEzglgb3ZgmcXHt6DjG3bjJvzPwTL+5zDQ2MhmSzAcTy0GTiQuCiriSWXvWM1/NhKdXuoQA==", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - }, - "uglify-js": { - "version": "2.4.24", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz", - "integrity": "sha512-tktIjwackfZLd893KGJmXc1hrRHH1vH9Po3xFh1XBjjeGAnN02xJ3SuoA+n1L29/ZaCA18KzCFlckS+vfPugiA==", - "dev": true, - "requires": { - "async": "~0.2.6", - "source-map": "0.1.34", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.5.4" - } - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", - "dev": true - }, - "yargs": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz", - "integrity": "sha512-5j382E4xQSs71p/xZQsU1PtRA2HXPAjX0E0DkoGLxwNASMOKX6A9doV1NrZmj85u2Pjquz402qonBzz/yLPbPA==", - "dev": true, - "requires": { - "camelcase": "^1.0.2", - "decamelize": "^1.0.0", - "window-size": "0.1.0", - "wordwrap": "0.0.2" - } - } - } - }, "unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", @@ -48395,18 +38487,6 @@ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, - "underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "dev": true - }, - "underscore.string": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", - "integrity": "sha512-yxkabuCaIBnzfIvX3kBxQqCs0ar/bfJwDnFEHJUm/ZrRVhT3IItdRF5cZjARLzEnyQYtIUhsZ2LG2j3HidFOFQ==", - "dev": true - }, "undertaker": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", @@ -48712,12 +38792,6 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha512-aggiKfEEubv3UwRNqTzLInZpAOmKzwdHqEBmW/hBA/mt99eg+b4VrX6i+IRLxU8+WJYfa33rGwRseg4eElUgsQ==", - "dev": true - }, "util": { "version": "0.12.4", "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", @@ -48738,12 +38812,6 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "dev": true - }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -49085,15 +39153,6 @@ "source-map": "^0.5.1" } }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha512-NyZNR3WDah+NPkjh/YmhuWSsT4a0mF0BJYgUmvrJ70zxjTXh5Y2Asobxlh0Nfs0PCFB5FVpRJft7NozAWFMwLQ==", - "dev": true, - "requires": { - "indexof": "0.0.1" - } - }, "void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -49202,9 +39261,9 @@ } }, "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -49516,12 +39575,6 @@ "is-typed-array": "^1.1.7" } }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", - "dev": true - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -49610,18 +39663,6 @@ "dev": true, "requires": {} }, - "xml-escape": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz", - "integrity": "sha512-gCT82WbwOT9SBI/94j5i0tqHpjHIP/0kP11BS8s2wcBtdcFsDNLS9sLvA+C55fD3hpGhgnE/r7hfeBFkiMATjw==", - "dev": true - }, - "xmlcreate": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "dev": true - }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", From b744a9d7e478cf8f5529db48dcbd3daf1654594f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Oct 2022 12:45:11 -0700 Subject: [PATCH 054/367] Bump @xmldom/xmldom from 0.7.5 to 0.7.6 (#9144) Bumps [@xmldom/xmldom](https://github.com/xmldom/xmldom) from 0.7.5 to 0.7.6. - [Release notes](https://github.com/xmldom/xmldom/releases) - [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md) - [Commits](https://github.com/xmldom/xmldom/compare/0.7.5...0.7.6) --- updated-dependencies: - dependency-name: "@xmldom/xmldom" dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index e11da6fba7b..ec0bebcd2d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3711,9 +3711,9 @@ } }, "node_modules/@xmldom/xmldom": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz", - "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==", + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.6.tgz", + "integrity": "sha512-HHXP9hskkFQHy8QxxUXkS7946FFIhYVfGqsk0WLwllmexN9x/+R4UBLvurHEuyXRfVEObVR8APuQehykLviwSQ==", "dev": true, "engines": { "node": ">=10.0.0" @@ -25217,9 +25217,9 @@ } }, "@xmldom/xmldom": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz", - "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==", + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.6.tgz", + "integrity": "sha512-HHXP9hskkFQHy8QxxUXkS7946FFIhYVfGqsk0WLwllmexN9x/+R4UBLvurHEuyXRfVEObVR8APuQehykLviwSQ==", "dev": true }, "@xtuc/ieee754": { From 0a267ddb587f955494bb9cf6cb49dba0810fd933 Mon Sep 17 00:00:00 2001 From: matthieularere-msq <63732822+matthieularere-msq@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:51:50 +0200 Subject: [PATCH 055/367] Oxxion Rtd Module: initial module release (#9102) * add oxxionRtdProvider new module * + * add tests * Update oxxionRtdProvider.md * Update oxxionRtdProvider.js * Update oxxionRtdProvider_spec.js * + * change test * change tests * change tests * change tests * change tests * requests changes * requests changes * requested changes --- modules/oxxionRtdProvider.js | 119 ++++++++++++++++ modules/oxxionRtdProvider.md | 48 +++++++ test/spec/modules/oxxionRtdProvider_spec.js | 142 ++++++++++++++++++++ 3 files changed, 309 insertions(+) create mode 100644 modules/oxxionRtdProvider.js create mode 100644 modules/oxxionRtdProvider.md create mode 100644 test/spec/modules/oxxionRtdProvider_spec.js diff --git a/modules/oxxionRtdProvider.js b/modules/oxxionRtdProvider.js new file mode 100644 index 00000000000..b4964818ddf --- /dev/null +++ b/modules/oxxionRtdProvider.js @@ -0,0 +1,119 @@ +import { submodule } from '../src/hook.js' +import { deepAccess, logInfo } from '../src/utils.js' + +const oxxionRtdSearchFor = [ 'adUnitCode', 'auctionId', 'bidder', 'bidderCode', 'bidId', 'cpm', 'creativeId', 'currency', 'width', 'height', 'mediaType', 'netRevenue', 'originalCpm', 'originalCurrency', 'requestId', 'size', 'source', 'status', 'timeToRespond', 'transactionId', 'ttl', 'sizes', 'mediaTypes', 'src', 'userId', 'labelAny', 'adId' ]; +const LOG_PREFIX = 'oxxionRtdProvider submodule: '; + +const allAdUnits = []; + +/** @type {RtdSubmodule} */ +export const oxxionSubmodule = { + name: 'oxxionRtd', + init: init, + onAuctionEndEvent: onAuctionEnd, + getBidRequestData: getAdUnits, +}; + +function init(config, userConsent) { + if (!config.params || !config.params.domain || !config.params.contexts || !Array.isArray(config.params.contexts) || config.params.contexts.length == 0) { + return false + } + return true; +} + +function getAdUnits(reqBidsConfigObj, callback, config, userConsent) { + const reqAdUnits = reqBidsConfigObj.adUnits; + if (Array.isArray(reqAdUnits)) { + reqAdUnits.forEach(adunit => { + if (config.params.contexts.includes(deepAccess(adunit, 'mediaTypes.video.context'))) { + allAdUnits.push(adunit); + } + }); + } +} + +function insertVideoTracking(bidResponse, config, maxCpm) { + if (bidResponse.mediaType === 'video') { + const trackingUrl = getImpUrl(config, bidResponse, maxCpm); + if (!trackingUrl) { + return; + } + // Vast Impression URL + if (bidResponse.vastUrl) { + bidResponse.vastImpUrl = bidResponse.vastImpUrl + ? trackingUrl + '&url=' + encodeURI(bidResponse.vastImpUrl) + : trackingUrl + } + // Vast XML document + if (bidResponse.vastXml !== undefined) { + const doc = new DOMParser().parseFromString(bidResponse.vastXml, 'text/xml'); + const wrappers = doc.querySelectorAll('VAST Ad Wrapper, VAST Ad InLine'); + let hasAltered = false; + if (wrappers.length) { + wrappers.forEach(wrapper => { + const impression = doc.createElement('Impression'); + impression.appendChild(doc.createCDATASection(trackingUrl)); + wrapper.appendChild(impression) + }); + bidResponse.vastXml = new XMLSerializer().serializeToString(doc); + hasAltered = true; + } + if (hasAltered) { + logInfo(LOG_PREFIX + 'insert into vastXml for adId ' + bidResponse.adId); + } + } + } +} + +function getImpUrl(config, data, maxCpm) { + const adUnitCode = data.adUnitCode; + const adUnits = allAdUnits.find(adunit => adunit.code === adUnitCode && + 'mediaTypes' in adunit && + 'video' in adunit.mediaTypes && + typeof adunit.mediaTypes.video.context === 'string'); + const context = adUnits !== undefined + ? adUnits.mediaTypes.video.context + : 'unknown'; + if (!config.params.contexts.includes(context)) { + return false; + } + let trackingImpUrl = 'https://' + config.params.domain + '.oxxion.io/analytics/vast_imp?'; + trackingImpUrl += oxxionRtdSearchFor.reduce((acc, param) => { + switch (typeof data[param]) { + case 'string': + case 'number': + acc += param + '=' + data[param] + '&' + break; + } + return acc; + }, ''); + const cpmIncrement = Math.round(100000 * (data.cpm - maxCpm)) / 100000; + return trackingImpUrl + 'cpmIncrement=' + cpmIncrement + '&context=' + context; +} + +function onAuctionEnd(auctionDetails, config, userConsent) { + const transactionsToCheck = {} + auctionDetails.adUnits.forEach(adunit => { + if (config.params.contexts.includes(deepAccess(adunit, 'mediaTypes.video.context'))) { + transactionsToCheck[adunit.transactionId] = {'bids': {}, 'maxCpm': 0.0, 'secondMaxCpm': 0.0}; + } + }); + for (const key in auctionDetails.bidsReceived) { + if (auctionDetails.bidsReceived[key].transactionId in transactionsToCheck) { + transactionsToCheck[auctionDetails.bidsReceived[key].transactionId]['bids'][auctionDetails.bidsReceived[key].adId] = {'key': key, 'cpm': auctionDetails.bidsReceived[key].cpm}; + if (auctionDetails.bidsReceived[key].cpm > transactionsToCheck[auctionDetails.bidsReceived[key].transactionId]['maxCpm']) { + transactionsToCheck[auctionDetails.bidsReceived[key].transactionId]['secondMaxCpm'] = transactionsToCheck[auctionDetails.bidsReceived[key].transactionId]['maxCpm']; + transactionsToCheck[auctionDetails.bidsReceived[key].transactionId]['maxCpm'] = auctionDetails.bidsReceived[key].cpm; + } else if (auctionDetails.bidsReceived[key].cpm > transactionsToCheck[auctionDetails.bidsReceived[key].transactionId]['secondMaxCpm']) { + transactionsToCheck[auctionDetails.bidsReceived[key].transactionId]['secondMaxCpm'] = auctionDetails.bidsReceived[key].cpm; + } + } + }; + Object.keys(transactionsToCheck).forEach(transaction => { + Object.keys(transactionsToCheck[transaction]['bids']).forEach(bid => { + insertVideoTracking(auctionDetails.bidsReceived[transactionsToCheck[transaction]['bids'][bid].key], config, transactionsToCheck[transaction].secondMaxCpm); + }); + }); +} + +submodule('realTimeData', oxxionSubmodule); diff --git a/modules/oxxionRtdProvider.md b/modules/oxxionRtdProvider.md new file mode 100644 index 00000000000..061acdbe11a --- /dev/null +++ b/modules/oxxionRtdProvider.md @@ -0,0 +1,48 @@ +# Overview + +Module Name: Oxxion Rtd Provider +Module Type: Rtd Provider +Maintainer: tech@oxxion.io + +# Oxxion Real-Time-Data submodule + +Oxxion helps you to understand how your prebid stack performs. +This Rtd module is to use in order to improve video events tracking. + +# Integration + +Make sure to have the following modules listed while building prebid : `rtdModule,oxxionRtdProvider` +`rtbModule` is required to activate real-time-data submodules. +For example : +``` +gulp build --modules=schain,priceFloors,currency,consentManagement,appnexusBidAdapter,rubiconBidAdapter,rtdModule,oxxionRtdProvider +``` + +Then add the oxxion Rtd module to your prebid configuration : +``` +pbjs.setConfig( + ... + realTimeData: { + auctionDelay: 200, + dataProviders: [ + { + name: "oxxionRtd", + waitForIt: true, + params: { + domain: "test.endpoint", + contexts: ["instream"], + } + } + ] + } + ... +) +``` + +# setConfig Parameters + +| Name | Type | Description | +|:---------------------------------|:---------|:------------------------------------------------------------------------------------------------------------| +| domain | String | This string identifies yourself in Oxxion's systems and is provided to you by your Oxxion representative. | +| contexts | Array | Array defining which video contexts to add tracking events into. Values can be instream and/or outstream. | + diff --git a/test/spec/modules/oxxionRtdProvider_spec.js b/test/spec/modules/oxxionRtdProvider_spec.js new file mode 100644 index 00000000000..776076cc215 --- /dev/null +++ b/test/spec/modules/oxxionRtdProvider_spec.js @@ -0,0 +1,142 @@ +import {oxxionSubmodule} from 'modules/oxxionRtdProvider.js'; +import 'src/prebid.js'; + +const utils = require('src/utils.js'); + +const moduleConfig = { + params: { + domain: 'test.endpoint', + contexts: ['instream', 'outstream'] + } +}; + +let request = { + 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', + 'timestamp': 1647424261187, + 'auctionEnd': 1647424261714, + 'auctionStatus': 'completed', + 'adUnits': [ + { + 'code': 'msq_tag_200124_banner', + 'mediaTypes': { 'banner': { 'sizes': [[300, 600]] } }, + 'bids': [{'bidder': 'appnexus', 'params': {'placementId': 123456}}], + 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40' + }, + { + 'code': 'msq_tag_200125_video', + 'mediaTypes': { 'video': { 'context': 'instream' }, playerSize: [640, 480], mimes: ['video/mp4'] }, + 'bids': [ + {'bidder': 'mediasquare', 'params': {'code': 'publishername_atf_desktop_rg_video', 'owner': 'test'}}, + {'bidder': 'appnexusAst', 'params': {'placementId': 345678}}, + ], + 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b41' + }, + ] +}; + +let bids = [{ + 'bidderCode': 'mediasquare', + 'width': 640, + 'height': 480, + 'statusMessage': 'Bid available', + 'adId': '3647626fdbe68a', + 'requestId': '2d891705d2125b', + 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b41', + 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', + 'mediaType': 'video', + 'source': 'client', + 'cpm': 0.9723, + 'creativeId': 'freewheel|AdswizzAd71819', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 2000, + 'mediasquare': { + 'bidder': 'freewheel', + 'code': 'test/publishername_atf_desktop_rg_video', + 'hasConsent': true + }, + 'meta': { + 'advertiserDomains': [ + 'unknown' + ] + }, + 'vastUrl': 'https://some.vast-url.com', + 'vastXml': '', + 'adapterCode': 'mediasquare', + 'originalCpm': 0.9723, + 'originalCurrency': 'USD', + 'responseTimestamp': 1665505150740, + 'requestTimestamp': 1665505150594, + 'bidder': 'mediasquare', + 'adUnitCode': 'msq_tag_200125_video', + 'timeToRespond': 146, + 'size': '640x480', +}, { + 'bidderCode': 'appnexusAst', + 'width': 640, + 'height': 480, + 'statusMessage': 'Bid available', + 'adId': '4b2e1581c0ca1a', + 'requestId': '2d891705d2125b', + 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b41', + 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', + 'mediaType': 'video', + 'source': 'client', + 'cpm': 1.9723, + 'creativeId': '159080650', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 2000, + 'vastUrl': 'https://some.vast-url.com', + 'vastXml': 'AdnxsTitle', + 'adapterCode': 'mediasquare', + 'originalCpm': 1.9723, + 'originalCurrency': 'USD', + 'responseTimestamp': 1665505150740, + 'requestTimestamp': 1665505150594, + 'bidder': 'appnexusAst', + 'adUnitCode': 'msq_tag_200125_video', + 'timeToRespond': 146, + 'size': '640x480', + 'vastImpUrl': 'https://some.tracking-url.com' +}, +]; + +describe('oxxionRtdProvider', () => { + describe('Oxxion RTD sub module', () => { + it('should init, return true, and set the params', () => { + expect(oxxionSubmodule.init(moduleConfig)).to.equal(true); + }); + }); + + describe('Oxxion RTD sub module', () => { + let auctionEnd = request; + auctionEnd.bidsReceived = bids; + it('call everything', function() { + oxxionSubmodule.getBidRequestData(request, null, moduleConfig); + oxxionSubmodule.onAuctionEndEvent(auctionEnd, moduleConfig); + }); + it('check vastImpUrl', function() { + expect(auctionEnd.bidsReceived[0]).to.have.property('vastImpUrl'); + let expectVastImpUrl = 'https://' + moduleConfig.params.domain + '.oxxion.io/analytics/vast_imp?'; + expect(auctionEnd.bidsReceived[1].vastImpUrl).to.contain(expectVastImpUrl); + expect(auctionEnd.bidsReceived[1].vastImpUrl).to.contain(encodeURI('https://some.tracking-url.com')); + }); + it('check vastXml', function() { + expect(auctionEnd.bidsReceived[0]).to.have.property('vastXml'); + let vastWrapper = new DOMParser().parseFromString(auctionEnd.bidsReceived[0].vastXml, 'text/xml'); + let impressions = vastWrapper.querySelectorAll('VAST Ad Wrapper Impression'); + expect(impressions.length).to.equal(2); + expect(auctionEnd.bidsReceived[1]).to.have.property('vastXml'); + expect(auctionEnd.bidsReceived[1].adId).to.equal('4b2e1581c0ca1a'); + let vastInline = new DOMParser().parseFromString(auctionEnd.bidsReceived[1].vastXml, 'text/xml'); + let inline = vastInline.querySelectorAll('VAST Ad InLine'); + expect(inline).to.have.lengthOf(1); + let inlineImpressions = vastInline.querySelectorAll('VAST Ad InLine Impression'); + expect(inlineImpressions).to.have.lengthOf.above(0); + }); + it('check cpmIncrement', function() { + expect(auctionEnd.bidsReceived[1].vastImpUrl).to.contain(encodeURI('cpmIncrement=1')); + }); + }); +}); From 64aff9b1af9bb1b2761e1012f628299f16c0eb46 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Mon, 24 Oct 2022 08:55:04 -0700 Subject: [PATCH 056/367] Prebid core: return a promise from `requestBids` (#9106) --- src/prebid.js | 139 +++++++++++++++++--------------- test/spec/unit/pbjs_api_spec.js | 139 ++++++++++++++++++++++---------- 2 files changed, 168 insertions(+), 110 deletions(-) diff --git a/src/prebid.js b/src/prebid.js index 0378f8c27ed..7b1cfd258ec 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -622,7 +622,7 @@ $$PREBID_GLOBAL$$.removeAdUnit = function (adUnitCode) { * @alias module:pbjs.requestBids */ $$PREBID_GLOBAL$$.requestBids = (function() { - const delegate = hook('async', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels, auctionId, ortb2, metrics } = {}) { + const delegate = hook('sync', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels, auctionId, ortb2, metrics } = {}) { events.emit(REQUEST_BIDS); const cbTimeout = timeout || config.getConfig('bidderTimeout'); logInfo('Invoking $$PREBID_GLOBAL$$.requestBids', arguments); @@ -646,7 +646,7 @@ $$PREBID_GLOBAL$$.requestBids = (function() { }); })(); -export const startAuction = hook('async', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ortb2Fragments, metrics } = {}) { +export const startAuction = hook('sync', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ortb2Fragments, metrics } = {}) { const s2sBidders = getS2SBidderSet(config.getConfig('s2sConfig') || []); adUnits = useMetrics(metrics).measureTime('requestBids.validate', () => checkAdUnitSetup(adUnits)); @@ -658,77 +658,82 @@ export const startAuction = hook('async', function ({ bidsBackHandler, timeout: adUnitCodes = adUnits && adUnits.map(unit => unit.code); } - /* - * for a given adunit which supports a set of mediaTypes - * and a given bidder which supports a set of mediaTypes - * a bidder is eligible to participate on the adunit - * if it supports at least one of the mediaTypes on the adunit - */ - adUnits.forEach(adUnit => { - // get the adunit's mediaTypes, defaulting to banner if mediaTypes isn't present - const adUnitMediaTypes = Object.keys(adUnit.mediaTypes || { 'banner': 'banner' }); - - // get the bidder's mediaTypes - const allBidders = adUnit.bids.map(bid => bid.bidder); - const bidderRegistry = adapterManager.bidderRegistry; - - const bidders = allBidders.filter(bidder => !s2sBidders.has(bidder)); - - const tid = adUnit.ortb2Imp?.ext?.tid || generateUUID(); - adUnit.transactionId = tid; - // Populate ortb2Imp.ext.tid with transactionId. Specifying a transaction ID per item in the ortb impression array, lets multiple transaction IDs be transmitted in a single bid request. - deepSetValue(adUnit, 'ortb2Imp.ext.tid', tid); - - bidders.forEach(bidder => { - const adapter = bidderRegistry[bidder]; - const spec = adapter && adapter.getSpec && adapter.getSpec(); - // banner is default if not specified in spec - const bidderMediaTypes = (spec && spec.supportedMediaTypes) || ['banner']; - - // check if the bidder's mediaTypes are not in the adUnit's mediaTypes - const bidderEligible = adUnitMediaTypes.some(type => includes(bidderMediaTypes, type)); - if (!bidderEligible) { - // drop the bidder from the ad unit if it's not compatible - logWarn(unsupportedBidderMessage(adUnit, bidder)); - adUnit.bids = adUnit.bids.filter(bid => bid.bidder !== bidder); - } else { - adunitCounter.incrementBidderRequestsCounter(adUnit.code, bidder); + return new Promise((resolve) => { + function auctionDone(bids, timedOut, auctionId) { + if (typeof bidsBackHandler === 'function') { + try { + bidsBackHandler(bids, timedOut, auctionId); + } catch (e) { + logError('Error executing bidsBackHandler', null, e); + } } + resolve({bids, timedOut, auctionId}); + } + + /* + * for a given adunit which supports a set of mediaTypes + * and a given bidder which supports a set of mediaTypes + * a bidder is eligible to participate on the adunit + * if it supports at least one of the mediaTypes on the adunit + */ + adUnits.forEach(adUnit => { + // get the adunit's mediaTypes, defaulting to banner if mediaTypes isn't present + const adUnitMediaTypes = Object.keys(adUnit.mediaTypes || { 'banner': 'banner' }); + + // get the bidder's mediaTypes + const allBidders = adUnit.bids.map(bid => bid.bidder); + const bidderRegistry = adapterManager.bidderRegistry; + + const bidders = allBidders.filter(bidder => !s2sBidders.has(bidder)); + + const tid = adUnit.ortb2Imp?.ext?.tid || generateUUID(); + adUnit.transactionId = tid; + // Populate ortb2Imp.ext.tid with transactionId. Specifying a transaction ID per item in the ortb impression array, lets multiple transaction IDs be transmitted in a single bid request. + deepSetValue(adUnit, 'ortb2Imp.ext.tid', tid); + + bidders.forEach(bidder => { + const adapter = bidderRegistry[bidder]; + const spec = adapter && adapter.getSpec && adapter.getSpec(); + // banner is default if not specified in spec + const bidderMediaTypes = (spec && spec.supportedMediaTypes) || ['banner']; + + // check if the bidder's mediaTypes are not in the adUnit's mediaTypes + const bidderEligible = adUnitMediaTypes.some(type => includes(bidderMediaTypes, type)); + if (!bidderEligible) { + // drop the bidder from the ad unit if it's not compatible + logWarn(unsupportedBidderMessage(adUnit, bidder)); + adUnit.bids = adUnit.bids.filter(bid => bid.bidder !== bidder); + } else { + adunitCounter.incrementBidderRequestsCounter(adUnit.code, bidder); + } + }); + adunitCounter.incrementRequestsCounter(adUnit.code); }); - adunitCounter.incrementRequestsCounter(adUnit.code); - }); - if (!adUnits || adUnits.length === 0) { - logMessage('No adUnits configured. No bids requested.'); - if (typeof bidsBackHandler === 'function') { - // executeCallback, this will only be called in case of first request - try { - bidsBackHandler(); - } catch (e) { - logError('Error executing bidsBackHandler', null, e); + if (!adUnits || adUnits.length === 0) { + logMessage('No adUnits configured. No bids requested.'); + auctionDone(); + } else { + const auction = auctionManager.createAuction({ + adUnits, + adUnitCodes, + callback: auctionDone, + cbTimeout, + labels, + auctionId, + ortb2Fragments, + metrics, + }); + + let adUnitsLen = adUnits.length; + if (adUnitsLen > 15) { + logInfo(`Current auction ${auction.getAuctionId()} contains ${adUnitsLen} adUnits.`, adUnits); } - } - return; - } - const auction = auctionManager.createAuction({ - adUnits, - adUnitCodes, - callback: bidsBackHandler, - cbTimeout, - labels, - auctionId, - ortb2Fragments, - metrics, + adUnitCodes.forEach(code => targeting.setLatestAuctionForAdUnit(code, auction.getAuctionId())); + auction.callBids(); + } }); - - let adUnitsLen = adUnits.length; - if (adUnitsLen > 15) { - logInfo(`Current auction ${auction.getAuctionId()} contains ${adUnitsLen} adUnits.`, adUnits); - } - - adUnitCodes.forEach(code => targeting.setLatestAuctionForAdUnit(code, auction.getAuctionId())); - auction.callBids(); }, 'startAuction'); export function executeCallbacks(fn, reqBidsConfigObj) { diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 4c1f5c3b455..e83608325d8 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -21,7 +21,8 @@ import {hook} from '../../../src/hook.js'; import {reset as resetDebugging} from '../../../src/debugging.js'; import $$PREBID_GLOBAL$$ from 'src/prebid.js'; import {resetAuctionState} from 'src/auction.js'; - +import {stubAuctionIndex} from '../../helpers/indexStub.js'; +import {createBid} from '../../../src/bidfactory.js'; var assert = require('chai').assert; var expect = require('chai').expect; @@ -1467,7 +1468,6 @@ describe('Unit: Prebid Module', function () { after(function () { clock.restore(); }); - let bidsBackHandlerStub = sinon.stub(); const BIDDER_CODE = 'sampleBidder'; let bids = [{ @@ -1504,11 +1504,12 @@ describe('Unit: Prebid Module', function () { 'start': 1000 }]; + let spec, indexStub, auction, completeAuction; + beforeEach(function () { logMessageSpy = sinon.spy(utils, 'logMessage'); makeRequestsStub = sinon.stub(adapterManager, 'makeBidRequests'); makeRequestsStub.returns(bidRequests); - adUnits = [{ code: 'adUnit-code', mediaTypes: { @@ -1516,45 +1517,53 @@ describe('Unit: Prebid Module', function () { sizes: [[300, 250]] } }, + transactionId: 'mock-tid', bids: [ {bidder: BIDDER_CODE, params: {placementId: 'id'}}, ] }]; - let adUnitCodes = ['adUnit-code']; - let auction = auctionModule.newAuction({ - adUnits, - adUnitCodes, - callback: bidsBackHandlerStub, - cbTimeout: 2000 - }); - let createAuctionStub = sinon.stub(auctionModule, 'newAuction'); - createAuctionStub.returns(auction); - }); - - afterEach(function () { - clock.restore(); - adapterManager.makeBidRequests.restore(); - auctionModule.newAuction.restore(); - utils.logMessage.restore(); - }); - - it('should execute callback after timeout', function () { - let spec = { + indexStub = sinon.stub(auctionManager, 'index'); + indexStub.get(() => stubAuctionIndex({adUnits, bidRequests})) + sinon.stub(adapterManager, 'callBids').callsFake((_, bidrequests, addBidResponse, adapterDone) => { + completeAuction = (bidsReceived) => { + bidsReceived.forEach((bid) => addBidResponse(bid.adUnitCode, Object.assign(createBid(), bid))); + bidRequests.forEach((req) => adapterDone.call(req)); + } + }) + const origNewAuction = auctionModule.newAuction; + sinon.stub(auctionModule, 'newAuction').callsFake(function (opts) { + auction = origNewAuction(opts); + return auction; + }) + spec = { code: BIDDER_CODE, isBidRequestValid: sinon.stub(), buildRequests: sinon.stub(), interpretResponse: sinon.stub(), getUserSyncs: sinon.stub(), - onTimeout: sinon.stub() + onTimeout: sinon.stub(), + onSetTargeting: sinon.stub(), }; registerBidder(spec); spec.buildRequests.returns([{'id': 123, 'method': 'POST'}]); spec.isBidRequestValid.returns(true); spec.interpretResponse.returns(bids); + }); + + afterEach(function () { + clock.restore(); + adapterManager.makeBidRequests.restore(); + adapterManager.callBids.restore(); + indexStub.restore(); + auction.getBidsReceived = () => []; + auctionModule.newAuction.restore(); + utils.logMessage.restore(); + }); + it('should execute callback after timeout', function () { let requestObj = { - bidsBackHandler: null, // does not need to be defined because of newAuction mock in beforeEach + bidsBackHandler: sinon.stub(), timeout: 2000, adUnits: adUnits }; @@ -1567,26 +1576,13 @@ describe('Unit: Prebid Module', function () { clock.tick(1); assert.ok(logMessageSpy.calledWith(sinon.match(re)), 'executeCallback called'); - expect(bidsBackHandlerStub.getCall(0).args[1]).to.equal(true, + expect(requestObj.bidsBackHandler.getCall(0).args[1]).to.equal(true, 'bidsBackHandler should be called with timedOut=true'); sinon.assert.called(spec.onTimeout); }); - it('should execute callback after setTargeting', function () { - let spec = { - code: BIDDER_CODE, - isBidRequestValid: sinon.stub(), - buildRequests: sinon.stub(), - interpretResponse: sinon.stub(), - onSetTargeting: sinon.stub() - }; - - registerBidder(spec); - spec.buildRequests.returns([{'id': 123, 'method': 'POST'}]); - spec.isBidRequestValid.returns(true); - spec.interpretResponse.returns(bids); - + it('should execute `onSetTargeting` after setTargetingForGPTAsync', function () { const bidId = 1; const auctionId = 1; let adResponse = Object.assign({ @@ -1595,6 +1591,7 @@ describe('Unit: Prebid Module', function () { width: 300, height: 250, adUnitCode: bidRequests[0].bids[0].adUnitCode, + transactionId: 'mock-tid', adserverTargeting: { 'hb_bidder': BIDDER_CODE, 'hb_adid': bidId, @@ -1603,20 +1600,76 @@ describe('Unit: Prebid Module', function () { }, bidder: bids[0].bidderCode, }, bids[0]); - auction.getBidsReceived = function() { return [adResponse]; } - auction.getAuctionId = () => auctionId; let requestObj = { - bidsBackHandler: null, // does not need to be defined because of newAuction mock in beforeEach + bidsBackHandler: null, timeout: 2000, adUnits: adUnits }; $$PREBID_GLOBAL$$.requestBids(requestObj); + completeAuction([adResponse]); $$PREBID_GLOBAL$$.setTargetingForGPTAsync(); sinon.assert.called(spec.onSetTargeting); }); + + describe('returns a promise that resolves', () => { + Object.entries({ + 'immediately, without bidsBackHandler': (req) => $$PREBID_GLOBAL$$.requestBids(req), + 'after bidsBackHandler': (() => { + const bidsBackHandler = sinon.stub(); + return function (req) { + return $$PREBID_GLOBAL$$.requestBids({...req, bidsBackHandler}).then(({bids, timedOut, auctionId}) => { + sinon.assert.calledWith(bidsBackHandler, bids, timedOut, auctionId); + return {bids, timedOut, auctionId}; + }) + } + })(), + 'after a bidsBackHandler that throws': (req) => $$PREBID_GLOBAL$$.requestBids({...req, bidsBackHandler: () => { throw new Error() }}) + }).forEach(([t, requestBids]) => { + describe(t, () => { + it('with no args, when no adUnits are defined', () => { + return requestBids({}).then((res) => { + expect(res).to.eql({ + bids: undefined, + timedOut: undefined, + auctionId: undefined + }); + }); + }); + + it('on timeout', (done) => { + requestBids({ + auctionId: 'mock-auctionId', + adUnits, + timeout: 10 + }).then(({timedOut, bids, auctionId}) => { + expect(timedOut).to.be.true; + expect(bids).to.eql({}); + expect(auctionId).to.eql('mock-auctionId'); + done(); + }); + clock.tick(12); + }); + + it('with auction result', (done) => { + const bid = { + bidder: 'mock-bidder', + adUnitCode: adUnits[0].code, + transactionId: adUnits[0].transactionId + } + requestBids({ + adUnits, + }).then(({bids}) => { + sinon.assert.match(bids[bid.adUnitCode].bids[0], bid) + done(); + }); + completeAuction([bid]); + }) + }) + }) + }) }) describe('requestBids', function () { From 8a1935e0e3d096bec47f92b82393289ebdd0dd99 Mon Sep 17 00:00:00 2001 From: TAKENORI MATSUMOTO Date: Tue, 25 Oct 2022 21:47:14 +0900 Subject: [PATCH 057/367] Fix typo "noDecodeWholeUrl" to "noDecodeWholeURL" at the priceFloors module (#9150) Co-authored-by: Takenori Matsumoto --- modules/priceFloors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/priceFloors.js b/modules/priceFloors.js index d7ab811d673..8b5976149d0 100644 --- a/modules/priceFloors.js +++ b/modules/priceFloors.js @@ -82,7 +82,7 @@ const getHostname = (() => { let domain; return function() { if (domain == null) { - domain = parseUrl(getRefererInfo().topmostLocation, {noDecodeWholeUrl: true}).hostname; + domain = parseUrl(getRefererInfo().topmostLocation, {noDecodeWholeURL: true}).hostname; } return domain; } From 4329b2a0d5a6fdc0cfbfcc11d845b16988e14ae7 Mon Sep 17 00:00:00 2001 From: Jeremy Sadwith Date: Wed, 26 Oct 2022 05:23:31 -0400 Subject: [PATCH 058/367] pageURL pull from topmostLocation (#9152) --- modules/kargoBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index f4563081aa7..c0faf2490cb 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -225,7 +225,7 @@ export const spec = { _getAllMetadata(bidderRequest, tdid) { return { userIDs: spec._getUserIds(tdid, bidderRequest.uspConsent, bidderRequest.gdprConsent), - pageURL: bidderRequest.refererInfo && bidderRequest.refererInfo.page, + pageURL: bidderRequest?.refererInfo?.topmostLocation || bidderRequest?.refererInfo?.page, rawCRB: storage.getCookie('krg_crb'), rawCRBLocalStorage: spec._getLocalStorageSafely('krg_crb') }; From 0642d6c95bfaf99732e549570e2b7278bdab22cc Mon Sep 17 00:00:00 2001 From: Antoin Date: Wed, 26 Oct 2022 06:55:54 -0400 Subject: [PATCH 059/367] Concert Bid Adapter: Add prebid unified ID 2.0 and slot coordinates (#9122) * collect EIDs for bid request * add ad slot positioning to payload Co-authored-by: Brett Bloxom <38990705+BrettBlox@users.noreply.github.com> --- modules/concertBidAdapter.js | 46 ++++++++++++++++- test/spec/modules/concertBidAdapter_spec.js | 56 +++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/modules/concertBidAdapter.js b/modules/concertBidAdapter.js index fc6fc23c26d..620e77a5a08 100644 --- a/modules/concertBidAdapter.js +++ b/modules/concertBidAdapter.js @@ -34,6 +34,9 @@ export const spec = { buildRequests: function(validBidRequests, bidderRequest) { logMessage(validBidRequests); logMessage(bidderRequest); + + const eids = []; + let payload = { meta: { prebidVersion: '$prebid.version$', @@ -49,6 +52,10 @@ export const spec = { }; payload.slots = validBidRequests.map(bidRequest => { + collectEid(eids, bidRequest); + const adUnitElement = document.getElementById(bidRequest.adUnitCode) + const coordinates = getOffset(adUnitElement) + let slot = { name: bidRequest.adUnitCode, bidId: bidRequest.bidId, @@ -59,12 +66,15 @@ export const spec = { adSlot: bidRequest.params.slot || bidRequest.adUnitCode, placementId: bidRequest.params.placementId || '', site: bidRequest.params.site || bidderRequest.refererInfo.page, - ref: bidderRequest.refererInfo.ref - }; + ref: bidderRequest.refererInfo.ref, + offsetCoordinates: { x: coordinates?.left, y: coordinates?.top } + } return slot; }); + payload.meta.eids = eids.filter(Boolean); + logMessage(payload); return { @@ -216,3 +226,35 @@ function consentAllowsPpid(bidderRequest) { return (uspConsent || gdprConsent); } + +function collectEid(eids, bid) { + if (bid.userId) { + const eid = getUserId(bid.userId.uid2 && bid.userId.uid2.id, 'uidapi.com', undefined, 3) + eids.push(eid) + } +} + +function getUserId(id, source, uidExt, atype) { + if (id) { + const uid = { id, atype }; + + if (uidExt) { + uid.ext = uidExt; + } + + return { + source, + uids: [ uid ] + }; + } +} + +function getOffset(el) { + if (el) { + const rect = el.getBoundingClientRect(); + return { + left: rect.left + window.scrollX, + top: rect.top + window.scrollY + }; + } +} diff --git a/test/spec/modules/concertBidAdapter_spec.js b/test/spec/modules/concertBidAdapter_spec.js index 2f9eda0ca7c..10ea997b304 100644 --- a/test/spec/modules/concertBidAdapter_spec.js +++ b/test/spec/modules/concertBidAdapter_spec.js @@ -7,11 +7,33 @@ describe('ConcertAdapter', function () { let bidRequests; let bidRequest; let bidResponse; + let element; + let sandbox; afterEach(function () { $$PREBID_GLOBAL$$.bidderSettings = {}; + sandbox.restore(); }); + 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 + }; + } + }; + $$PREBID_GLOBAL$$.bidderSettings = { concert: { storageAllowed: true @@ -56,6 +78,9 @@ describe('ConcertAdapter', function () { ] } } + + sandbox = sinon.sandbox.create(); + sandbox.stub(document, 'getElementById').withArgs('desktop_leaderboard_variable').returns(element) }); describe('spec.isBidRequestValid', function() { @@ -119,6 +144,37 @@ describe('ConcertAdapter', function () { expect(payload.meta.uid).to.equal('foo'); }); + + it('should add uid2 to eids list if available', function() { + bidRequests[0].userId = { uid2: { id: 'uid123' } } + + const request = spec.buildRequests(bidRequests, bidRequest); + const payload = JSON.parse(request.data); + const meta = payload.meta + + expect(meta.eids.length).to.equal(1); + expect(meta.eids[0].uids[0].id).to.equal('uid123') + expect(meta.eids[0].uids[0].atype).to.equal(3) + }) + + it('should return empty eids list if none are available', function() { + bidRequests[0].userId = { testId: { id: 'uid123' } } + const request = spec.buildRequests(bidRequests, bidRequest); + const payload = JSON.parse(request.data); + const meta = payload.meta + + expect(meta.eids.length).to.equal(0); + }); + + it('should return x/y offset coordiantes when element is present', function() { + Object.assign(element, { x: 100, y: 0, width: 400, height: 400 }) + const request = spec.buildRequests(bidRequests, bidRequest); + const payload = JSON.parse(request.data); + const slot = payload.slots[0]; + + expect(slot.offsetCoordinates.x).to.equal(100) + expect(slot.offsetCoordinates.y).to.equal(0) + }) }); describe('spec.interpretResponse', function() { From 4ff34061c97661b8865c2553eec3fdb4b95fdc7f Mon Sep 17 00:00:00 2001 From: github-tom-kuhnen <101572885+github-tom-kuhnen@users.noreply.github.com> Date: Wed, 26 Oct 2022 20:45:15 +0200 Subject: [PATCH 060/367] Teads: add the gvlid declaration (#9155) --- modules/teadsIdSystem.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/teadsIdSystem.js b/modules/teadsIdSystem.js index 20ca4dca460..c18f8fb76ac 100644 --- a/modules/teadsIdSystem.js +++ b/modules/teadsIdSystem.js @@ -37,6 +37,11 @@ export const teadsIdSubmodule = { * @type {string} */ name: MODULE_NAME, + /** + * Vendor id of Teads + * @type {number} + */ + gvlid: GVL_ID, /** * decode the stored id value for passing to bid requests * @function From ea7ee396e42a33f330636c4e1c3dc27a80784906 Mon Sep 17 00:00:00 2001 From: product-aax <103228925+product-aax@users.noreply.github.com> Date: Thu, 27 Oct 2022 00:41:35 +0530 Subject: [PATCH 061/367] AAX Blockmeter RTD Module : Initial Release (#9135) * AAX Blockmeter RTD Module Release * added url in rtd configuration params as params.url * Prebid 7.21.0 release * Increment version to 7.22.0-pre * Prebid core: do not enforce valid size in bid responses (#9138) * Prebid 7.22.0 release * Increment version to 7.23.0-pre * added url in rtd configuration params as params.url Co-authored-by: shubham.si Co-authored-by: Prebid.js automated release Co-authored-by: Demetrio Girardi --- modules/.submodules.json | 1 + modules/aaxBlockmeterRtdProvider.js | 59 +++++++++++++++++++++++++ modules/aaxBlockmeterRtdProvider.md | 48 ++++++++++++++++++++ src/adloader.js | 3 +- test/spec/modules/aaxBlockmeter_spec.js | 58 ++++++++++++++++++++++++ 5 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 modules/aaxBlockmeterRtdProvider.js create mode 100644 modules/aaxBlockmeterRtdProvider.md create mode 100644 test/spec/modules/aaxBlockmeter_spec.js diff --git a/modules/.submodules.json b/modules/.submodules.json index e4678a86b71..e4d09b8c9df 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -52,6 +52,7 @@ ], "rtdModule": [ "1plusXRtdProvider", + "aaxBlockmeterRtdProvider", "airgridRtdProvider", "akamaiDapRtdProvider", "blueconicRtdProvider", diff --git a/modules/aaxBlockmeterRtdProvider.js b/modules/aaxBlockmeterRtdProvider.js new file mode 100644 index 00000000000..a3b7b4812a7 --- /dev/null +++ b/modules/aaxBlockmeterRtdProvider.js @@ -0,0 +1,59 @@ +import {isEmptyStr, isStr, logError, isFn, logWarn} from '../src/utils.js'; +import {submodule} from '../src/hook.js'; +import { loadExternalScript } from '../src/adloader.js'; + +export const _config = { + MODULE: 'aaxBlockmeter', + ADSERVER_TARGETING_KEY: 'atk', + BLOCKMETER_URL: 'c.aaxads.com/aax.js', + VERSION: '1.2' +}; + +window.aax = window.aax || {}; + +function loadBlockmeter(_rtdConfig) { + if (!(_rtdConfig.params && _rtdConfig.params.pub) || !isStr(_rtdConfig.params && _rtdConfig.params.pub) || isEmptyStr(_rtdConfig.params && _rtdConfig.params.pub)) { + logError(`${_config.MODULE}: params.pub should be a string`); + return false; + } + + const params = []; + params.push(`pub=${_rtdConfig.params.pub}`); + params.push(`dn=${window.location.hostname}`); + + let url = _rtdConfig.params.url; + if (!url || isEmptyStr(url)) { + logWarn(`${_config.MODULE}: params.url is missing, using default url.`); + url = `${_config.BLOCKMETER_URL}?ver=${_config.VERSION}`; + } + + const scriptUrl = `https://${url}&${params.join('&')}`; + loadExternalScript(scriptUrl, _config.MODULE); + return true; +} + +function markAdBlockInventory(codes, _rtdConfig, _userConsent) { + return codes.reduce((targets, code) => { + targets[code] = targets[code] || {}; + const getAaxTargets = () => isFn(window.aax.getTargetingData) + ? window.aax.getTargetingData(code, _rtdConfig, _userConsent) + : {}; + targets[code] = { + [_config.ADSERVER_TARGETING_KEY]: code, + ...getAaxTargets() + }; + return targets; + }, {}); +} + +export const aaxBlockmeterRtdModule = { + name: _config.MODULE, + init: loadBlockmeter, + getTargetingData: markAdBlockInventory, +}; + +function registerSubModule() { + submodule('realTimeData', aaxBlockmeterRtdModule); +} + +registerSubModule(); diff --git a/modules/aaxBlockmeterRtdProvider.md b/modules/aaxBlockmeterRtdProvider.md new file mode 100644 index 00000000000..0a317f85b85 --- /dev/null +++ b/modules/aaxBlockmeterRtdProvider.md @@ -0,0 +1,48 @@ +## Overview + +Module Name: AAX Blockmeter Realtime Data Module +Module Type: Rtd Provider +Maintainer: product@aax.media + +## Description + +The module enables publishers to measure traffic coming from visitors using adblockers. + +AAX can also help publishers monetize this traffic by allowing them to serve [acceptable ads](https://acceptableads.com/about/) to these adblock visitors and recover their lost revenue. [Reach out to us](https://www.aax.media/try-blockmeter/) to know more. + +## Integration + +Build the AAX Blockmeter Realtime Data Module into the Prebid.js package with: + +``` +gulp build --modules=aaxBlockmeterRtdProvider,rtdModule +``` + +## Configuration + +This module is configured as part of the `realTimeData.dataProviders` object. + +| Name | Scope | Description | Example | Type | +|:----------:|:--------:|:-----------------------------|:---------------:|:------:| +| `name` | required | Real time data module name | `'aaxBlockmeter'` | `string` | +| `params` | required | | | `Object` | +| `params.pub` | required | AAX to share pub ID, [Reach out to us](https://www.aax.media/try-blockmeter/) to know more! | `'AAX00000'` | `string` | +| `params.url` | optional | AAX Blockmeter Script Url. Defaults to `'c.aaxads.com/aax.js?ver=1.2'` | `'c.aaxads.com/aax.js?ver=1.2'` | `string` | + +### Example + +```javascript +pbjs.setConfig({ + "realTimeData": { + "dataProviders": [ + { + "name": "aaxBlockmeter", + "params": { + "pub": "AAX00000", + "url": "c.aaxads.com/aax.js?ver=1.2", + } + } + ] + } +}) +``` diff --git a/src/adloader.js b/src/adloader.js index 6b7427d3e52..64408683e9f 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -19,7 +19,8 @@ const _approvedLoadExternalJSList = [ 'inskin', 'hadron', 'medianet', - 'improvedigital' + 'improvedigital', + 'aaxBlockmeter' ] /** diff --git a/test/spec/modules/aaxBlockmeter_spec.js b/test/spec/modules/aaxBlockmeter_spec.js new file mode 100644 index 00000000000..f9704361976 --- /dev/null +++ b/test/spec/modules/aaxBlockmeter_spec.js @@ -0,0 +1,58 @@ +import {aaxBlockmeterRtdModule} from '../../../modules/aaxBlockmeterRtdProvider.js'; +import * as sinon from 'sinon'; +import {assert} from 'chai'; + +let sandbox; +let getTargetingDataSpy; + +const config = { + dataProviders: [{ + 'name': 'aaxBlockmeter', + 'params': { + 'pub': 'publisher_id', + } + }] +}; + +describe('aaxBlockmeter realtime module', function () { + beforeEach(function () { + sandbox = sinon.sandbox.create(); + window.aax = window.aax || {}; + window.aax.getTargetingData = getTargetingDataSpy = sandbox.spy(); + }); + + afterEach(function () { + sandbox.restore(); + window.aax = {}; + }); + + it('init should return false when config is empty', function () { + assert.equal(aaxBlockmeterRtdModule.init({}), false); + }); + + it('init should return false when config.params id is empty', function () { + assert.equal(aaxBlockmeterRtdModule.init({params: {}}), false); + }); + + it('init should return true when config.params.pub is not string', function () { + assert.equal(aaxBlockmeterRtdModule.init({params: {pub: 12345}}), false); + }); + + it('init should return true when config.params.pub id is passed and is string typed', function () { + assert.equal(aaxBlockmeterRtdModule.init(config.dataProviders[0]), true); + }); + + describe('getTargetingData should work correctly', function () { + it('should return ad unit codes when ad units are present', function () { + const codes = ['code1', 'code2']; + assert.deepEqual(aaxBlockmeterRtdModule.getTargetingData(codes), { + code1: {'atk': 'code1'}, + code2: {'atk': 'code2'}, + }); + }); + + it('should call aax.getTargetingData if loaded', function () { + aaxBlockmeterRtdModule.getTargetingData([], config.dataProviders[0], null); + }); + }); +}); From 1d334e70cee194f9bfcf171044a16a1bbe9d9fc7 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 27 Oct 2022 11:51:17 -0700 Subject: [PATCH 062/367] Multiple modules: USP data deletion event handling (#9116) * Multiple modules: USP data deletion event handling * Add `onDataDeletionRequest` to RTD submodule spec Co-authored-by: Patrick McCann --- modules/consentManagementUsp.js | 25 +++-- modules/rtdModule/index.js | 23 +++- modules/userId/index.js | 59 +++++++++- src/adapterManager.js | 63 +++++++++-- .../spec/modules/consentManagementUsp_spec.js | 82 ++++++++++---- test/spec/modules/realTimeDataModule_spec.js | 65 +++++++++++ test/spec/modules/userId_spec.js | 68 +++++++++++- test/spec/unit/core/adapterManager_spec.js | 102 ++++++++++++++++++ 8 files changed, 449 insertions(+), 38 deletions(-) diff --git a/modules/consentManagementUsp.js b/modules/consentManagementUsp.js index 1e77dd4ef48..805c796312c 100644 --- a/modules/consentManagementUsp.js +++ b/modules/consentManagementUsp.js @@ -6,7 +6,7 @@ */ import {deepSetValue, isFn, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js'; import {config} from '../src/config.js'; -import {uspDataHandler} from '../src/adapterManager.js'; +import adapterManager, {uspDataHandler} from '../src/adapterManager.js'; import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; import {timedAuctionHook} from '../src/utils/perfMetrics.js'; import {getHook} from '../src/hook.js'; @@ -115,6 +115,11 @@ function lookupUspConsent({onSuccess, onError}) { USPAPI_VERSION, callbackHandler.consentDataCallback ); + uspapiFunction( + 'registerDeletion', + USPAPI_VERSION, + adapterManager.callDataDeletionRequest + ) } else { logInfo( 'Detected USP CMP is outside the current iframe where Prebid.js is located, calling it now...' @@ -124,12 +129,17 @@ function lookupUspConsent({onSuccess, onError}) { uspapiFrame, callbackHandler.consentDataCallback ); + callUspApiWhileInIframe( + 'registerDeletion', + uspapiFrame, + adapterManager.callDataDeletionRequest + ); } + let listening = false; + function callUspApiWhileInIframe(commandName, uspapiFrame, moduleCallback) { - /* Setup up a __uspapi function to do the postMessage and stash the callback. - This function behaves, from the caller's perspective, identicially to the in-frame __uspapi call (although it is not synchronous) */ - window.__uspapi = function (cmd, ver, callback) { + function callUsp(cmd, ver, callback) { let callId = Math.random() + ''; let msg = { __uspapiCall: { @@ -144,10 +154,13 @@ function lookupUspConsent({onSuccess, onError}) { }; /** when we get the return message, call the stashed callback */ - window.addEventListener('message', readPostMessageResponse, false); + if (!listening) { + window.addEventListener('message', readPostMessageResponse, false); + listening = true; + } // call uspapi - window.__uspapi(commandName, USPAPI_VERSION, moduleCallback); + callUsp(commandName, USPAPI_VERSION, moduleCallback); function readPostMessageResponse(event) { const res = event && event.data && event.data.__uspapiReturn; diff --git a/modules/rtdModule/index.js b/modules/rtdModule/index.js index e32d2169c5c..876da8dda37 100644 --- a/modules/rtdModule/index.js +++ b/modules/rtdModule/index.js @@ -108,6 +108,13 @@ * @param {UserConsentData} userConsent */ +/** + * @function? + * @summary on data deletion request + * @name RtdSubmodule#onDataDeletionRequest + * @param {SubmoduleConfig} config + */ + /** * @interface ModuleConfig */ @@ -156,7 +163,7 @@ import {getHook, module} from '../../src/hook.js'; import {logError, logInfo, logWarn} from '../../src/utils.js'; import * as events from '../../src/events.js'; import CONSTANTS from '../../src/constants.json'; -import {gdprDataHandler, uspDataHandler} from '../../src/adapterManager.js'; +import adapterManager, {gdprDataHandler, uspDataHandler} from '../../src/adapterManager.js'; import {find} from '../../src/polyfill.js'; import {timedAuctionHook} from '../../src/utils/perfMetrics.js'; @@ -230,6 +237,7 @@ export function init(config) { _dataProviders = realTimeData.dataProviders; setEventsListeners(); getHook('startAuction').before(setBidRequestsData, 20); // RTD should run before FPD + adapterManager.callDataDeletionRequest.before(onDataDeletionRequest); initSubModules(); }); } @@ -386,5 +394,18 @@ export function deepMerge(arr) { }, {}); } +export function onDataDeletionRequest(next, ...args) { + subModules.forEach((sm) => { + if (typeof sm.onDataDeletionRequest === 'function') { + try { + sm.onDataDeletionRequest(sm.config); + } catch (e) { + logError(`Error executing ${sm.name}.onDataDeletionRequest`, e) + } + } + }); + next.apply(this, args); +} + module('realTimeData', attachRealTimeDataProvider); init(config); diff --git a/modules/userId/index.js b/modules/userId/index.js index 6df78b9e73c..8fdd4319dfc 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -129,7 +129,7 @@ import {find, includes} from '../../src/polyfill.js'; import {config} from '../../src/config.js'; import * as events from '../../src/events.js'; import {getGlobal} from '../../src/prebidGlobal.js'; -import {gdprDataHandler} from '../../src/adapterManager.js'; +import adapterManager, {gdprDataHandler} from '../../src/adapterManager.js'; import CONSTANTS from '../../src/constants.json'; import {hook, module, ready as hooksReady} from '../../src/hook.js'; import {buildEidPermissions, createEidsArray, USER_IDS_CONFIG} from './eids.js'; @@ -217,6 +217,14 @@ export function setSubmoduleRegistry(submodules) { submoduleRegistry = submodules; } +function cookieSetter(submodule) { + const domainOverride = (typeof submodule.submodule.domainOverride === 'function') ? submodule.submodule.domainOverride() : null; + const name = submodule.config.storage.name; + return function setCookie(suffix, value, expiration) { + coreStorage.setCookie(name + (suffix || ''), value, expiration, 'Lax', domainOverride); + } +} + /** * @param {SubmoduleContainer} submodule * @param {(Object|string)} value @@ -226,15 +234,15 @@ export function setStoredValue(submodule, value) { * @type {SubmoduleStorage} */ const storage = submodule.config.storage; - const domainOverride = (typeof submodule.submodule.domainOverride === 'function') ? submodule.submodule.domainOverride() : null; try { - const valueStr = isPlainObject(value) ? JSON.stringify(value) : value; const expiresStr = (new Date(Date.now() + (storage.expires * (60 * 60 * 24 * 1000)))).toUTCString(); + const valueStr = isPlainObject(value) ? JSON.stringify(value) : value; if (storage.type === COOKIE) { - coreStorage.setCookie(storage.name, valueStr, expiresStr, 'Lax', domainOverride); + const setCookie = cookieSetter(submodule); + setCookie(null, value, expiresStr); if (typeof storage.refreshInSeconds === 'number') { - coreStorage.setCookie(`${storage.name}_last`, new Date().toUTCString(), expiresStr, 'Lax', domainOverride); + setCookie('_last', new Date().toUTCString(), expiresStr); } } else if (storage.type === LOCAL_STORAGE) { coreStorage.setDataInLocalStorage(`${storage.name}_exp`, expiresStr); @@ -248,6 +256,31 @@ export function setStoredValue(submodule, value) { } } +export function deleteStoredValue(submodule) { + let deleter, suffixes; + switch (submodule.config?.storage?.type) { + case COOKIE: + const setCookie = cookieSetter(submodule); + const expiry = (new Date(Date.now() - 1000 * 60 * 60 * 24)).toUTCString(); + deleter = (suffix) => setCookie(suffix, '', expiry) + suffixes = ['', '_last']; + break; + case LOCAL_STORAGE: + deleter = (suffix) => coreStorage.removeDataFromLocalStorage(submodule.config.storage.name + suffix) + suffixes = ['', '_last', '_exp']; + break; + } + if (deleter) { + suffixes.forEach(suffix => { + try { + deleter(suffix) + } catch (e) { + logError(e); + } + }); + } +} + function setPrebidServerEidPermissions(initializedSubmodules) { let setEidPermissions = getPrebidInternal().setEidPermissions; if (typeof setEidPermissions === 'function' && isArray(initializedSubmodules)) { @@ -1010,12 +1043,28 @@ function updateSubmodules() { if (!addedUserIdHook && submodules.length) { // priority value 40 will load after consentManagement with a priority of 50 getGlobal().requestBids.before(requestBidsHook, 40); + adapterManager.callDataDeletionRequest.before(requestDataDeletion); coreGetPPID.after((next) => next(getPPID())); logInfo(`${MODULE_NAME} - usersync config updated for ${submodules.length} submodules: `, submodules.map(a => a.submodule.name)); addedUserIdHook = true; } } +export function requestDataDeletion(next, ...args) { + logInfo('UserID: received data deletion request; deleting all stored IDs...') + submodules.forEach(submodule => { + if (typeof submodule.submodule.onDataDeletionRequest === 'function') { + try { + submodule.submodule.onDataDeletionRequest(submodule.config, submodule.idObj, ...args); + } catch (e) { + logError(`Error calling onDataDeletionRequest for ID submodule ${submodule.submodule.name}`, e); + } + } + deleteStoredValue(submodule); + }) + next.apply(this, args); +} + /** * enable submodule in User ID * @param {Submodule} submodule diff --git a/src/adapterManager.js b/src/adapterManager.js index 4722013d5f0..eb6a74a82a4 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -35,6 +35,7 @@ import {GdprConsentHandler, UspConsentHandler} from './consentHandler.js'; import * as events from './events.js'; import CONSTANTS from './constants.json'; import {useMetrics} from './utils/perfMetrics.js'; +import {auctionManager} from './auctionManager.js'; export const PARTITIONS = { CLIENT: 'client', @@ -553,19 +554,30 @@ adapterManager.getAnalyticsAdapter = function(code) { return _analyticsRegistry[code]; } -function tryCallBidderMethod(bidder, method, param) { +function getBidderMethod(bidder, method) { + const adapter = _bidderRegistry[bidder]; + const spec = adapter?.getSpec && adapter.getSpec(); + if (spec && spec[method] && typeof spec[method] === 'function') { + return [spec, spec[method]] + } +} + +function invokeBidderMethod(bidder, method, spec, fn, ...params) { try { - const adapter = _bidderRegistry[bidder]; - const spec = adapter.getSpec(); - if (spec && spec[method] && typeof spec[method] === 'function') { - logInfo(`Invoking ${bidder}.${method}`); - config.runWithBidder(bidder, bind.call(spec[method], spec, param)); - } + logInfo(`Invoking ${bidder}.${method}`); + config.runWithBidder(bidder, fn.bind(spec, ...params)); } catch (e) { logWarn(`Error calling ${method} of ${bidder}`); } } +function tryCallBidderMethod(bidder, method, param) { + const target = getBidderMethod(bidder, method); + if (target != null) { + invokeBidderMethod(bidder, method, ...target, param); + } +} + adapterManager.callTimedOutBidders = function(adUnits, timedOutBidders, cbTimeout) { timedOutBidders = timedOutBidders.map((timedOutBidder) => { // Adding user configured params & timeout to timeout event data @@ -600,4 +612,41 @@ adapterManager.callBidderError = function(bidder, error, bidderRequest) { tryCallBidderMethod(bidder, 'onBidderError', param); }; +function resolveAlias(alias) { + const seen = new Set(); + while (_aliasRegistry.hasOwnProperty(alias) && !seen.has(alias)) { + seen.add(alias); + alias = _aliasRegistry[alias]; + } + return alias; +} +/** + * Ask every adapter to delete PII. + * See https://github.com/prebid/Prebid.js/issues/9081 + */ +adapterManager.callDataDeletionRequest = hook('sync', function (...args) { + const method = 'onDataDeletionRequest'; + Object.keys(_bidderRegistry) + .filter((bidder) => !_aliasRegistry.hasOwnProperty(bidder)) + .forEach(bidder => { + const target = getBidderMethod(bidder, method); + if (target != null) { + const bidderRequests = auctionManager.getBidsRequested().filter((br) => + resolveAlias(br.bidderCode) === bidder + ); + invokeBidderMethod(bidder, method, ...target, bidderRequests, ...args); + } + }); + Object.entries(_analyticsRegistry).forEach(([name, entry]) => { + const fn = entry?.adapter?.[method]; + if (typeof fn === 'function') { + try { + fn.apply(entry.adapter, args); + } catch (e) { + logError(`error calling ${method} of ${name}`, e); + } + } + }); +}); + export default adapterManager; diff --git a/test/spec/modules/consentManagementUsp_spec.js b/test/spec/modules/consentManagementUsp_spec.js index 39aeee4470b..f9c3cd5890e 100644 --- a/test/spec/modules/consentManagementUsp_spec.js +++ b/test/spec/modules/consentManagementUsp_spec.js @@ -8,8 +8,9 @@ import { } from 'modules/consentManagementUsp.js'; import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; -import {uspDataHandler} from 'src/adapterManager.js'; +import adapterManager, {uspDataHandler} from 'src/adapterManager.js'; import 'src/prebid.js'; +import {defer} from '../../../src/utils/promise.js'; let expect = require('chai').expect; @@ -23,6 +24,16 @@ function createIFrameMarker() { } describe('consentManagement', function () { + let sandbox; + beforeEach(() => { + sandbox = sinon.sandbox.create(); + sandbox.stub(adapterManager, 'callDataDeletionRequest'); + }); + + afterEach(() => { + sandbox.restore(); + }); + it('should enable itself on requestBids using default values', (done) => { requestBidsHook(() => { expect(uspDataHandler.enabled).to.be.true; @@ -301,8 +312,11 @@ describe('consentManagement', function () { describe('USPAPI workflow for iframed page', function () { let ifr = null; let stringifyResponse = false; + let mockApi, replySent; beforeEach(function () { + mockApi = sinon.stub(); + replySent = defer(); sinon.stub(utils, 'logError'); sinon.stub(utils, 'logWarn'); ifr = createIFrameMarker(); @@ -322,17 +336,21 @@ describe('consentManagement', function () { function uspapiMessageHandler(event) { if (event && event.data) { - var data = event.data; + const data = event.data; if (data.__uspapiCall) { - var callId = data.__uspapiCall.callId; - var response = { - __uspapiReturn: { - callId, - returnValue: { uspString: '1YY' }, - success: true + const {command, version, callId} = data.__uspapiCall; + let response = mockApi(command, version, callId); + if (response) { + response = { + __uspapiReturn: { + callId, + returnValue: response, + success: true + } } - }; - event.source.postMessage(stringifyResponse ? JSON.stringify(response) : response, '*'); + event.source.postMessage(stringifyResponse ? JSON.stringify(response) : response, '*'); + replySent.resolve(); + } } } } @@ -345,6 +363,11 @@ describe('consentManagement', function () { function testIFramedPage(testName, messageFormatString) { it(`should return the consent string from a postmessage + addEventListener response - ${testName}`, (done) => { stringifyResponse = messageFormatString; + mockApi.callsFake((cmd) => { + if (cmd === 'getUSPData') { + return { uspString: '1YY' } + } + }) setConsentConfig(goodConfig); requestBidsHook(() => { let consent = uspDataHandler.getConsentData(); @@ -355,6 +378,20 @@ describe('consentManagement', function () { }, {}); }); } + + it('fires deletion request on registerDeletion', (done) => { + mockApi.callsFake((cmd) => { + return cmd === 'registerDeletion' + }) + sinon.assert.notCalled(adapterManager.callDataDeletionRequest); + setConsentConfig(goodConfig); + replySent.promise.then(() => { + setTimeout(() => { // defer again to give time for the message to get through + sinon.assert.calledOnce(adapterManager.callDataDeletionRequest); + done() + }, 200) + }) + }); }); describe('test without iframe locater', function() { @@ -400,23 +437,19 @@ describe('consentManagement', function () { }); describe('USPAPI workflow for normal pages:', function () { - let uspapiStub = sinon.stub(); let ifr = null; beforeEach(function () { didHookReturn = false; ifr = createIFrameMarker(); - sinon.stub(utils, 'logError'); - sinon.stub(utils, 'logWarn'); + sandbox.stub(utils, 'logError'); + sandbox.stub(utils, 'logWarn'); window.__uspapi = function() {}; }); afterEach(function () { config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); - uspapiStub.restore(); - utils.logError.restore(); - utils.logWarn.restore(); document.body.removeChild(ifr); delete window.__uspapi; resetConsentData(); @@ -427,7 +460,7 @@ describe('consentManagement', function () { uspString: '1NY' }; - uspapiStub = sinon.stub(window, '__uspapi').callsFake((...args) => { + sandbox.stub(window, '__uspapi').callsFake((...args) => { args[2](testConsentData, true); }); @@ -448,7 +481,7 @@ describe('consentManagement', function () { uspString: '1NY' }; - uspapiStub = sinon.stub(window, '__uspapi').callsFake((...args) => { + sandbox.stub(window, '__uspapi').callsFake((...args) => { args[2](testConsentData, true); }); @@ -463,6 +496,19 @@ describe('consentManagement', function () { expect(consentMeta.usp).to.equal(testConsentData.uspString); expect(consentMeta.generatedAt).to.be.above(1644367751709); }); + + it('registers deletion request event listener', () => { + let listener; + sandbox.stub(window, '__uspapi').callsFake((cmd, _, cb) => { + if (cmd === 'registerDeletion') { + listener = cb; + } + }); + setConsentConfig(goodConfig); + sinon.assert.notCalled(adapterManager.callDataDeletionRequest); + listener(); + sinon.assert.calledOnce(adapterManager.callDataDeletionRequest); + }) }); }); }); diff --git a/test/spec/modules/realTimeDataModule_spec.js b/test/spec/modules/realTimeDataModule_spec.js index daeeb9bc47c..ced2f697649 100644 --- a/test/spec/modules/realTimeDataModule_spec.js +++ b/test/spec/modules/realTimeDataModule_spec.js @@ -4,6 +4,7 @@ import * as sinon from 'sinon'; import {default as CONSTANTS} from '../../../src/constants.json'; import * as events from '../../../src/events.js'; import 'src/prebid.js'; +import {attachRealTimeDataProvider, onDataDeletionRequest} from 'modules/rtdModule/index.js'; const getBidRequestDataSpy = sinon.spy(); @@ -305,4 +306,68 @@ describe('Real time module', function () { }); }); }); + + describe('data deletion requests', () => { + let detach = () => null; + + function mkRtdModule(name) { + const mod = { + name, + init: () => true, + onDataDeletionRequest: sinon.stub() + }; + detach = ((orig) => { + const smDetach = attachRealTimeDataProvider(mod); + return function () { + orig(); + smDetach(); + } + })(detach); + return mod; + } + let sm1, sm2, cfg1, cfg2; + beforeEach(() => { + sm1 = mkRtdModule('mockMod1'); + sm2 = mkRtdModule('mockMod2'); + cfg1 = { + name: 'mockMod1', + i: 0 + }; + cfg2 = { + name: 'mockMod2', + i: 1 + }; + rtdModule.init(config); + config.setConfig({ + realTimeData: { + dataProviders: [cfg1, cfg2], + } + }); + }); + afterEach(() => { + detach(); + config.resetConfig(); + }); + + it('calls onDataDeletionRequest on submodules', () => { + const next = sinon.stub(); + onDataDeletionRequest(next, {a: 0}); + sinon.assert.calledWith(next, {a: 0}); + sinon.assert.calledWith(sm1.onDataDeletionRequest, cfg1); + sinon.assert.calledWith(sm2.onDataDeletionRequest, cfg2); + }); + + describe('does not choke if onDataDeletionRequest', () => { + Object.entries({ + 'is missing': () => { delete sm1.onDataDeletionRequest }, + 'throws': () => { sm1.onDataDeletionRequest.throws(new Error()) } + }).forEach(([t, setup]) => { + it(t, () => { + setup(); + onDataDeletionRequest(sinon.stub()); + sinon.assert.calledWith(sm2.onDataDeletionRequest, cfg2); + }) + }) + }) + }); }); diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index 4e9be5417e2..f4abcc4b9f6 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -9,7 +9,7 @@ import { setSubmoduleRegistry, syncDelay, PBJS_USER_ID_OPTOUT_NAME, - findRootDomain, + findRootDomain, requestDataDeletion, } from 'modules/userId/index.js'; import {createEidsArray} from 'modules/userId/eids.js'; import {config} from 'src/config.js'; @@ -2703,6 +2703,72 @@ describe('User ID', function () { }); }); + describe('requestDataDeletion', () => { + function idMod(name, value) { + return { + name, + getId() { + return {id: value} + }, + decode(d) { + return {[name]: d} + }, + onDataDeletionRequest: sinon.stub() + } + } + let mod1, mod2, mod3, cfg1, cfg2, cfg3; + + beforeEach(() => { + init(config); + mod1 = idMod('id1', 'val1'); + mod2 = idMod('id2', 'val2'); + mod3 = idMod('id3', 'val3'); + cfg1 = getStorageMock('id1', 'id1', 'cookie'); + cfg2 = getStorageMock('id2', 'id2', 'html5'); + cfg3 = {name: 'id3', value: {id3: 'val3'}}; + setSubmoduleRegistry([mod1, mod2, mod3]); + config.setConfig({ + auctionDelay: 1, + userSync: { + userIds: [cfg1, cfg2, cfg3] + } + }); + return getGlobal().refreshUserIds(); + }); + + it('deletes stored IDs', () => { + expect(coreStorage.getCookie('id1')).to.exist; + expect(coreStorage.getDataFromLocalStorage('id2')).to.exist; + requestDataDeletion(sinon.stub()); + expect(coreStorage.getCookie('id1')).to.not.exist; + expect(coreStorage.getDataFromLocalStorage('id2')).to.not.exist; + }); + + it('invokes onDataDeletionRequest', () => { + requestDataDeletion(sinon.stub()); + sinon.assert.calledWith(mod1.onDataDeletionRequest, cfg1, {id1: 'val1'}); + sinon.assert.calledWith(mod2.onDataDeletionRequest, cfg2, {id2: 'val2'}) + sinon.assert.calledWith(mod3.onDataDeletionRequest, cfg3, {id3: 'val3'}) + }); + + describe('does not choke when onDataDeletionRequest', () => { + Object.entries({ + 'is missing': () => { delete mod1.onDataDeletionRequest }, + 'throws': () => { mod1.onDataDeletionRequest.throws(new Error()) } + }).forEach(([t, setup]) => { + it(t, () => { + setup(); + const next = sinon.stub(); + const arg = {random: 'value'}; + requestDataDeletion(next, arg); + sinon.assert.calledOnce(mod2.onDataDeletionRequest); + sinon.assert.calledOnce(mod3.onDataDeletionRequest); + sinon.assert.calledWith(next, arg); + }) + }) + }) + }); + describe('findRootDomain', function () { let sandbox; diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js index 6e37da4e85f..3fea8988a95 100644 --- a/test/spec/unit/core/adapterManager_spec.js +++ b/test/spec/unit/core/adapterManager_spec.js @@ -20,6 +20,7 @@ import { setSizeConfig } from 'src/sizeMapping.js'; import {find, includes} from 'src/polyfill.js'; import s2sTesting from 'modules/s2sTesting.js'; import {hook} from '../../../../src/hook.js'; +import {auctionManager} from '../../../../src/auctionManager.js'; var events = require('../../../../src/events'); const CONFIG = { @@ -2543,4 +2544,105 @@ describe('adapterManager tests', function () { }) }); }); + + describe('callDataDeletionRequest', () => { + function delMethodForBidder(bidderCode) { + const del = sinon.stub(); + adapterManager.registerBidAdapter({ + callBids: sinon.stub(), + getSpec() { + return { + onDataDeletionRequest: del + } + } + }, bidderCode); + return del; + } + + function delMethodForAnalytics(provider) { + const del = sinon.stub(); + adapterManager.registerAnalyticsAdapter({ + code: provider, + adapter: { + enableAnalytics: sinon.stub(), + onDataDeletionRequest: del, + }, + }) + return del; + } + + Object.entries({ + 'bid adapters': delMethodForBidder, + 'analytics adapters': delMethodForAnalytics + }).forEach(([t, getDelMethod]) => { + describe(t, () => { + it('invokes onDataDeletionRequest', () => { + const del = getDelMethod('mockAdapter'); + adapterManager.callDataDeletionRequest(); + sinon.assert.calledOnce(del); + }); + + it('does not choke if onDeletionRequest throws', () => { + const del1 = getDelMethod('mockAdapter1'); + const del2 = getDelMethod('mockAdapter2'); + del1.throws(new Error()); + adapterManager.callDataDeletionRequest(); + sinon.assert.calledOnce(del1); + sinon.assert.calledOnce(del2); + }); + }) + }) + + describe('for bid adapters', () => { + let bidderRequests; + + beforeEach(() => { + bidderRequests = []; + sinon.stub(auctionManager, 'getBidsRequested').callsFake(() => bidderRequests); + }) + afterEach(() => { + auctionManager.getBidsRequested.restore(); + }) + + it('does not invoke onDataDeletionRequest on aliases', () => { + const del = delMethodForBidder('mockBidder'); + adapterManager.aliasBidAdapter('mockBidder', 'mockBidderAlias'); + adapterManager.aliasBidAdapter('mockBidderAlias2', 'mockBidderAlias'); + adapterManager.callDataDeletionRequest(); + sinon.assert.calledOnce(del); + }); + + it('passes known bidder requests', () => { + const del1 = delMethodForBidder('mockBidder1'); + const del2 = delMethodForBidder('mockBidder2'); + adapterManager.aliasBidAdapter('mockBidder1', 'mockBidder1Alias'); + adapterManager.aliasBidAdapter('mockBidder1Alias', 'mockBidder1Alias2') + bidderRequests = [ + { + bidderCode: 'mockBidder1', + id: 0 + }, + { + bidderCode: 'mockBidder2', + id: 1, + }, + { + bidderCode: 'mockBidder1Alias', + id: 2, + }, + { + bidderCode: 'someOtherBidder', + id: 3 + }, + { + bidderCode: 'mockBidder1Alias2', + id: 4 + } + ]; + adapterManager.callDataDeletionRequest(); + sinon.assert.calledWith(del1, [bidderRequests[0], bidderRequests[2], bidderRequests[4]]); + sinon.assert.calledWith(del2, [bidderRequests[1]]); + }) + }) + }); }); From fc67eb022a57985b6173e39556b82e43d185f79a Mon Sep 17 00:00:00 2001 From: Peiyuan <106841361+ix-peiyuan@users.noreply.github.com> Date: Thu, 27 Oct 2022 14:53:41 -0400 Subject: [PATCH 063/367] IX Bid Adapter: completely change request to POST method (#9156) --- modules/ixBidAdapter.js | 88 +--- test/spec/modules/ixBidAdapter_spec.js | 601 ++++++++++--------------- 2 files changed, 254 insertions(+), 435 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index fc387fac76a..4efed90d147 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -16,15 +16,15 @@ import { parseQueryStringParameters, safeJSONParse } from '../src/utils.js'; -import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; +import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; import CONSTANTS from '../src/constants.json'; -import {getStorageManager} from '../src/storageManager.js'; +import { getStorageManager } from '../src/storageManager.js'; import * as events from '../src/events.js'; -import {find} from '../src/polyfill.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {INSTREAM, OUTSTREAM} from '../src/video.js'; -import {Renderer} from '../src/Renderer.js'; +import { find } from '../src/polyfill.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { INSTREAM, OUTSTREAM } from '../src/video.js'; +import { Renderer } from '../src/Renderer.js'; const BIDDER_CODE = 'ix'; const ALIAS_BIDDER_CODE = 'roundel'; @@ -102,13 +102,13 @@ const VIDEO_PARAMS_ALLOW_LIST = [ const LOCAL_STORAGE_KEY = 'ixdiag'; export const LOCAL_STORAGE_FEATURE_TOGGLES_KEY = `${BIDDER_CODE}_features`; let hasRegisteredHandler = false; -export const storage = getStorageManager({gvlid: GLOBAL_VENDOR_ID, bidderCode: BIDDER_CODE}); +export const storage = getStorageManager({ gvlid: GLOBAL_VENDOR_ID, bidderCode: BIDDER_CODE }); export const FEATURE_TOGGLES = { featureToggles: {}, - isFeatureEnabled: function(ft) { + isFeatureEnabled: function (ft) { return deepAccess(this.featureToggles, `features.${ft}.activated`) }, - getFeatureToggles: function() { + getFeatureToggles: function () { if (storage.localStorageIsEnabled()) { const parsedToggles = safeJSONParse(storage.getDataFromLocalStorage(LOCAL_STORAGE_FEATURE_TOGGLES_KEY)); if (deepAccess(parsedToggles, 'expiry') && parsedToggles.expiry >= new Date().getTime()) { @@ -118,7 +118,7 @@ export const FEATURE_TOGGLES = { } } }, - setFeatureToggles: function(serverResponse) { + setFeatureToggles: function (serverResponse) { const responseBody = serverResponse.body; const expiryTime = new Date(); const toggles = deepAccess(responseBody, 'ext.features'); @@ -133,7 +133,7 @@ export const FEATURE_TOGGLES = { } } }, - clearFeatureToggles: function() { + clearFeatureToggles: function () { this.featureToggles = {}; if (storage.localStorageIsEnabled()) { storage.removeDataFromLocalStorage(LOCAL_STORAGE_FEATURE_TOGGLES_KEY); @@ -391,7 +391,7 @@ function parseBid(rawBid, currency, bidRequest) { bid.mediaTypes = bidRequest.mediaTypes; bid.ttl = isValidExpiry ? rawBid.exp : VIDEO_TIME_TO_LIVE; } else if (parsedAdm && parsedAdm.native) { - bid.native = {ortb: parsedAdm.native}; + bid.native = { ortb: parsedAdm.native }; bid.width = rawBid.w ? rawBid.w : 1; bid.height = rawBid.h ? rawBid.h : 1; bid.mediaType = NATIVE; @@ -708,18 +708,6 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { siteID = validBidRequests[0].params.siteId; payload.s = siteID; - if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_enable_post')) { - if (version) { - payload.v = version; - } - payload.ac = 'j'; - payload.sd = 1; - - if (version === VIDEO_ENDPOINT_VERSION) { - payload.nf = 1; - } - } - // Parse additional runtime configs. const bidderCode = (bidderRequest && bidderRequest.bidderCode) || 'ix'; const otherIxConfig = config.getConfig(bidderCode); @@ -762,13 +750,6 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { logError('IX Bid Adapter: IX config FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.IX_FPD_EXCEEDS_MAX_SIZE }); } } - - if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_enable_post')) { - // Create t in payload if timeout is configured. - if (typeof otherIxConfig.timeout === 'number') { - payload.t = otherIxConfig.timeout; - } - } } for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { @@ -909,36 +890,21 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { const isLastAdUnit = adUnitIndex === transactionIds.length - 1; if (wasAdUnitImpressionsTrimmed || isLastAdUnit) { - const clonedPayload = deepClone(payload); if (!isLastAdUnit || requestSequenceNumber) { r.ext.ixdiag.sn = requestSequenceNumber; - clonedPayload.sn = requestSequenceNumber; } requestSequenceNumber++; - clonedPayload.r = JSON.stringify(r); - - let requestData; - - if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_enable_post')) { - requestData = { - method: 'POST', - url: baseUrl + '?s=' + payload.s, - data: deepClone(r), - option: { - contentType: 'text/plain', - }, - validBidRequests - } - } else { - requestData = { - method: 'GET', - url: baseUrl, - data: clonedPayload, - validBidRequests - } - } - requests.push(requestData); + + requests.push({ + method: 'POST', + url: baseUrl + '?s=' + siteID, + data: deepClone(r), + option: { + contentType: 'text/plain', + }, + validBidRequests + }); currentRequestSize = baseRequestSize; r.imp = []; @@ -1532,13 +1498,7 @@ export const spec = { // Transform rawBid in bid response to the format that will be accepted by prebid. const innerBids = seatbid[i].bid; - let requestBid; - - if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_enable_post')) { - requestBid = bidderRequest.data; - } else { - requestBid = safeJSONParse(bidderRequest.data.r); - } + const requestBid = bidderRequest.data; for (let j = 0; j < innerBids.length; j++) { const bidRequest = getBidRequest(innerBids[j].impid, requestBid.imp, bidderRequest.validBidRequests); diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index a1b79358e8c..a2698fa2cdc 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -286,6 +286,44 @@ describe('IndexexchangeAdapter', function () { } ]; + const DEFAULT_VIDEO_VALID_BID_MEDIUM_SIZE = [ + { + bidder: 'ix', + params: { + siteId: '456', + video: { + skippable: false, + mimes: [ + 'video/mp4', + 'video/webm' + ], + minduration: 0, + maxduration: 60, + protocols: [2] + }, + size: [640, 480] + }, + sizes: [[640, 480], [200, 400]], + mediaTypes: { + video: { + context: 'instream', + playerSize: [[640, 480], [200, 400]] + } + }, + ortb2Imp: { + ext: { + tid: '173f49a8-7549-4218-a23c-e7ba59b47230' + } + }, + adUnitCode: 'div-gpt-ad-1460505748562-0', + transactionId: '173f49a8-7549-4218-a23c-e7ba59b47230', + bidId: '1a2b3c4e', + bidderRequestId: '11a22b33c44e', + auctionId: '1aa2bb3cc4de', + schain: SAMPLE_SCHAIN + } + ]; + const DEFAULT_MULTIFORMAT_BANNER_VALID_BID = [ { bidder: 'ix', @@ -400,7 +438,7 @@ describe('IndexexchangeAdapter', function () { } }, nativeOrtbRequest: { - assets: [{id: 0, required: 0, img: {type: 1}}, {id: 1, required: 1, title: {len: 140}}, {id: 2, required: 1, data: {type: 2}}, {id: 3, required: 1, img: {type: 3}}, {id: 4, required: false, video: {mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6]}}] + assets: [{ id: 0, required: 0, img: { type: 1 } }, { id: 1, required: 1, title: { len: 140 } }, { id: 2, required: 1, data: { type: 2 } }, { id: 3, required: 1, img: { type: 3 } }, { id: 4, required: false, video: { mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6] } }] }, adUnitCode: 'div-gpt-ad-1460505748563-0', transactionId: '173f49a8-7549-4218-a23c-e7ba59b47231', @@ -441,7 +479,7 @@ describe('IndexexchangeAdapter', function () { } }, nativeOrtbRequest: { - assets: [{id: 0, required: 0, img: {type: 1}}, {id: 1, required: 1, title: {len: 140}}, {id: 2, required: 1, data: {type: 2}}, {id: 3, required: 1, img: {type: 3}}, {id: 4, required: false, video: {mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6]}}] + assets: [{ id: 0, required: 0, img: { type: 1 } }, { id: 1, required: 1, title: { len: 140 } }, { id: 2, required: 1, data: { type: 2 } }, { id: 3, required: 1, img: { type: 3 } }, { id: 4, required: false, video: { mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6] } }] }, adUnitCode: 'div-gpt-ad-1460505748562-0', transactionId: '173f49a8-7549-4218-a23c-e7ba59b47230', @@ -633,31 +671,6 @@ describe('IndexexchangeAdapter', function () { } }; - const DEFAULT_BIDDER_REQUEST_DATA = { - ac: 'j', - r: JSON.stringify({ - id: '345', - imp: [ - { - id: '1a2b3c4e', - video: { - w: 640, - h: 480, - placement: 1 - } - } - ], - site: { - ref: 'https://ref.com/ref.html', - page: 'https://page.com' - }, - }), - s: '21', - sd: 1, - t: 1000, - v: 8.1 - }; - const DEFAULT_USERID_DATA = { idl_env: '1234-5678-9012-3456', // Liveramp netId: 'testnetid123', // NetId @@ -724,6 +737,8 @@ describe('IndexexchangeAdapter', function () { lotamePanoramaId: 'bd738d136bdaa841117fe9b331bb4' }; + const extractPayload = function (bidRequest) { return bidRequest.data } + describe('inherited functions', function () { it('should exists and is a function', function () { const adapter = newBidder(spec); @@ -778,7 +793,7 @@ describe('IndexexchangeAdapter', function () { syncsPerBidder: 3 } }); - let userSync = spec.getUserSyncs(syncOptions, [{'body': {'ext': {'publishersyncsperbidderoverride': 0}}}]); + let userSync = spec.getUserSyncs(syncOptions, [{ 'body': { 'ext': { 'publishersyncsperbidderoverride': 0 } } }]); expect(userSync.length).to.equal(0); }); @@ -792,7 +807,7 @@ describe('IndexexchangeAdapter', function () { syncsPerBidder: 3 } }); - let userSync = spec.getUserSyncs(syncOptions, [{'body': {'ext': {'publishersyncsperbidderoverride': 2}}}]); + let userSync = spec.getUserSyncs(syncOptions, [{ 'body': { 'ext': { 'publishersyncsperbidderoverride': 2 } } }]); expect(userSync[0].type).to.equal('image'); const USER_SYNC_URL_0 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=2&i=0&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy='; const USER_SYNC_URL_1 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=2&i=1&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy='; @@ -811,7 +826,7 @@ describe('IndexexchangeAdapter', function () { syncsPerBidder: 3 } }); - let userSync = spec.getUserSyncs(syncOptions, [{'body': {'ext': {'publishersyncsperbidderoverride': 4}}}]); + let userSync = spec.getUserSyncs(syncOptions, [{ 'body': { 'ext': { 'publishersyncsperbidderoverride': 4 } } }]); expect(userSync[0].type).to.equal('image'); const USER_SYNC_URL_0 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=3&i=0&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy='; const USER_SYNC_URL_1 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=3&i=1&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy='; @@ -832,7 +847,7 @@ describe('IndexexchangeAdapter', function () { syncsPerBidder: 0 } }); - let userSync = spec.getUserSyncs(syncOptions, [{'body': {'ext': {'publishersyncsperbidderoverride': 2}}}]); + let userSync = spec.getUserSyncs(syncOptions, [{ 'body': { 'ext': { 'publishersyncsperbidderoverride': 2 } } }]); expect(userSync[0].type).to.equal('image'); const USER_SYNC_URL_0 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=2&i=0&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy='; const USER_SYNC_URL_1 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=2&i=1&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy='; @@ -868,7 +883,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); bid.mediaTypes.video.renderer = { url: 'test', - render: () => {} + render: () => { } }; bid.mediaTypes.video.context = 'outstream'; bid.mediaTypes.video.playerSize = [[300, 249]]; @@ -1080,7 +1095,7 @@ describe('IndexexchangeAdapter', function () { bid.nativeOrtbRequest = {} expect(spec.isBidRequestValid(bid)).to.be.false; - bid.nativeOrtbRequest = {assets: []} + bid.nativeOrtbRequest = { assets: [] } expect(spec.isBidRequestValid(bid)).to.be.false; }); }); @@ -1104,7 +1119,7 @@ describe('IndexexchangeAdapter', function () { const cloneValidBid = utils.deepClone(validBid); cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA); const request = spec.buildRequests(cloneValidBid, ALIAS_OPTIONS); - const payload = JSON.parse(request[0].data.r); + const payload = extractPayload(request[0]); expect(request).to.be.an('array'); expect(request).to.have.lengthOf.above(0); // should be 1 or more expect(payload.user.eids).to.have.lengthOf(6); @@ -1115,7 +1130,7 @@ describe('IndexexchangeAdapter', function () { describe('buildRequestsIdentity', function () { let request; - let query; + let payload; let testCopy; beforeEach(function () { @@ -1124,7 +1139,7 @@ describe('IndexexchangeAdapter', function () { return testCopy; }; request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - query = request.data; + payload = extractPayload(request); }); afterEach(function () { @@ -1137,8 +1152,6 @@ describe('IndexexchangeAdapter', function () { }); it('payload should have correct format and value (single identity partner)', function () { - const payload = JSON.parse(query.r); - expect(payload.user).to.exist; expect(payload.user.eids).to.exist; expect(payload.user.eids).to.be.an('array'); @@ -1146,7 +1159,7 @@ describe('IndexexchangeAdapter', function () { }); it('identity data in impression should have correct format and value (single identity partner)', function () { - const impression = JSON.parse(query.r).user.eids; + const impression = payload.user.eids; expect(impression[0].source).to.equal(testCopy.IdentityIp.data.source); expect(impression[0].uids[0].id).to.equal(testCopy.IdentityIp.data.uids[0].id); }); @@ -1166,8 +1179,6 @@ describe('IndexexchangeAdapter', function () { }); it('payload should have correct format and value (single identity w/ multi ids)', function () { - const payload = JSON.parse(query.r); - expect(payload.user).to.exist; expect(payload.user.eids).to.exist; expect(payload.user.eids).to.be.an('array'); @@ -1175,7 +1186,7 @@ describe('IndexexchangeAdapter', function () { }); it('identity data in impression should have correct format and value (single identity w/ multi ids)', function () { - const impression = JSON.parse(query.r).user.eids; + const impression = payload.user.eids; expect(impression[0].source).to.equal(testCopy.IdentityIp.data.source); expect(impression[0].uids).to.have.lengthOf(3); @@ -1210,8 +1221,6 @@ describe('IndexexchangeAdapter', function () { }); it('payload should have correct format and value (multiple identity partners)', function () { - const payload = JSON.parse(query.r); - expect(payload.user).to.exist; expect(payload.user.eids).to.exist; expect(payload.user.eids).to.be.an('array'); @@ -1219,7 +1228,7 @@ describe('IndexexchangeAdapter', function () { }); it('identity data in impression should have correct format and value (multiple identity partners)', function () { - const impression = JSON.parse(query.r).user.eids; + const impression = payload.user.eids; expect(impression[0].source).to.equal(testCopy.IdentityIp.data.source); expect(impression[0].uids).to.have.lengthOf(1); @@ -1242,8 +1251,7 @@ describe('IndexexchangeAdapter', function () { return undefined; }; request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - query = request.data; - const payload = JSON.parse(query.r); + payload = extractPayload(request); expect(payload.user).to.exist; expect(payload.user.eids).to.not.exist; @@ -1255,8 +1263,7 @@ describe('IndexexchangeAdapter', function () { data: {} } request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - query = request.data; - const payload = JSON.parse(query.r); + payload = extractPayload(request); expect(payload.user).to.exist; expect(payload.user.eids).to.exist; @@ -1265,8 +1272,7 @@ describe('IndexexchangeAdapter', function () { it('payload should not have any user eids if identity data is pending for all partners', function () { testCopy.IdentityIp.responsePending = true; request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - query = request.data; - const payload = JSON.parse(query.r); + payload = extractPayload(request); expect(payload.user).to.exist; expect(payload.user.eids).to.not.exist; @@ -1276,8 +1282,7 @@ describe('IndexexchangeAdapter', function () { testCopy.IdentityIp.responsePending = false; testCopy.IdentityIp.data = {}; request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - query = request.data; - const payload = JSON.parse(query.r); + payload = extractPayload(request); expect(payload.user).to.exist; expect(payload.user.eids).to.not.exist; @@ -1304,7 +1309,7 @@ describe('IndexexchangeAdapter', function () { const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA); const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; - const payload = JSON.parse(request.data.r); + const payload = extractPayload(request); expect(payload.user.eids).to.have.lengthOf(6); expect(payload.user.eids).to.have.deep.members(DEFAULT_USERID_PAYLOAD); @@ -1401,7 +1406,7 @@ describe('IndexexchangeAdapter', function () { cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA); const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; - const payload = JSON.parse(request.data.r); + const payload = extractPayload(request); validUserIdPayload = utils.deepClone(DEFAULT_USERID_PAYLOAD); validUserIdPayload.push({ @@ -1480,7 +1485,7 @@ describe('IndexexchangeAdapter', function () { }] }); - const payload = JSON.parse(request.data.r); + const payload = extractPayload(request); expect(payload.user.eids).to.have.lengthOf(7); expect(payload.user.eids).to.have.deep.members(validUserIdPayload); }); @@ -1503,7 +1508,7 @@ describe('IndexexchangeAdapter', function () { bid.userId = DEFAULT_USERID_BID_DATA; const request = spec.buildRequests([bid], DEFAULT_OPTION)[0]; - const r = JSON.parse(request.data.r); + const r = extractPayload(request); expect(r.ext.ixdiag.userIds).to.be.an('array'); expect(r.ext.ixdiag.userIds.should.not.include('lotamePanoramaId')); @@ -1514,8 +1519,8 @@ describe('IndexexchangeAdapter', function () { describe('First party data', function () { it('should not set ixdiag.fpd value if not defined', function () { - const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {ortb2: {}})[0]; - const r = JSON.parse(request.data.r); + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2: {} })[0]; + const r = extractPayload(request); expect(r.ext.ixdiag.fpd).to.be.undefined; }); @@ -1531,8 +1536,8 @@ describe('IndexexchangeAdapter', function () { } }; - const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {ortb2})[0]; - const r = JSON.parse(request.data.r); + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2 })[0]; + const r = extractPayload(request); expect(r.ext.ixdiag.fpd).to.exist; }); @@ -1543,7 +1548,7 @@ describe('IndexexchangeAdapter', function () { }); const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID)[0]; - const r = JSON.parse(request.data.r); + const r = extractPayload(request); expect(r.ext.ixdiag.tmax).to.equal(250); }); @@ -1553,7 +1558,7 @@ describe('IndexexchangeAdapter', function () { bidderTimeout: null }) const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID)[0]; - const r = JSON.parse(request.data.r); + const r = extractPayload(request); expect(r.ext.ixdiag.tmax).to.be.undefined }); @@ -1571,8 +1576,8 @@ describe('IndexexchangeAdapter', function () { } }; - const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {ortb2})[0]; - const r = JSON.parse(request.data.r); + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2 })[0]; + const r = extractPayload(request); expect(r.site.keywords).to.exist; expect(r.site.search).to.exist; @@ -1595,8 +1600,8 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); bid.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; - const request = spec.buildRequests([bid], {ortb2})[0]; - const r = JSON.parse(request.data.r); + const request = spec.buildRequests([bid], { ortb2 })[0]; + const r = extractPayload(request); expect(r.site.ref).to.exist; expect(r.site.keywords).to.be.undefined; @@ -1608,33 +1613,25 @@ describe('IndexexchangeAdapter', function () { let request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; const requestUrl = request.url; const requestMethod = request.method; - const query = request.data; + const payloadData = 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 payloadWithoutSchain = extractPayload(requestWithoutSchain); const GPID = '/19968336/some-adunit-path'; - it('request should be made to IX endpoint with GET method', function () { - expect(requestMethod).to.equal('GET'); - expect(requestUrl).to.equal(IX_SECURE_ENDPOINT); + it('request should be made to IX endpoint with POST method and siteId in query param', function () { + expect(requestMethod).to.equal('POST'); + expect(requestUrl).to.equal(IX_SECURE_ENDPOINT + '?s=' + DEFAULT_BANNER_VALID_BID[0].params.siteId); + expect(request.option.contentType).to.equal('text/plain') }); it('auction type should be set correctly', function () { - const at = JSON.parse(query.r).at; + const at = payloadData.at; expect(at).to.equal(1); }) - it('query object (version, siteID and request) should be correct', function () { - expect(query.v).to.equal(BANNER_ENDPOINT_VERSION); - expect(query.s).to.equal(DEFAULT_BANNER_VALID_BID[0].params.siteId); - expect(query.r).to.exist; - expect(query.ac).to.equal('j'); - expect(query.sd).to.equal(1); - expect(query.nf).not.to.exist; - }); - it('should send dfp_adunit_code in request if ortb2Imp.ext.data.adserver.adslot exists', function () { const AD_UNIT_CODE = '/19968336/some-adunit-path'; const validBids = utils.deepClone(DEFAULT_BANNER_VALID_BID); @@ -1649,7 +1646,7 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const { ext: { dfp_ad_unit_code } } = JSON.parse(requests[0].data.r).imp[0]; + const { ext: { dfp_ad_unit_code } } = extractPayload(requests[0]).imp[0]; expect(dfp_ad_unit_code).to.equal(AD_UNIT_CODE); }); @@ -1661,7 +1658,7 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const { ext: { gpid } } = JSON.parse(requests[0].data.r).imp[0]; + const { ext: { gpid } } = extractPayload(requests[0]).imp[0]; expect(gpid).to.equal(GPID); }); @@ -1673,7 +1670,7 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const { ext: { gpid } } = JSON.parse(requests[0].data.r).imp[0]; + const { ext: { gpid } } = extractPayload(requests[0]).imp[0]; expect(gpid).to.equal(GPID); }); @@ -1686,7 +1683,7 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const imp = JSON.parse(requests[0].data.r).imp[0]; + const imp = extractPayload(requests[0]).imp[0]; expect(deepAccess(imp, 'ext.dfp_ad_unit_code')).to.not.exist; }); @@ -1704,7 +1701,7 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const imp = JSON.parse(requests[0].data.r).imp[0]; + const imp = extractPayload(requests[0]).imp[0]; expect(deepAccess(imp, 'ext.gpid')).to.not.exist; }); @@ -1724,13 +1721,13 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const imp = JSON.parse(requests[0].data.r).imp[0]; + const imp = extractPayload(requests[0]).imp[0]; expect(deepAccess(imp, 'ext.gpid')).to.equal(GPID); expect(deepAccess(imp, 'ext.dfp_ad_unit_code')).to.equal(AD_UNIT_CODE); }); it('payload should have correct format and value', function () { - const payload = JSON.parse(query.r); + const payload = payloadData; expect(payload.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidderRequestId); expect(payload.id).to.be.a('string'); expect(payload.site.page).to.equal(DEFAULT_OPTION.refererInfo.page); @@ -1748,7 +1745,7 @@ describe('IndexexchangeAdapter', function () { request = spec.buildRequests(bidWithIntId, DEFAULT_OPTION)[0]; - const payload = JSON.parse(request.data.r); + const payload = extractPayload(request); expect(bidWithIntId[0].bidderRequestId).to.be.a('number'); expect(payload.id).to.equal(bidWithIntId[0].bidderRequestId.toString()); expect(payload.id).to.be.a('string'); @@ -1760,19 +1757,21 @@ describe('IndexexchangeAdapter', function () { request = spec.buildRequests(bidWithIntId, DEFAULT_OPTION)[0]; - const payload = JSON.parse(request.data.r); + const payload = extractPayload(request); expect(bidWithIntId[0].bidderRequestId).to.be.a('number'); expect(payload.id).to.equal(bidWithIntId[0].bidderRequestId.toString()); expect(payload.id).to.be.a('string'); }); it('payload should not include schain when not provided', function () { - const payload = JSON.parse(queryWithoutSchain.r); - expect(payload.source.schain).to.not.exist; // source object currently only written for schain + const payload = payloadWithoutSchain; + + const actualSchain = (((payload || {}).source || {}).ext || {}).schain; + expect(actualSchain).to.not.exist; }); it('impression should have correct format and value', function () { - const impression = JSON.parse(query.r).imp[0]; + const impression = payloadData.imp[0]; const sidValue = DEFAULT_BANNER_VALID_BID[0].params.id; expect(impression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); @@ -1797,7 +1796,7 @@ describe('IndexexchangeAdapter', function () { request = spec.buildRequests([bid], DEFAULT_OPTION)[0]; - const payload = JSON.parse(request.data.r); + const payload = extractPayload(request); payload.imp[0].banner.format.forEach((imp) => { expect(imp.ext.siteID).to.be.a('string'); }); @@ -1813,7 +1812,7 @@ describe('IndexexchangeAdapter', function () { const expectedFloor = 3.25; bid.getFloor = () => ({ floor: expectedFloor, currency }); const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.bidfloor).to.equal(expectedFloor); expect(impression.bidfloorcur).to.equal(currency); @@ -1825,7 +1824,7 @@ describe('IndexexchangeAdapter', function () { const expectedFloor = 3.25; bid.getFloor = () => ({ floor: expectedFloor, currency }); const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.bidfloor).to.equal(expectedFloor); expect(impression.bidfloorcur).to.equal(currency); @@ -1837,7 +1836,7 @@ describe('IndexexchangeAdapter', function () { bid.params.bidFloor = highFloor; bid.params.bidFloorCur = 'USD' const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.bidfloor).to.equal(highFloor); expect(impression.bidfloorcur).to.equal(bid.params.bidFloorCur); @@ -1851,7 +1850,7 @@ describe('IndexexchangeAdapter', function () { const expectedFloor = highFloor; bid.getFloor = () => ({ floor: expectedFloor, currency }); const requestBidFloor = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.bidfloor).to.equal(highFloor); expect(impression.bidfloorcur).to.equal(bid.params.bidFloorCur); @@ -1863,7 +1862,7 @@ describe('IndexexchangeAdapter', function () { bid.params.bidFloor = 50; bid.params.bidFloorCur = 'USD'; const requestBidFloor = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.bidfloor).to.equal(bid.params.bidFloor); expect(impression.bidfloorcur).to.equal(bid.params.bidFloorCur); @@ -1875,7 +1874,7 @@ describe('IndexexchangeAdapter', function () { bid.params.bidFloor = 50; bid.params.bidFloorCur = 'USD'; const requestBidFloor = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.bidfloor).to.equal(bid.params.bidFloor); expect(impression.bidfloorcur).to.equal(bid.params.bidFloorCur); @@ -1900,7 +1899,7 @@ describe('IndexexchangeAdapter', function () { expect(bid.getFloor.getCall(1).args[0].size[0]).to.equal(500); expect(bid.getFloor.getCall(1).args[0].size[1]).to.equal(400); - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.bidfloor).to.equal(expectedFloor); expect(impression.bidfloorcur).to.equal(currency); }); @@ -1930,7 +1929,7 @@ describe('IndexexchangeAdapter', function () { expect(bid.getFloor.getCall(0).args[0].size[0]).to.equal(300); expect(bid.getFloor.getCall(0).args[0].size[1]).to.equal(250); - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.bidfloor).to.equal(expectedFloor); expect(impression.bidfloorcur).to.equal(currency); }); @@ -1940,7 +1939,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); bid.params.id = 50; const requestBidFloor = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); expect(impression.banner.format[0].w).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[0]); @@ -1954,7 +1953,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); bid.params.id = 'abc'; const requestBidFloor = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(requestBidFloor.data.r).imp[0]; + const impression = extractPayload(requestBidFloor).imp[0]; expect(impression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); expect(impression.banner.format[0].w).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[0]); @@ -1982,7 +1981,7 @@ describe('IndexexchangeAdapter', function () { }); const requestWithFirstPartyData = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - const pageUrl = JSON.parse(requestWithFirstPartyData.data.r).site.page; + const pageUrl = extractPayload(requestWithFirstPartyData).site.page; const expectedPageUrl = DEFAULT_OPTION.refererInfo.page + '?ab=123&cd=123%23ab&e%2Ff=456&h%3Fg=456%23cd'; expect(pageUrl).to.equal(expectedPageUrl); }); @@ -1995,7 +1994,7 @@ describe('IndexexchangeAdapter', function () { }); const requestFirstPartyDataNumber = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - const pageUrl = JSON.parse(requestFirstPartyDataNumber.data.r).site.page; + const pageUrl = extractPayload(requestFirstPartyDataNumber).site.page; expect(pageUrl).to.equal(DEFAULT_OPTION.refererInfo.page); }); @@ -2006,7 +2005,7 @@ describe('IndexexchangeAdapter', function () { }); const requestWithoutConfig = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - const pageUrl = JSON.parse(requestWithoutConfig.data.r).site.page; + const pageUrl = extractPayload(requestWithoutConfig).site.page; expect(pageUrl).to.equal(DEFAULT_OPTION.refererInfo.page); expect(requestWithoutConfig.data.t).to.be.undefined; @@ -2014,13 +2013,13 @@ describe('IndexexchangeAdapter', function () { it('should not set first party or timeout if it is setConfig is not called', function () { const requestWithoutConfig = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; - const pageUrl = JSON.parse(requestWithoutConfig.data.r).site.page; + const pageUrl = extractPayload(requestWithoutConfig).site.page; expect(pageUrl).to.equal(DEFAULT_OPTION.refererInfo.page); expect(requestWithoutConfig.data.t).to.be.undefined; }); - it('should set timeout if publisher set it through setConfig', function () { + it('should no longer set timeout even if publisher set it through setConfig', function () { config.setConfig({ ix: { timeout: 500 @@ -2028,10 +2027,10 @@ describe('IndexexchangeAdapter', function () { }); const requestWithTimeout = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {})[0]; - expect(requestWithTimeout.data.t).to.equal(500); + expect(requestWithTimeout.data.t).to.be.undefined; }); - it('should set timeout if timeout is a string', function () { + it('should no longer set timeout even if timeout is a string', function () { config.setConfig({ ix: { timeout: '500' @@ -2046,11 +2045,10 @@ describe('IndexexchangeAdapter', function () { describe('request should contain both banner and video requests', function () { const request = spec.buildRequests([DEFAULT_BANNER_VALID_BID[0], DEFAULT_VIDEO_VALID_BID[0]], {}); it('should have banner request', () => { - const bannerImpression = JSON.parse(request[0].data.r).imp[0]; + const bannerImpression = extractPayload(request[0]).imp[0]; const sidValue = DEFAULT_BANNER_VALID_BID[0].params.id; - expect(JSON.parse(request[0].data.r).imp).to.have.lengthOf(1); - expect(JSON.parse(request[0].data.v)).to.equal(BANNER_ENDPOINT_VERSION); + expect(extractPayload(request[0]).imp).to.have.lengthOf(1); expect(bannerImpression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); expect(bannerImpression.banner.format).to.be.length(2); @@ -2067,9 +2065,8 @@ describe('IndexexchangeAdapter', function () { }); it('should have video request', () => { - const videoImpression = JSON.parse(request[1].data.r).imp[0]; + const videoImpression = extractPayload(request[1]).imp[0]; - expect(JSON.parse(request[1].data.v)).to.equal(VIDEO_ENDPOINT_VERSION); expect(videoImpression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); expect(videoImpression.video.w).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.size[0]); expect(videoImpression.video.h).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.size[1]); @@ -2080,11 +2077,10 @@ describe('IndexexchangeAdapter', function () { const request = spec.buildRequests([DEFAULT_BANNER_VALID_BID[0], DEFAULT_NATIVE_VALID_BID[0]]); it('should have banner request', () => { - const bannerImpression = JSON.parse(request[0].data.r).imp[0]; + const bannerImpression = extractPayload(request[0]).imp[0]; const sidValue = DEFAULT_BANNER_VALID_BID[0].params.id; - expect(JSON.parse(request[0].data.r).imp).to.have.lengthOf(1); - expect(JSON.parse(request[0].data.v)).to.equal(BANNER_ENDPOINT_VERSION); + expect(extractPayload(request[0]).imp).to.have.lengthOf(1); expect(bannerImpression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); expect(bannerImpression.banner.format).to.be.length(2); @@ -2101,7 +2097,7 @@ describe('IndexexchangeAdapter', function () { }); it('should have native request', () => { - const nativeImpression = JSON.parse(request[1].data.r).imp[0]; + const nativeImpression = extractPayload(request[1]).imp[0]; expect(request[1].data.hasOwnProperty('v')).to.equal(false); expect(nativeImpression.id).to.equal(DEFAULT_NATIVE_VALID_BID[0].bidId); @@ -2133,8 +2129,6 @@ describe('IndexexchangeAdapter', function () { const requests = spec.buildRequests([bid, DEFAULT_BANNER_VALID_BID[0]], DEFAULT_OPTION); expect(requests).to.be.an('array'); expect(requests).to.have.lengthOf(2); - expect(requests[0].data.sn).to.be.equal(0); - expect(requests[1].data.sn).to.be.equal(1); }); it('6 ad units should generate only 4 requests', function () { @@ -2168,10 +2162,7 @@ describe('IndexexchangeAdapter', function () { for (var i = 0; i < requests.length; i++) { const reqSize = `${requests[i].url}?${utils.parseQueryStringParameters(requests[i].data)}`.length; expect(reqSize).to.be.lessThan(8000); - let payload = JSON.parse(requests[i].data.r); - if (requests.length > 1) { - expect(requests[i].data.sn).to.equal(i); - } + let payload = extractPayload(requests[i]); expect(payload.source.ext.schain).to.deep.equal(SAMPLE_SCHAIN); } }); @@ -2196,7 +2187,7 @@ describe('IndexexchangeAdapter', function () { expect(requests).to.be.an('array'); expect(requests).to.have.lengthOf(1); - const impressions = JSON.parse(requests[0].data.r).imp; + const impressions = extractPayload(requests[0]).imp; expect(impressions).to.be.an('array'); expect(impressions).to.have.lengthOf(3); expect(requests[0].data.sn).to.be.undefined; @@ -2212,7 +2203,7 @@ describe('IndexexchangeAdapter', function () { bid2.params.bidId = '2b3c4d5e'; const request = spec.buildRequests([bid, bid2], DEFAULT_OPTION)[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; const sidValue = bid.params.id; expect(impression.id).to.equal(bid.bidId); @@ -2242,7 +2233,7 @@ describe('IndexexchangeAdapter', function () { const bids = [DEFAULT_BANNER_VALID_BID[0], bid]; const request = spec.buildRequests(bids, DEFAULT_OPTION)[0]; - const impressions = JSON.parse(request.data.r).imp; + const impressions = extractPayload(request).imp; expect(impressions).to.be.an('array'); expect(impressions).to.have.lengthOf(2); expect(request.data.sn).to.be.undefined; @@ -2267,7 +2258,7 @@ describe('IndexexchangeAdapter', function () { 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; + const impressions = extractPayload(request[0]).imp; expect(impressions).to.be.an('array'); expect(impressions).to.have.lengthOf(1); @@ -2280,7 +2271,7 @@ describe('IndexexchangeAdapter', function () { const requests = spec.buildRequests([bid1, DEFAULT_BANNER_VALID_BID[0]], DEFAULT_OPTION); - const impressions = JSON.parse(requests[0].data.r).imp; + const impressions = extractPayload(requests[0]).imp; expect(impressions).to.be.an('array'); expect(impressions).to.have.lengthOf(1); @@ -2290,24 +2281,15 @@ describe('IndexexchangeAdapter', function () { describe('buildRequestVideo', function () { const request = spec.buildRequests(DEFAULT_VIDEO_VALID_BID, DEFAULT_OPTION); - const query = request[0].data; - - it('query object (version, siteID and request) should be correct', function () { - expect(query.v).to.equal(VIDEO_ENDPOINT_VERSION); - expect(query.s).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.siteId); - expect(query.r).to.exist; - expect(query.ac).to.equal('j'); - expect(query.sd).to.equal(1); - expect(query.nf).to.equal(1); - }); + const payloadData = request[0].data; it('auction type should be set correctly', function () { - const at = JSON.parse(query.r).at; + const at = payloadData.at; expect(at).to.equal(1); }) it('impression should have correct format and value', function () { - const impression = JSON.parse(query.r).imp[0]; + const impression = payloadData.imp[0]; expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); expect(impression.video.w).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.size[0]); @@ -2326,7 +2308,7 @@ describe('IndexexchangeAdapter', function () { bid.mediaTypes.video.context = 'outstream'; bid.mediaTypes.video.placement = 2; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); expect(impression.video.placement).to.equal(2); @@ -2336,7 +2318,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); bid.params.id = 50; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.ext.sid).to.equal('50'); }); @@ -2345,7 +2327,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); bid.mediaTypes.video.context = 'instream'; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); expect(impression.video.placement).to.equal(1); @@ -2355,7 +2337,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); bid.mediaTypes.video.context = 'outstream'; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId); expect(impression.video.placement).to.equal(4); @@ -2365,7 +2347,7 @@ describe('IndexexchangeAdapter', function () { const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]); bid.mediaTypes.video.context = 'not-valid'; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.video.placement).to.be.undefined; }); @@ -2375,7 +2357,7 @@ describe('IndexexchangeAdapter', function () { bid.mediaTypes.video.protocols = [1]; bid.mediaTypes.video.mimes = ['video/override']; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.video.protocols[0]).to.equal(2); expect(impression.video.mimes[0]).to.not.equal('video/override'); @@ -2386,7 +2368,7 @@ describe('IndexexchangeAdapter', function () { bid.mediaTypes.video.context = 'outstream'; bid.mediaTypes.video.random = true; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.video.random).to.not.exist; }); @@ -2401,7 +2383,7 @@ describe('IndexexchangeAdapter', function () { bid.mediaTypes.video.api = 2; bid.mediaTypes.video.pos = 0; const request = spec.buildRequests([bid], {})[0]; - const impression = JSON.parse(request.data.r).imp[0]; + const impression = extractPayload(request).imp[0]; expect(impression.video.protocols[0]).to.equal(6); expect(impression.video.api).to.equal(2); @@ -2418,15 +2400,14 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(validBids, DEFAULT_OPTION); - const { ext: { gpid } } = JSON.parse(requests[0].data.r).imp[0]; + const { ext: { gpid } } = extractPayload(requests[0]).imp[0]; expect(gpid).to.equal(GPID); }); it('should build video request when if video obj is not provided at params level', () => { const request = spec.buildRequests([DEFAULT_VIDEO_VALID_BID_NO_VIDEO_PARAMS[0]], {}); - const videoImpression = JSON.parse(request[0].data.r).imp[0]; + const videoImpression = extractPayload(request[0]).imp[0]; - expect(JSON.parse(request[0].data.v)).to.equal(VIDEO_ENDPOINT_VERSION); expect(videoImpression.id).to.equal(DEFAULT_VIDEO_VALID_BID_NO_VIDEO_PARAMS[0].bidId); expect(videoImpression.video.w).to.equal(DEFAULT_VIDEO_VALID_BID_NO_VIDEO_PARAMS[0].mediaTypes.video.playerSize[0][0]); expect(videoImpression.video.h).to.equal(DEFAULT_VIDEO_VALID_BID_NO_VIDEO_PARAMS[0].mediaTypes.video.playerSize[0][1]); @@ -2440,23 +2421,18 @@ describe('IndexexchangeAdapter', function () { }; const request = spec.buildRequests([bid]); - const videoImpression = JSON.parse(request[0].data.r).imp[0]; + const videoImpression = extractPayload(request[0]).imp[0]; expect(videoImpression.video.placement).to.eq(5); }) }); describe('buildRequestNative', function () { - it('should build request with expected params', function() { - const request = spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION); - const query = request[0].data; + it('should build request with expected params', function () { + const request = spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION)[0]; - expect(query.hasOwnProperty('v')).to.equal(false); - expect(query.s).to.equal(DEFAULT_NATIVE_VALID_BID[0].params.siteId); - expect(query.r).to.exist; - expect(query.ac).to.equal('j'); - expect(query.sd).to.equal(1); - expect(JSON.parse(query.r).at).to.equal(1); + expect(request.data).to.exist; + expect(request.method).to.equal('POST') }); it('should send gpid in request if ortb2Imp.ext.gpid exists', function () { @@ -2468,40 +2444,40 @@ describe('IndexexchangeAdapter', function () { } }; const requests = spec.buildRequests(bids, DEFAULT_OPTION); - const { ext: { gpid } } = JSON.parse(requests[0].data.r).imp[0]; + const { ext: { gpid } } = extractPayload(requests[0]).imp[0]; expect(gpid).to.equal(GPID); }); - it('should build request with required asset properties with default values', function() { + it('should build request with required asset properties with default values', function () { const request = spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION); - const nativeImpression = JSON.parse(request[0].data.r).imp[0]; + const nativeImpression = extractPayload(request[0]).imp[0]; expect(request[0].data.hasOwnProperty('v')).to.equal(false); expect(nativeImpression.id).to.equal(DEFAULT_NATIVE_VALID_BID[0].bidId); expect(nativeImpression.native).to.deep.equal(DEFAULT_NATIVE_IMP); }); - it('should set imp.ext.sid for native imps if params.id exist', function() { + it('should set imp.ext.sid for native imps if params.id exist', function () { const bid = utils.deepClone(DEFAULT_NATIVE_VALID_BID); bid[0].params.id = 'abc' const request = spec.buildRequests(bid, DEFAULT_OPTION); - const nativeImpression = JSON.parse(request[0].data.r).imp[0]; + const nativeImpression = extractPayload(request[0]).imp[0]; expect(nativeImpression.id).to.equal(DEFAULT_NATIVE_VALID_BID[0].bidId); expect(nativeImpression.ext.sid).to.equal('abc'); }); - it('should build request with given asset properties', function() { + it('should build request with given asset properties', function () { let bid = utils.deepClone(DEFAULT_NATIVE_VALID_BID) bid[0].nativeOrtbRequest = { - assets: [{id: 0, required: 0, title: {len: 140}}, {id: 1, required: 0, video: {mimes: ['javascript'], minduration: 10, maxduration: 60, protocols: [1]}}] + assets: [{ id: 0, required: 0, title: { len: 140 } }, { id: 1, required: 0, video: { mimes: ['javascript'], minduration: 10, maxduration: 60, protocols: [1] } }] } const request = spec.buildRequests(bid, DEFAULT_OPTION); - const nativeImpression = JSON.parse(request[0].data.r).imp[0]; - expect(nativeImpression.native).to.deep.equal({request: '{"assets":[{"id":0,"required":0,"title":{"len":140}},{"id":1,"required":0,"video":{"mimes":["javascript"],"minduration":10,"maxduration":60,"protocols":[1]}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2'}); + const nativeImpression = extractPayload(request[0]).imp[0]; + expect(nativeImpression.native).to.deep.equal({ request: '{"assets":[{"id":0,"required":0,"title":{"len":140}},{"id":1,"required":0,"video":{"mimes":["javascript"],"minduration":10,"maxduration":60,"protocols":[1]}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2' }); }); - it('should build request with all possible Prebid asset properties', function() { + it('should build request with all possible Prebid asset properties', function () { let bid = utils.deepClone(DEFAULT_NATIVE_VALID_BID) bid[0].nativeOrtbRequest = { 'ver': '1.2', @@ -2626,17 +2602,16 @@ describe('IndexexchangeAdapter', function () { ] } const request = spec.buildRequests(bid, DEFAULT_OPTION); - const nativeImpression = JSON.parse(request[0].data.r).imp[0]; - expect(nativeImpression.native).to.deep.equal({request: '{"ver":"1.2","assets":[{"id":0,"required":0,"title":{"len":140}},{"id":1,"required":0,"data":{"type":2}},{"id":2,"required":0,"data":{"type":10}},{"id":3,"required":0,"data":{"type":1}},{"id":4,"required":0,"img":{"type":1}},{"id":5,"required":0,"img":{"type":3}},{"id":6,"required":0},{"id":7,"required":0,"data":{"type":11}},{"id":8,"required":0},{"id":9,"required":0},{"id":10,"required":0,"data":{"type":12}},{"id":11,"required":0,"data":{"type":3}},{"id":12,"required":0,"data":{"type":5}},{"id":13,"required":0,"data":{"type":4}},{"id":14,"required":0,"data":{"type":6}},{"id":15,"required":0,"data":{"type":7}},{"id":16,"required":0,"data":{"type":9}},{"id":17,"required":0,"data":{"type":8}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2'}); + const nativeImpression = extractPayload(request[0]).imp[0]; + expect(nativeImpression.native).to.deep.equal({ request: '{"ver":"1.2","assets":[{"id":0,"required":0,"title":{"len":140}},{"id":1,"required":0,"data":{"type":2}},{"id":2,"required":0,"data":{"type":10}},{"id":3,"required":0,"data":{"type":1}},{"id":4,"required":0,"img":{"type":1}},{"id":5,"required":0,"img":{"type":3}},{"id":6,"required":0},{"id":7,"required":0,"data":{"type":11}},{"id":8,"required":0},{"id":9,"required":0},{"id":10,"required":0,"data":{"type":12}},{"id":11,"required":0,"data":{"type":3}},{"id":12,"required":0,"data":{"type":5}},{"id":13,"required":0,"data":{"type":4}},{"id":14,"required":0,"data":{"type":6}},{"id":15,"required":0,"data":{"type":7}},{"id":16,"required":0,"data":{"type":9}},{"id":17,"required":0,"data":{"type":8}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2' }); }) }); describe('buildRequestMultiFormat', function () { it('only banner bidder params set', function () { const request = spec.buildRequests(DEFAULT_MULTIFORMAT_BANNER_VALID_BID, {}) - const bannerImpression = JSON.parse(request[0].data.r).imp[0]; - expect(JSON.parse(request[0].data.r).imp).to.have.lengthOf(1); - expect(JSON.parse(request[0].data.v)).to.equal(BANNER_ENDPOINT_VERSION); + const bannerImpression = extractPayload(request[0]).imp[0]; + expect(extractPayload(request[0]).imp).to.have.lengthOf(1); expect(bannerImpression.id).to.equal(DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0].bidId); expect(bannerImpression.banner.format[0].w).to.equal(DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0].params.size[0]); expect(bannerImpression.banner.format[0].h).to.equal(DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0].params.size[1]); @@ -2645,9 +2620,8 @@ describe('IndexexchangeAdapter', function () { describe('only video bidder params set', function () { it('should generate video impression', function () { const request = spec.buildRequests(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID, {}); - const videoImp = JSON.parse(request[1].data.r).imp[0]; - expect(JSON.parse(request[1].data.r).imp).to.have.lengthOf(1); - expect(JSON.parse(request[1].data.v)).to.equal(VIDEO_ENDPOINT_VERSION); + const videoImp = extractPayload(request[1]).imp[0]; + expect(extractPayload(request[1]).imp).to.have.lengthOf(1); expect(videoImp.id).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].bidId); expect(videoImp.video.w).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].params.size[0]); expect(videoImp.video.h).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].params.size[1]); @@ -2659,10 +2633,9 @@ describe('IndexexchangeAdapter', function () { const request = spec.buildRequests(bids, {}); it('should return valid banner requests', function () { - const impressions = JSON.parse(request[0].data.r).imp; + const impressions = extractPayload(request[0]).imp; expect(impressions).to.have.lengthOf(2); - expect(JSON.parse(request[0].data.v)).to.equal(BANNER_ENDPOINT_VERSION); impressions.map((impression, index) => { const bid = bids[index]; @@ -2682,17 +2655,16 @@ describe('IndexexchangeAdapter', function () { }); it('should return valid banner and video requests', function () { - const videoImpression = JSON.parse(request[1].data.r).imp[0]; + const videoImpression = extractPayload(request[1]).imp[0]; - expect(JSON.parse(request[1].data.r).imp).to.have.lengthOf(1); - expect(JSON.parse(request[1].data.v)).to.equal(VIDEO_ENDPOINT_VERSION); + expect(extractPayload(request[1]).imp).to.have.lengthOf(1); expect(videoImpression.id).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].bidId); expect(videoImpression.video.w).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].mediaTypes.video.playerSize[0][0]); expect(videoImpression.video.h).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].mediaTypes.video.playerSize[0][1]); }); it('should contain all correct IXdiag properties', function () { - const diagObj = JSON.parse(request[0].data.r).ext.ixdiag; + const diagObj = extractPayload(request[0]).ext.ixdiag; expect(diagObj.iu).to.equal(0); expect(diagObj.nu).to.equal(0); expect(diagObj.ou).to.equal(2); @@ -2709,6 +2681,17 @@ describe('IndexexchangeAdapter', function () { }); describe('interpretResponse', function () { + // generate bidderRequest with real buildRequest logic for intepretResponse testing + let bannerBidderRequest + let videoBidderRequest + let nativeBidderRequest + + beforeEach(() => { + bannerBidderRequest = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {})[0] + videoBidderRequest = spec.buildRequests(DEFAULT_VIDEO_VALID_BID_MEDIUM_SIZE, {})[0] + nativeBidderRequest = spec.buildRequests(DEFAULT_NATIVE_VALID_BID, {})[0] + }); + it('should get correct bid response for banner ad', function () { const expectedParse = [ { @@ -2730,7 +2713,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, bannerBidderRequest); expect(result[0]).to.deep.equal(expectedParse[0]); }); @@ -2754,7 +2737,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE_WITHOUT_ADOMAIN }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE_WITHOUT_ADOMAIN }, bannerBidderRequest); expect(result[0]).to.deep.equal(expectedParse[0]); }); @@ -2781,7 +2764,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: bidResponse }, bannerBidderRequest); }); it('should set Japanese price correctly', function () { @@ -2807,7 +2790,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: bidResponse }, bannerBidderRequest); expect(result[0]).to.deep.equal(expectedParse[0]); }); @@ -2836,7 +2819,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: bidResponse }, bannerBidderRequest); expect(result[0].dealId).to.equal(expectedParse[0].dealId); }); @@ -2863,7 +2846,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: bidResponse }, bannerBidderRequest); expect(result[0]).to.deep.equal(expectedParse[0]); }); @@ -2891,7 +2874,7 @@ describe('IndexexchangeAdapter', function () { } } ]; - const result = spec.interpretResponse({ body: bidResponse }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: bidResponse }, bannerBidderRequest); expect(result[0].dealId).to.deep.equal(expectedParse[0].dealId); }); @@ -2928,7 +2911,7 @@ describe('IndexexchangeAdapter', function () { } ]; const result = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: ONE_VIDEO + data: videoBidderRequest.data, validBidRequests: ONE_VIDEO }); expect(result[0]).to.deep.equal(expectedParse[0]); @@ -2936,14 +2919,14 @@ describe('IndexexchangeAdapter', function () { it('should set bid[].renderer if renderer not defined at mediaType.video level', function () { const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: DEFAULT_MULTIFORMAT_BANNER_VALID_BID + data: videoBidderRequest.data, validBidRequests: DEFAULT_MULTIFORMAT_BANNER_VALID_BID }); expect(bid[0].renderer).to.exist; }); it('should set renderer URL by parsing video response', function () { const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: DEFAULT_MULTIFORMAT_BANNER_VALID_BID + data: videoBidderRequest.data, validBidRequests: DEFAULT_MULTIFORMAT_BANNER_VALID_BID }); expect(bid[0].renderer.url).to.equal(DEFAULT_VIDEO_BID_RESPONSE.ext.videoplayerurl); }); @@ -2952,10 +2935,10 @@ describe('IndexexchangeAdapter', function () { let outstreamAdUnit = utils.deepClone(DEFAULT_MULTIFORMAT_BANNER_VALID_BID); outstreamAdUnit[0].mediaTypes.video.renderer = { url: 'test', - render: function() {} + render: function () { } }; const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: outstreamAdUnit + data: videoBidderRequest.data, validBidRequests: outstreamAdUnit }); expect(bid[0].renderer).to.be.undefined; }); @@ -2964,10 +2947,10 @@ describe('IndexexchangeAdapter', function () { let outstreamAdUnit = utils.deepClone(DEFAULT_MULTIFORMAT_BANNER_VALID_BID); outstreamAdUnit[0].renderer = { url: 'test', - render: function() {} + render: function () { } }; const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: outstreamAdUnit + data: videoBidderRequest.data, validBidRequests: outstreamAdUnit }); expect(bid[0].renderer).to.be.undefined; }); @@ -2978,7 +2961,7 @@ describe('IndexexchangeAdapter', function () { url: 'test' }; const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: outstreamAdUnit + data: videoBidderRequest.data, validBidRequests: outstreamAdUnit }); expect(bid[0].renderer).to.exist; }); @@ -2987,11 +2970,11 @@ describe('IndexexchangeAdapter', function () { let outstreamAdUnit = utils.deepClone(DEFAULT_MULTIFORMAT_BANNER_VALID_BID); outstreamAdUnit[0].mediaTypes.video.renderer = { url: 'test', - render: function() {}, + render: function () { }, backupOnly: true }; const bid = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: outstreamAdUnit + data: videoBidderRequest.data, validBidRequests: outstreamAdUnit }); expect(bid[0].renderer).to.exist; }); @@ -3029,7 +3012,7 @@ describe('IndexexchangeAdapter', function () { } ]; const result = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE_WITH_MTYPE_SET }, { - data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: ONE_VIDEO + data: videoBidderRequest.data, validBidRequests: ONE_VIDEO }); expect(result[0]).to.deep.equal(expectedParse[0]); @@ -3038,10 +3021,11 @@ describe('IndexexchangeAdapter', function () { it('bidrequest should not have page if options is undefined', function () { const options = {}; const validBidWithoutreferInfo = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithoutreferInfo = JSON.parse(validBidWithoutreferInfo[0].data.r); + const requestWithoutreferInfo = extractPayload(validBidWithoutreferInfo[0]); + const expectedURL = IX_SECURE_ENDPOINT + '?s=' + DEFAULT_BANNER_VALID_BID[0].params.siteId expect(requestWithoutreferInfo.site.page).to.be.undefined; - expect(validBidWithoutreferInfo[0].url).to.equal(IX_SECURE_ENDPOINT); + expect(validBidWithoutreferInfo[0].url).to.equal(expectedURL); }); it('bidrequest should not have page if options.refererInfo is an empty object', function () { @@ -3049,10 +3033,11 @@ describe('IndexexchangeAdapter', function () { refererInfo: {} }; const validBidWithoutreferInfo = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithoutreferInfo = JSON.parse(validBidWithoutreferInfo[0].data.r); + const requestWithoutreferInfo = extractPayload(validBidWithoutreferInfo[0]); + const expectedURL = IX_SECURE_ENDPOINT + '?s=' + DEFAULT_BANNER_VALID_BID[0].params.siteId expect(requestWithoutreferInfo.site.page).to.be.undefined; - expect(validBidWithoutreferInfo[0].url).to.equal(IX_SECURE_ENDPOINT); + expect(validBidWithoutreferInfo[0].url).to.equal(expectedURL); }); it('bidrequest should sent to secure endpoint if page url is secure', function () { @@ -3062,10 +3047,11 @@ describe('IndexexchangeAdapter', function () { } }; const validBidWithoutreferInfo = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithoutreferInfo = JSON.parse(validBidWithoutreferInfo[0].data.r); + const requestWithoutreferInfo = extractPayload(validBidWithoutreferInfo[0]); + const expectedURL = IX_SECURE_ENDPOINT + '?s=' + DEFAULT_BANNER_VALID_BID[0].params.siteId expect(requestWithoutreferInfo.site.page).to.equal(options.refererInfo.page); - expect(validBidWithoutreferInfo[0].url).to.equal(IX_SECURE_ENDPOINT); + expect(validBidWithoutreferInfo[0].url).to.equal(expectedURL); }); it('should set bid[].ttl to seatbid[].bid[].exp value from response', function () { @@ -3073,16 +3059,16 @@ describe('IndexexchangeAdapter', function () { const VIDEO_RESPONSE_WITH_EXP = utils.deepClone(DEFAULT_VIDEO_BID_RESPONSE); VIDEO_RESPONSE_WITH_EXP.seatbid[0].bid[0].exp = 200; BANNER_RESPONSE_WITH_EXP.seatbid[0].bid[0].exp = 100; - const bannerResult = spec.interpretResponse({ body: BANNER_RESPONSE_WITH_EXP }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); - const videoResult = spec.interpretResponse({ body: VIDEO_RESPONSE_WITH_EXP }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const bannerResult = spec.interpretResponse({ body: BANNER_RESPONSE_WITH_EXP }, bannerBidderRequest); + const videoResult = spec.interpretResponse({ body: VIDEO_RESPONSE_WITH_EXP }, videoBidderRequest); expect(bannerResult[0].ttl).to.equal(100); expect(videoResult[0].ttl).to.equal(200); }); it('should default bid[].ttl if seat[].bid[].exp is not in the resposne', function () { - const bannerResult = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); - const videoResult = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const bannerResult = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, bannerBidderRequest); + const videoResult = spec.interpretResponse({ body: DEFAULT_VIDEO_BID_RESPONSE }, videoBidderRequest); expect(bannerResult[0].ttl).to.equal(300); expect(videoResult[0].ttl).to.equal(3600); @@ -3174,7 +3160,7 @@ describe('IndexexchangeAdapter', function () { ttl: 3600 } ]; - const result = spec.interpretResponse({ body: DEFAULT_NATIVE_BID_RESPONSE }, { data: DEFAULT_BIDDER_REQUEST_DATA, validBidRequests: [] }); + const result = spec.interpretResponse({ body: DEFAULT_NATIVE_BID_RESPONSE }, nativeBidderRequest); expect(result[0]).to.deep.equal(expectedParse[0]); }); }); @@ -3182,7 +3168,7 @@ describe('IndexexchangeAdapter', 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); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.regs.ext.gdpr).to.equal(1); expect(requestWithConsent.user.ext.consent).to.equal('3huaa11=qu3198ae'); @@ -3196,7 +3182,7 @@ describe('IndexexchangeAdapter', function () { } }; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.regs.ext.gdpr).to.equal(1); expect(requestWithConsent.user).to.be.undefined; @@ -3210,7 +3196,7 @@ describe('IndexexchangeAdapter', function () { } }; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.regs).to.be.undefined; expect(requestWithConsent.user.ext.consent).to.equal('3huaa11=qu3198ae'); @@ -3219,7 +3205,7 @@ describe('IndexexchangeAdapter', function () { it('should not have consent info if options.gdprConsent is undefined', function () { const options = {}; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.regs).to.be.undefined; expect(requestWithConsent.user).to.be.undefined; @@ -3230,7 +3216,7 @@ describe('IndexexchangeAdapter', function () { uspConsent: '1YYN' }; const validBidWithUspConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithUspConsent = JSON.parse(validBidWithUspConsent[0].data.r); + const requestWithUspConsent = extractPayload(validBidWithUspConsent[0]); expect(requestWithUspConsent.regs.ext.us_privacy).to.equal('1YYN'); }); @@ -3238,7 +3224,7 @@ describe('IndexexchangeAdapter', 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); + const requestWithUspConsent = extractPayload(validBidWithUspConsent[0]); expect(requestWithUspConsent.regs).to.be.undefined; }); @@ -3252,7 +3238,7 @@ describe('IndexexchangeAdapter', function () { uspConsent: '1YYN' }; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.regs.ext.gdpr).to.equal(1); expect(requestWithConsent.regs.ext.us_privacy).to.equal('1YYN'); }); @@ -3266,7 +3252,7 @@ describe('IndexexchangeAdapter', function () { }; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(requestWithConsent.user.ext.consented_providers_settings.consented_providers).to.equal('1~1.35.41.101'); expect(requestWithConsent.user.ext.consent).to.equal('3huaa11=qu3198ae'); }); @@ -3279,7 +3265,7 @@ describe('IndexexchangeAdapter', function () { }; const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); - const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); + const requestWithConsent = extractPayload(validBidWithConsent[0]); expect(utils.deepAccess(requestWithConsent, 'user.ext.consented_providers_settings')).to.not.exist; expect(utils.deepAccess(requestWithConsent, 'user.ext.consent')).to.not.exist; }); @@ -3287,21 +3273,21 @@ describe('IndexexchangeAdapter', function () { it('should set coppa to 1 in config when enabled', () => { config.setConfig({ coppa: true }) const bid = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION); - const r = JSON.parse(bid[0].data.r); + const r = extractPayload(bid[0]); expect(r.regs.coppa).to.equal(1); }); it('should not set coppa in config when disabled', () => { config.setConfig({ coppa: false }) const bid = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION); - const r = JSON.parse(bid[0].data.r); + const r = extractPayload(bid[0]); expect(r.regs.coppa).to.be.undefined; }); it('should not set coppa when not specified in config', () => { config.resetConfig(); const bid = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION); - const r = JSON.parse(bid[0].data.r); + const r = extractPayload(bid[0]); expect(r.regs.coppa).to.be.undefined; }); @@ -3402,127 +3388,6 @@ describe('IndexexchangeAdapter', function () { expect(FEATURE_TOGGLES.isFeatureEnabled('test')).to.be.undefined; expect(FEATURE_TOGGLES.featureToggles).to.deep.equal({}); }); - - it('should create POST request when pbjs_enable_post feature is active', () => { - sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_enable_post = { - activated: true - }; - FEATURE_TOGGLES.setFeatureToggles(serverResponse); - const builtRequests = { - banner: { - request: spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_BANNER_VALID_BID[0].params.siteId - }, - video: { - request: spec.buildRequests(DEFAULT_VIDEO_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_VIDEO_VALID_BID[0].params.siteId - }, - native: { - request: spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_NATIVE_VALID_BID[0].params.siteId - } - }; - - Object.keys(builtRequests).forEach((reqType) => { - const request = builtRequests[reqType].request; - const siteId = builtRequests[reqType].siteId; - expect(request.method).to.equal('POST'); - expect(request.option.contentType).to.equal('text/plain'); - expect(request.url).to.be.equal(`${IX_SECURE_ENDPOINT}?s=${siteId}`); - expect(request.data.r).to.be.undefined; - expect(request.data.ac).to.be.undefined; - expect(request.data.sd).to.be.undefined; - expect(request.data.v).to.be.undefined; - expect(request.data.nf).to.be.undefined; - }); - }); - - it('should create GET request when pbjs_enable_post feature is disabled', () => { - sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_enable_post = { - activated: false - }; - FEATURE_TOGGLES.setFeatureToggles(serverResponse); - const builtRequests = { - banner: { - request: spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_BANNER_VALID_BID[0].params.siteId - }, - video: { - request: spec.buildRequests(DEFAULT_VIDEO_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_VIDEO_VALID_BID[0].params.siteId - }, - native: { - request: spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION)[0], - siteId: DEFAULT_NATIVE_VALID_BID[0].params.siteId - } - }; - - Object.keys(builtRequests).forEach((reqType) => { - const request = builtRequests[reqType].request; - const siteId = builtRequests[reqType].siteId; - expect(request.method).to.equal('GET'); - expect(request.url).to.equal(IX_SECURE_ENDPOINT); - expect(request.data.r).to.exist; - expect(request.data.ac).to.equal('j'); - expect(request.data.sd).to.equal(1); - expect(request.data.s).to.equal(siteId); - if (reqType == 'video') { - expect(request.data.nf).to.equal(1); - } - - if (reqType === 'native') { - expect(request.data.v).to.be.undefined; - } - }); - }); - - it('should interpertResponse correctly when pbjs_enable_post feature is active', function () { - serverResponse.body.ext.features.pbjs_enable_post = { - activated: true - }; - FEATURE_TOGGLES.setFeatureToggles(serverResponse); - const postBiddderRequestData = { - id: '345', - imp: [ - { - id: '1a2b3c4e', - banner: { - w: 300, - h: 250, - placement: 1 - } - } - ], - site: { - ref: 'https://ref.com/ref.html', - page: 'https://page.com' - }, - }; - const expectedParse = [ - { - requestId: '1a2b3c4d', - cpm: 1, - creativeId: '12345', - width: 300, - height: 250, - mediaType: 'banner', - ad: '', - currency: 'USD', - ttl: 300, - netRevenue: true, - meta: { - networkId: 50, - brandId: 303325, - brandName: 'OECTA', - advertiserDomains: ['www.abc.com'] - } - } - ]; - const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data: postBiddderRequestData, validBidRequests: [] }); - expect(result[0]).to.deep.equal(expectedParse[0]); - }); }); describe('LocalStorage error codes', () => { @@ -3640,7 +3505,7 @@ describe('IndexexchangeAdapter', function () { }; expect(spec.isBidRequestValid(bid)).to.be.true; - spec.buildRequests([bid], {ortb2}); + spec.buildRequests([bid], { ortb2 }); expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.PB_FPD_EXCEEDS_MAX_SIZE]: 2 } }); }); @@ -3694,30 +3559,24 @@ describe('IndexexchangeAdapter', function () { expect(spec.isBidRequestValid(request)).to.be.true; const data = { - ...utils.deepClone(DEFAULT_BIDDER_REQUEST_DATA[0]), - r: JSON.stringify({ - id: '345', - imp: [ - { - id: '1a2b3c4e', - } - ], - ext: { - ixdiag: { - err: { - '4': 8 - } + id: '345', + imp: [ + { + id: '1a2b3c4e', + } + ], + ext: { + ixdiag: { + err: { + '4': 8 } } - }), + } }; - const validBidRequests = [ - DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0], - DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0] - ]; + const validBidRequest = DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0]; - spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data, validBidRequests }); + spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data, validBidRequest }); expect(localStorageValues[key]).to.be.undefined; }); From 11fd3d30fd44d832374928e509ff6917a632d7a8 Mon Sep 17 00:00:00 2001 From: Yuki Tsujii Date: Fri, 28 Oct 2022 03:55:24 +0900 Subject: [PATCH 064/367] =?UTF-8?q?localStrage=E3=82=92=E8=AA=AD=E3=81=BF?= =?UTF-8?q?=E8=BE=BC=E3=82=80=E3=81=8B=E3=81=A9=E3=81=86=E3=81=8B=E3=81=AF?= =?UTF-8?q?default:=20false=E3=81=A8=E3=81=AA=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB=E5=A4=89=E6=9B=B4=20(#9146)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: mediaconsortium-develop --- modules/dgkeywordRtdProvider.js | 6 +++--- test/spec/modules/dgkeywordRtdProvider_spec.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/dgkeywordRtdProvider.js b/modules/dgkeywordRtdProvider.js index 032cb4a780a..99df3b18a39 100644 --- a/modules/dgkeywordRtdProvider.js +++ b/modules/dgkeywordRtdProvider.js @@ -41,7 +41,7 @@ export function getDgKeywordsAndSet(reqBidsConfigObj, callback, moduleConfig, us } else { logMessage('[dgkeyword sub module] dgkeyword targets:', setKeywordTargetBidders); logMessage('[dgkeyword sub module] get targets from profile api start.'); - ajax(getProfileApiUrl(moduleConfig?.params?.url, moduleConfig?.params?.disableReadFpid), { + ajax(getProfileApiUrl(moduleConfig?.params?.url, moduleConfig?.params?.enableReadFpid), { success: function(response) { const res = JSON.parse(response); if (!isFinish) { @@ -96,9 +96,9 @@ export function getDgKeywordsAndSet(reqBidsConfigObj, callback, moduleConfig, us } } -export function getProfileApiUrl(customeUrl, disableReadFpid) { +export function getProfileApiUrl(customeUrl, enableReadFpid) { const URL = 'https://mediaconsortium.profiles.tagger.opecloud.com/api/v1'; - const fpid = (disableReadFpid) ? '' : readFpidFromLocalStrage(); + const fpid = (enableReadFpid) ? readFpidFromLocalStrage() : ''; let url = customeUrl || URL; url = url + '?url=' + encodeURIComponent(window.location.href) + ((fpid) ? `&fpid=${fpid}` : ''); return url; diff --git a/test/spec/modules/dgkeywordRtdProvider_spec.js b/test/spec/modules/dgkeywordRtdProvider_spec.js index 16f2906b681..754740b7a64 100644 --- a/test/spec/modules/dgkeywordRtdProvider_spec.js +++ b/test/spec/modules/dgkeywordRtdProvider_spec.js @@ -383,10 +383,11 @@ describe('Digital Garage Keyword Module', function () { } let moduleConfig = cloneDeep(DEF_CONFIG); window.localStorage.setItem('ope_fpid', uuid); + moduleConfig.params.enableReadFpid = true; dgRtd.getDgKeywordsAndSet( pbjs, () => { - const url = dgRtd.getProfileApiUrl(null); + const url = dgRtd.getProfileApiUrl(null, moduleConfig.params.enableReadFpid); expect(url.indexOf(uuid) > 0).to.equal(true); expect(url).to.equal(server.requests[0].url); done(); @@ -410,11 +411,10 @@ describe('Digital Garage Keyword Module', function () { } let moduleConfig = cloneDeep(DEF_CONFIG); window.localStorage.setItem('ope_fpid', uuid); - moduleConfig.params.disableReadFpid = true; dgRtd.getDgKeywordsAndSet( pbjs, () => { - const url = dgRtd.getProfileApiUrl(null, moduleConfig.params.disableReadFpid); + const url = dgRtd.getProfileApiUrl(null); expect(url.indexOf(uuid) > 0).to.equal(false); expect(url).to.equal(server.requests[0].url); done(); From e08fea6af362770bb67cf6f466c871c5d03b8c92 Mon Sep 17 00:00:00 2001 From: Jozef Bartek <31618107+jbartek25@users.noreply.github.com> Date: Thu, 27 Oct 2022 20:58:11 +0200 Subject: [PATCH 065/367] Improve Digital adapter: publisher endpoint, addtl consent, syncs (#9125) * Improve Digital adapter: publisher endpoint, addtl consent, syncs (#14) - add bidders to sync url when extend mode enabled - set ConsentedProvidersSettings when extend mode enabled - dynamically generated AD_SERVER_URL when publisherId available * Code refactored * Minor changes Co-authored-by: Faisal Islam <93644923+faisalvs@users.noreply.github.com> Co-authored-by: Faisal Islam --- modules/improvedigitalBidAdapter.js | 59 ++++++++++--- .../modules/improvedigitalBidAdapter_spec.js | 86 ++++++++++++++++++- 2 files changed, 131 insertions(+), 14 deletions(-) diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js index cc039354878..94f50094a91 100644 --- a/modules/improvedigitalBidAdapter.js +++ b/modules/improvedigitalBidAdapter.js @@ -10,8 +10,9 @@ import {loadExternalScript} from '../src/adloader.js'; const BIDDER_CODE = 'improvedigital'; const CREATIVE_TTL = 300; -const AD_SERVER_URL = 'https://ad.360yield.com/pb'; -const BASIC_ADS_URL = 'https://ad.360yield-basic.com/pb'; +const AD_SERVER_BASE_URL = 'https://ad.360yield.com'; +const BASIC_ADS_BASE_URL = 'https://ad.360yield-basic.com'; +const PB_ENDPOINT = 'pb'; const EXTEND_URL = 'https://pbs.360yield.com/openrtb2/auction'; const IFRAME_SYNC_URL = 'https://hb.360yield.com/prebid-universal-creative/load-cookie.html'; @@ -79,6 +80,13 @@ export const spec = { const syncs = []; if ((this.syncStore.extendMode || !syncOptions.pixelEnabled) && syncOptions.iframeEnabled) { const { gdprApplies, consentString } = gdprConsent || {}; + const bidders = new Set(); + if (this.syncStore.extendMode && serverResponses) { + serverResponses.forEach(response => { + if (!response?.body?.ext?.responsetimemillis) return; + Object.keys(response.body.ext.responsetimemillis).forEach(b => bidders.add(b)) + }) + } syncs.push({ type: 'iframe', url: IFRAME_SYNC_URL + @@ -86,7 +94,8 @@ export const spec = { (this.syncStore.extendMode ? '&pbs=1' : '') + (typeof gdprApplies === 'boolean' ? `&gdpr=${Number(gdprApplies)}` : '') + (consentString ? `&gdpr_consent=${consentString}` : '') + - (uspConsent ? `&us_privacy=${encodeURIComponent(uspConsent)}` : '') + (uspConsent ? `&us_privacy=${encodeURIComponent(uspConsent)}` : '') + + (bidders.size ? `&bidders=${[...bidders].join(',')}` : '') }); } else if (syncOptions.pixelEnabled) { serverResponses.forEach(response => { @@ -220,8 +229,14 @@ export const CONVERTER = ortbConverter({ }, request: { gdprAddtlConsent(setAddtlConsent, ortbRequest, bidderRequest) { - // override attlConsent processor to do some additional parsing, and use a different destination - const additionalConsent = deepAccess(bidderRequest, 'gdprConsent.addtlConsent'); + const additionalConsent = bidderRequest?.gdprConsent?.addtlConsent; + if (!additionalConsent) { + return; + } + if (spec.syncStore.extendMode) { + setAddtlConsent(ortbRequest, bidderRequest); + return; + } if (additionalConsent && additionalConsent.indexOf('~') !== -1) { // Google Ad Tech Provider IDs const atpIds = additionalConsent.substring(additionalConsent.indexOf('~') + 1); @@ -247,23 +262,43 @@ const ID_REQUEST = { const extendBids = []; const adServerBids = []; - function formatRequest(bidRequests, extendMode) { + function adServerUrl(extendMode, publisherId) { + if (extendMode) { + return EXTEND_URL; + } + const urlSegments = []; + urlSegments.push(hasPurpose1Consent(bidderRequest?.gdprConsent) ? AD_SERVER_BASE_URL : BASIC_ADS_BASE_URL) + if (publisherId) { + urlSegments.push(publisherId) + } + urlSegments.push(PB_ENDPOINT) + return urlSegments.join('/'); + } + + function formatRequest(bidRequests, publisherId, extendMode) { const ortbRequest = CONVERTER.toORTB({bidRequests, bidderRequest, context: {extendMode}}); - const adServerUrl = hasPurpose1Consent(bidderRequest?.gdprConsent) ? AD_SERVER_URL : BASIC_ADS_URL; return { method: 'POST', - url: extendMode ? EXTEND_URL : adServerUrl, + url: adServerUrl(extendMode, publisherId), data: JSON.stringify(ortbRequest), - ortbRequest + ortbRequest, + bidderRequest } } + let publisherId = null; bidRequests.map((bidRequest) => { + const bidParamsPublisherId = bidRequest.params.publisherId; const extendModeEnabled = this.isExtendModeEnabled(globalExtendMode, bidRequest.params); if (singleRequestMode) { + if (!publisherId) { + publisherId = bidParamsPublisherId; + } else if (bidParamsPublisherId && publisherId !== bidParamsPublisherId) { + throw new Error(`All Improve Digital placements in a single call must have the same publisherId. Please check your 'params.publisherId' or turn off the single request mode.`); + } extendModeEnabled ? extendBids.push(bidRequest) : adServerBids.push(bidRequest); } else { - requests.push(formatRequest([bidRequest], extendModeEnabled)); + requests.push(formatRequest([bidRequest], bidParamsPublisherId, extendModeEnabled)); } }); @@ -272,10 +307,10 @@ const ID_REQUEST = { } // In the single request mode, split imps between those going to the ad server and those going to extend server if (extendBids.length) { - requests.push(formatRequest(extendBids, true)); + requests.push(formatRequest(extendBids, publisherId, true)); } if (adServerBids.length) { - requests.push(formatRequest(adServerBids, false)); + requests.push(formatRequest(adServerBids, publisherId, false)); } return requests; diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js index 9190c008a9f..b3b01dc93b5 100644 --- a/test/spec/modules/improvedigitalBidAdapter_spec.js +++ b/test/spec/modules/improvedigitalBidAdapter_spec.js @@ -18,8 +18,11 @@ import {createEidsArray} from '../../../modules/userId/eids.js'; describe('Improve Digital Adapter Tests', function () { const METHOD = 'POST'; - const AD_SERVER_URL = 'https://ad.360yield.com/pb'; - const BASIC_ADS_URL = 'https://ad.360yield-basic.com/pb'; + const AD_SERVER_BASE_URL = 'https://ad.360yield.com'; + const BASIC_ADS_BASE_URL = 'https://ad.360yield-basic.com'; + const PB_ENDPOINT = 'pb'; + const AD_SERVER_URL = `${AD_SERVER_BASE_URL}/${PB_ENDPOINT}`; + const BASIC_ADS_URL = `${BASIC_ADS_BASE_URL}/${PB_ENDPOINT}`; const EXTEND_URL = 'https://pbs.360yield.com/openrtb2/auction'; const IFRAME_SYNC_URL = 'https://hb.360yield.com/prebid-universal-creative/load-cookie.html'; const INSTREAM_TYPE = 1; @@ -390,6 +393,7 @@ describe('Improve Digital Adapter Tests', function () { const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdpr)[0].data); expect(payload.regs.ext.gdpr).to.exist.and.to.equal(1); expect(payload.user.ext.consent).to.equal('CONSENT'); + expect(payload.user.ext.ConsentedProvidersSettings).to.not.exist; expect(payload.user.ext.consented_providers_settings.consented_providers).to.exist.and.to.deep.equal([1, 35, 41, 101]); }); @@ -401,6 +405,15 @@ describe('Improve Digital Adapter Tests', function () { expect(payload.user.ext.consented_providers_settings).to.not.exist; }); + it('should add ConsentedProvidersSettings when extend mode enabled', function () { + const bidRequest = deepClone(extendBidRequest); + const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdpr)[0].data); + expect(payload.regs.ext.gdpr).to.exist.and.to.equal(1); + expect(payload.user.ext.consent).to.equal('CONSENT'); + expect(payload.user.ext.ConsentedProvidersSettings.consented_providers).to.exist.and.to.equal('1~1.35.41.101'); + expect(payload.user.ext.consented_providers_settings).to.not.exist; + }); + it('should add CCPA consent string', function () { const bidRequest = Object.assign({}, simpleBidRequest); const request = spec.buildRequests([bidRequest], {...bidderRequest, ...{ uspConsent: '1YYY' }}); @@ -753,6 +766,64 @@ describe('Improve Digital Adapter Tests', function () { expect(requests[0].url).to.equal(AD_SERVER_URL); expect(requests[1].url).to.equal(EXTEND_URL); }); + + it('should add publisherId to request URL when available in request params', function() { + function formatPublisherUrl(baseUrl, publisherId) { + return `${baseUrl}/${publisherId}/${PB_ENDPOINT}`; + } + const bidRequest = deepClone(simpleBidRequest); + bidRequest.params.publisherId = 1000; + let request = spec.buildRequests([bidRequest], bidderRequest)[0]; + expect(request).to.be.an('object'); + sinon.assert.match(request, { + method: METHOD, + url: formatPublisherUrl(AD_SERVER_BASE_URL, 1000), + bidderRequest + }); + + const bidRequest2 = deepClone(simpleBidRequest) + bidRequest2.params.publisherId = 1002; + + const bidRequest3 = deepClone(extendBidRequest) + bidRequest3.params.publisherId = 1002; + + const request1 = spec.buildRequests([bidRequest, bidRequest2], bidderRequest)[0]; + expect(request1.url).to.equal(formatPublisherUrl(AD_SERVER_BASE_URL, 1000)); + const request2 = spec.buildRequests([bidRequest, bidRequest2], bidderRequest)[1]; + expect(request2.url).to.equal(formatPublisherUrl(AD_SERVER_BASE_URL, 1002)); + const request3 = spec.buildRequests([bidRequest, bidRequest3], bidderRequest)[1]; + expect(request3.url).to.equal(EXTEND_URL); + + // Enable single request mode + getConfigStub = sinon.stub(config, 'getConfig'); + getConfigStub.withArgs('improvedigital.singleRequest').returns(true); + try { + spec.buildRequests([bidRequest, bidRequest2], bidderRequest)[0]; + } catch (e) { + expect(e.name).to.exist.equal('Error') + expect(e.message).to.exist.equal(`All Improve Digital placements in a single call must have the same publisherId. Please check your 'params.publisherId' or turn off the single request mode.`) + } + + bidRequest2.params.publisherId = null; + request = spec.buildRequests([bidRequest, bidRequest2], bidderRequest)[0]; + expect(request.url).to.equal(formatPublisherUrl(AD_SERVER_BASE_URL, 1000)); + + const consent = deepClone(gdprConsent); + deepSetValue(consent, 'vendorData.purpose.consents.1', false); + const bidderRequestWithConsent = deepClone(bidderRequest); + bidderRequestWithConsent.gdprConsent = consent; + request = spec.buildRequests([bidRequest], bidderRequestWithConsent)[0]; + expect(request.url).to.equal(formatPublisherUrl(BASIC_ADS_BASE_URL, 1000)); + + deepSetValue(consent, 'vendorData.purpose.consents.1', true); + bidderRequestWithConsent.gdprConsent = consent; + request = spec.buildRequests([bidRequest], bidderRequestWithConsent)[0]; + expect(request.url).to.equal(formatPublisherUrl(AD_SERVER_BASE_URL, 1000)); + + delete bidRequest.params.publisherId; + request = spec.buildRequests([bidRequest], bidderRequestWithConsent)[0]; + expect(request.url).to.equal(AD_SERVER_URL); + }); }); const serverResponse = { @@ -1285,5 +1356,16 @@ describe('Improve Digital Adapter Tests', function () { const syncs = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }, serverResponses); expect(syncs).to.deep.equal([{ type: 'iframe', url: basicIframeSyncUrl + '&pbs=1' }]); }); + + it('should add bidders to iframe user sync url', function () { + getConfigStub = sinon.stub(config, 'getConfig'); + getConfigStub.withArgs('improvedigital.extend').returns(true); + spec.buildRequests([simpleBidRequest], {}); + const rawResponse = deepClone(serverResponse) + deepSetValue(rawResponse, 'body.ext.responsetimemillis', {a: 1, b: 1, c: 1, d: 1, e: 1}) + let syncs = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }, [rawResponse]); + let url = basicIframeSyncUrl + '&pbs=1' + '&bidders=a,b,c,d,e' + expect(syncs).to.deep.equal([{ type: 'iframe', url }]); + }); }); }); From cc3f01df18a21fa163fa34723556313d76eece9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9onard=20Labat?= Date: Thu, 27 Oct 2022 20:59:01 +0200 Subject: [PATCH 066/367] Criteo Bid Adapter : Bump Publisher Tag version (#9151) --- modules/criteoBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 622c42c9cb7..c0251ab0165 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -27,7 +27,7 @@ const LOG_PREFIX = 'Criteo: '; Unminified source code can be found in the privately shared repo: https://github.com/Prebid-org/prebid-js-external-js-criteo/blob/master/dist/prod.js */ const FAST_BID_VERSION_PLACEHOLDER = '%FAST_BID_VERSION%'; -export const FAST_BID_VERSION_CURRENT = 130; +export const FAST_BID_VERSION_CURRENT = 132; const FAST_BID_VERSION_LATEST = 'latest'; const FAST_BID_VERSION_NONE = 'none'; const PUBLISHER_TAG_URL_TEMPLATE = 'https://static.criteo.net/js/ld/publishertag.prebid' + FAST_BID_VERSION_PLACEHOLDER + '.js'; From 297bb486c8be55e1dafd793cb9757fcb3a38d269 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 27 Oct 2022 12:51:17 -0700 Subject: [PATCH 067/367] Prebid core: allow configurable TTL buffer (#9136) --- src/auction.js | 5 ++++ src/prebid.js | 9 ++++--- src/targeting.js | 12 ++++++++-- test/spec/auctionmanager_spec.js | 6 +++++ test/spec/unit/core/targeting_spec.js | 34 +++++++++++++++++++++++++++ test/spec/unit/pbjs_api_spec.js | 12 +++++++++- 6 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/auction.js b/src/auction.js index 89b8f21d571..469cb2adcd1 100644 --- a/src/auction.js +++ b/src/auction.js @@ -666,6 +666,7 @@ export const callPrebidCache = hook('async', function(auctionInstance, bidRespon */ function addCommonResponseProperties(bidResponse, adUnitCode, {index = auctionManager.index} = {}) { const bidderRequest = index.getBidderRequest(bidResponse); + const adUnit = index.getAdUnit(bidResponse); const start = (bidderRequest && bidderRequest.start) || bidResponse.requestTimestamp; Object.assign(bidResponse, { @@ -676,6 +677,10 @@ function addCommonResponseProperties(bidResponse, adUnitCode, {index = auctionMa adUnitCode }); + if (adUnit?.ttlBuffer != null) { + bidResponse.ttlBuffer = adUnit.ttlBuffer; + } + bidResponse.timeToRespond = bidResponse.responseTimestamp - bidResponse.requestTimestamp; } diff --git a/src/prebid.js b/src/prebid.js index 7b1cfd258ec..94391343cd3 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -622,7 +622,7 @@ $$PREBID_GLOBAL$$.removeAdUnit = function (adUnitCode) { * @alias module:pbjs.requestBids */ $$PREBID_GLOBAL$$.requestBids = (function() { - const delegate = hook('sync', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels, auctionId, ortb2, metrics } = {}) { + const delegate = hook('sync', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2, metrics } = {}) { events.emit(REQUEST_BIDS); const cbTimeout = timeout || config.getConfig('bidderTimeout'); logInfo('Invoking $$PREBID_GLOBAL$$.requestBids', arguments); @@ -630,7 +630,7 @@ $$PREBID_GLOBAL$$.requestBids = (function() { global: mergeDeep({}, config.getAnyConfig('ortb2') || {}, ortb2 || {}), bidder: Object.fromEntries(Object.entries(config.getBidderConfig()).map(([bidder, cfg]) => [bidder, cfg.ortb2]).filter(([_, ortb2]) => ortb2 != null)) } - return startAuction({bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ortb2Fragments, metrics}); + return startAuction({bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2Fragments, metrics}); }, 'requestBids'); return wrapHook(delegate, function requestBids(req = {}) { @@ -646,7 +646,7 @@ $$PREBID_GLOBAL$$.requestBids = (function() { }); })(); -export const startAuction = hook('sync', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ortb2Fragments, metrics } = {}) { +export const startAuction = hook('sync', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, ttlBuffer, adUnitCodes, labels, auctionId, ortb2Fragments, metrics } = {}) { const s2sBidders = getS2SBidderSet(config.getConfig('s2sConfig') || []); adUnits = useMetrics(metrics).measureTime('requestBids.validate', () => checkAdUnitSetup(adUnits)); @@ -688,6 +688,9 @@ export const startAuction = hook('sync', function ({ bidsBackHandler, timeout: c const tid = adUnit.ortb2Imp?.ext?.tid || generateUUID(); adUnit.transactionId = tid; + if (ttlBuffer != null && !adUnit.hasOwnProperty('ttlBuffer')) { + adUnit.ttlBuffer = ttlBuffer; + } // Populate ortb2Imp.ext.tid with transactionId. Specifying a transaction ID per item in the ortb impression array, lets multiple transaction IDs be transmitted in a single bid request. deepSetValue(adUnit, 'ortb2Imp.ext.tid', tid); diff --git a/src/targeting.js b/src/targeting.js index a427867e890..a75c9a2b52f 100644 --- a/src/targeting.js +++ b/src/targeting.js @@ -28,7 +28,15 @@ import CONSTANTS from './constants.json'; var pbTargetingKeys = []; const MAX_DFP_KEYLENGTH = 20; -const TTL_BUFFER = 1000; +let DEFAULT_TTL_BUFFER = 1; + +config.getConfig('ttlBuffer', (cfg) => { + if (typeof cfg.ttlBuffer === 'number') { + DEFAULT_TTL_BUFFER = cfg.ttlBuffer; + } else { + logError('Invalid value for ttlBuffer', cfg.ttlBuffer); + } +}) const CFG_ALLOW_TARGETING_KEYS = `targetingControls.allowTargetingKeys`; const CFG_ADD_TARGETING_KEYS = `targetingControls.addTargetingKeys`; @@ -39,7 +47,7 @@ export const TARGETING_KEYS = Object.keys(CONSTANTS.TARGETING_KEYS).map( ); // return unexpired bids -const isBidNotExpired = (bid) => (bid.responseTimestamp + bid.ttl * 1000 - TTL_BUFFER) > timestamp(); +const isBidNotExpired = (bid) => (bid.responseTimestamp + (bid.ttl - (bid.hasOwnProperty('ttlBuffer') ? bid.ttlBuffer : DEFAULT_TTL_BUFFER)) * 1000) > timestamp(); // return bids whose status is not set. Winning bids can only have a status of `rendered`. const isUnusedBid = (bid) => bid && ((bid.status && !includes([CONSTANTS.BID_STATUS.RENDERED], bid.status)) || !bid.status); diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index e36b2ccbb07..a48424b045c 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -955,6 +955,12 @@ describe('auctionmanager.js', function () { const addedBid = find(auction.getBidsReceived(), bid => bid.adUnitCode == ADUNIT_CODE); assert.equal(addedBid.renderer.url, 'renderer.js'); }); + + it('sets bidResponse.ttlBuffer from adUnit.ttlBuffer', () => { + adUnits[0].ttlBuffer = 0; + auction.callBids(); + expect(auction.getBidsReceived()[0].ttlBuffer).to.eql(0); + }); }); describe('when auction timeout is 20', function () { diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js index 448f1b36e3a..f9fe2e398b0 100644 --- a/test/spec/unit/core/targeting_spec.js +++ b/test/spec/unit/core/targeting_spec.js @@ -269,6 +269,40 @@ describe('targeting tests', function () { bidCacheFilterFunction = undef; }); + describe('isBidNotExpired', () => { + let clock; + beforeEach(() => { + clock = sandbox.useFakeTimers(0); + }); + + Object.entries({ + 'bid.ttlBuffer': (bid, ttlBuffer) => { + bid.ttlBuffer = ttlBuffer + }, + 'setConfig({ttlBuffer})': (_, ttlBuffer) => { + config.setConfig({ttlBuffer}) + }, + }).forEach(([t, setup]) => { + describe(`respects ${t}`, () => { + [0, 2].forEach(ttlBuffer => { + it(`when ttlBuffer is ${ttlBuffer}`, () => { + const bid = { + responseTimestamp: 0, + ttl: 10, + } + setup(bid, ttlBuffer); + + expect(filters.isBidNotExpired(bid)).to.be.true; + clock.tick((bid.ttl - ttlBuffer) * 1000 - 100); + expect(filters.isBidNotExpired(bid)).to.be.true; + clock.tick(101); + expect(filters.isBidNotExpired(bid)).to.be.false; + }); + }); + }); + }); + }); + describe('getAllTargeting', function () { let amBidsReceivedStub; let amGetAdUnitsStub; diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index e83608325d8..b8b82f7ca96 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -1459,7 +1459,7 @@ describe('Unit: Prebid Module', function () { describe('requestBids', function () { let logMessageSpy; - let makeRequestsStub; + let makeRequestsStub, createAuctionStub; let adUnits; let clock; before(function () { @@ -1670,6 +1670,16 @@ describe('Unit: Prebid Module', function () { }) }) }) + + it('should transfer ttlBuffer to adUnit.ttlBuffer', () => { + $$PREBID_GLOBAL$$.requestBids({ + ttlBuffer: 123, + adUnits: [adUnits[0], {...adUnits[0], ttlBuffer: 0}] + }); + sinon.assert.calledWithMatch(auctionModule.newAuction, { + adUnits: sinon.match((units) => units[0].ttlBuffer === 123 && units[1].ttlBuffer === 0) + }) + }); }) describe('requestBids', function () { From c39afc8d2aafcb36f88a403003a030e8f153719c Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 28 Oct 2022 12:49:37 +0000 Subject: [PATCH 068/367] Prebid 7.23.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec0bebcd2d9..9dc01f50c8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.23.0-pre", + "version": "7.23.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index c5f1b1861a0..7515b1d6248 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.23.0-pre", + "version": "7.23.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 3fa7e3701df9dead109526a96140657cbbd14f01 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 28 Oct 2022 12:49:37 +0000 Subject: [PATCH 069/367] Increment version to 7.24.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9dc01f50c8b..d37403f06e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.23.0", + "version": "7.24.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 7515b1d6248..60586841a53 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.23.0", + "version": "7.24.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From efedc7454d1eb352f14db5168df766da34c71f2a Mon Sep 17 00:00:00 2001 From: Samuel Adu Date: Fri, 28 Oct 2022 14:28:46 +0100 Subject: [PATCH 070/367] ConnectId User ID Module: Support Publisher-supplied user identifier (#9119) * ConnectId User ID Module: Support Publisher-supplied user identifier * Additonal tests for increased coverage * Linting * Linting Co-authored-by: slimkrazy --- modules/connectIdSystem.js | 59 ++++--- modules/connectIdSystem.md | 5 +- test/spec/modules/connectIdSystem_spec.js | 180 +++++++++++++++++++++- 3 files changed, 214 insertions(+), 30 deletions(-) diff --git a/modules/connectIdSystem.js b/modules/connectIdSystem.js index 4fad832302f..24ef8ad0af5 100644 --- a/modules/connectIdSystem.js +++ b/modules/connectIdSystem.js @@ -15,18 +15,7 @@ const VENDOR_ID = 25; const PLACEHOLDER = '__PIXEL_ID__'; const UPS_ENDPOINT = `https://ups.analytics.yahoo.com/ups/${PLACEHOLDER}/fed`; const OVERRIDE_OPT_OUT_KEY = 'connectIdOptOut'; - -function isEUConsentRequired(consentData) { - return !!(consentData && consentData.gdpr && consentData.gdpr.gdprApplies); -} - -function userHasOptedOut() { - try { - return localStorage.getItem(OVERRIDE_OPT_OUT_KEY) === '1'; - } catch { - return false; - } -} +const INPUT_PARAM_KEYS = ['pixelId', 'he', 'puid']; /** @type {Submodule} */ export const connectIdSubmodule = { @@ -45,7 +34,7 @@ export const connectIdSubmodule = { * @returns {{connectId: string} | undefined} */ decode(value) { - if (userHasOptedOut()) { + if (connectIdSubmodule.userHasOptedOut()) { return undefined; } return (typeof value === 'object' && value.connectid) @@ -59,27 +48,29 @@ export const connectIdSubmodule = { * @returns {IdResponse|undefined} */ getId(config, consentData) { - if (userHasOptedOut()) { + if (connectIdSubmodule.userHasOptedOut()) { return; } const params = config.params || {}; - if (!params || typeof params.he !== 'string' || - (typeof params.pixelId === 'undefined' && typeof params.endpoint === 'undefined')) { - logError('The connectId submodule requires the \'he\' and \'pixelId\' parameters to be defined.'); + if (!params || (typeof params.he !== 'string' && typeof params.puid !== 'string') || + (typeof params.pixelId === 'undefined' && typeof params.endpoint === 'undefined')) { + logError('The connectId submodule requires the \'pixelId\' and at least one of the \'he\' ' + + 'or \'puid\' parameters to be defined.'); return; } const data = { '1p': includes([1, '1', true], params['1p']) ? '1' : '0', - he: params.he, - gdpr: isEUConsentRequired(consentData) ? '1' : '0', - gdpr_consent: isEUConsentRequired(consentData) ? consentData.gdpr.consentString : '', + gdpr: connectIdSubmodule.isEUConsentRequired(consentData) ? '1' : '0', + gdpr_consent: connectIdSubmodule.isEUConsentRequired(consentData) ? consentData.gdpr.consentString : '', us_privacy: consentData && consentData.uspConsent ? consentData.uspConsent : '' }; - if (params.pixelId) { - data.pixelId = params.pixelId - } + INPUT_PARAM_KEYS.forEach(key => { + if (typeof params[key] != 'undefined') { + data[key] = params[key]; + } + }); const resp = function (callback) { const callbacks = { @@ -106,6 +97,28 @@ export const connectIdSubmodule = { return {callback: resp}; }, + /** + * Utility function that returns a boolean flag indicating if the opporunity + * is subject to GDPR + * @returns {Boolean} + */ + isEUConsentRequired(consentData) { + return !!(consentData && consentData.gdpr && consentData.gdpr.gdprApplies); + }, + + /** + * Utility function that returns a boolean flag indicating if the user + * has opeted out via the Yahoo easy-opt-out mechanism. + * @returns {Boolean} + */ + userHasOptedOut() { + try { + return localStorage.getItem(OVERRIDE_OPT_OUT_KEY) === '1'; + } catch { + return false; + } + }, + /** * Return the function used to perform XHR calls. * Utilised for each of testing. diff --git a/modules/connectIdSystem.md b/modules/connectIdSystem.md index f2153e1b6cb..c671c036b77 100644 --- a/modules/connectIdSystem.md +++ b/modules/connectIdSystem.md @@ -29,5 +29,6 @@ The below parameters apply only to the Yahoo ConnectID user ID Module. | --- | --- | --- | --- | --- | | name | Required | String | ID value for the Yahoo ConnectID module - `"connectId"` | `"connectId"` | | params | Required | Object | Data for Yahoo ConnectID initialization. | | -| params.pixelId | Required | Number | The Yahoo supplied publisher specific pixel Id | `8976` | -| params.he | Required | String | The SHA-256 hashed user email address | `"529cb86de31e9547a712d9f380146e98bbd39beec"` | +| params.pixelId | Required | Number | The Yahoo supplied publisher specific pixel Id. | `8976` | +| params.he | Optional | String | The SHA-256 hashed user email address. One of either the `he` parameter or the `puid` parameter must be supplied. | `"529cb86de31e9547a712d9f380146e98bbd39beec"` | +| params.puid | Optional | String | The publisher-supplied user identifier. One of either the `he` parameter or the `puid` parameter must be supplied. | `"P-975484817"` | diff --git a/test/spec/modules/connectIdSystem_spec.js b/test/spec/modules/connectIdSystem_spec.js index fe3cb81c2ea..b2193f350ce 100644 --- a/test/spec/modules/connectIdSystem_spec.js +++ b/test/spec/modules/connectIdSystem_spec.js @@ -4,6 +4,7 @@ import {connectIdSubmodule} from 'modules/connectIdSystem.js'; describe('Yahoo ConnectID Submodule', () => { const HASHED_EMAIL = '6bda6f2fa268bf0438b5423a9861a2cedaa5dec163c03f743cfe05c08a8397b2'; + const PUBLISHER_USER_ID = '975484817'; const PIXEL_ID = '1234'; const PROD_ENDPOINT = `https://ups.analytics.yahoo.com/ups/${PIXEL_ID}/fed`; const OVERRIDE_ENDPOINT = 'https://foo/bar'; @@ -48,26 +49,55 @@ describe('Yahoo ConnectID Submodule', () => { return result; } - it('returns undefined if he and pixelId params are not passed', () => { + it('returns undefined if he, pixelId and puid params are not passed', () => { expect(invokeGetIdAPI({}, consentData)).to.be.undefined; expect(ajaxStub.callCount).to.equal(0); }); it('returns undefined if the pixelId param is not passed', () => { expect(invokeGetIdAPI({ - he: HASHED_EMAIL + he: HASHED_EMAIL, + puid: PUBLISHER_USER_ID }, consentData)).to.be.undefined; expect(ajaxStub.callCount).to.equal(0); }); - it('returns undefined if the he param is not passed', () => { + it('returns undefined if the pixelId param is passed, but the he and puid param are not passed', () => { expect(invokeGetIdAPI({ pixelId: PIXEL_ID }, consentData)).to.be.undefined; expect(ajaxStub.callCount).to.equal(0); }); - it('returns an object with the callback function if the correct params are passed', () => { + it('returns an object with the callback function if the endpoint override param and the he params are passed', () => { + let result = invokeGetIdAPI({ + he: HASHED_EMAIL, + endpoint: OVERRIDE_ENDPOINT + }, consentData); + expect(result).to.be.an('object').that.has.all.keys('callback'); + expect(result.callback).to.be.a('function'); + }); + + it('returns an object with the callback function if the endpoint override param and the puid params are passed', () => { + let result = invokeGetIdAPI({ + puid: PUBLISHER_USER_ID, + endpoint: OVERRIDE_ENDPOINT + }, consentData); + expect(result).to.be.an('object').that.has.all.keys('callback'); + expect(result.callback).to.be.a('function'); + }); + + it('returns an object with the callback function if the endpoint override param and the puid and he params are passed', () => { + let result = invokeGetIdAPI({ + he: HASHED_EMAIL, + puid: PUBLISHER_USER_ID, + endpoint: OVERRIDE_ENDPOINT + }, consentData); + expect(result).to.be.an('object').that.has.all.keys('callback'); + expect(result.callback).to.be.a('function'); + }); + + it('returns an object with the callback function if the pixelId and he params are passed', () => { let result = invokeGetIdAPI({ he: HASHED_EMAIL, pixelId: PIXEL_ID @@ -76,6 +106,25 @@ describe('Yahoo ConnectID Submodule', () => { expect(result.callback).to.be.a('function'); }); + it('returns an object with the callback function if the pixelId and puid params are passed', () => { + let result = invokeGetIdAPI({ + puid: PUBLISHER_USER_ID, + pixelId: PIXEL_ID + }, consentData); + expect(result).to.be.an('object').that.has.all.keys('callback'); + expect(result.callback).to.be.a('function'); + }); + + it('returns an object with the callback function if the pixelId, he and puid params are passed', () => { + let result = invokeGetIdAPI({ + he: HASHED_EMAIL, + puid: PUBLISHER_USER_ID, + pixelId: PIXEL_ID + }, consentData); + expect(result).to.be.an('object').that.has.all.keys('callback'); + expect(result.callback).to.be.a('function'); + }); + it('returns an undefined if the Yahoo specific opt-out key is present in local storage', () => { localStorage.setItem('connectIdOptOut', '1'); expect(invokeGetIdAPI({ @@ -96,13 +145,57 @@ describe('Yahoo ConnectID Submodule', () => { localStorage.removeItem('connectIdOptOut'); }); - it('Makes an ajax GET request to the production API endpoint with query params', () => { + it('Makes an ajax GET request to the production API endpoint with pixelId and he query params', () => { + invokeGetIdAPI({ + he: HASHED_EMAIL, + pixelId: PIXEL_ID + }, consentData); + + const expectedParams = { + he: HASHED_EMAIL, + pixelId: PIXEL_ID, + '1p': '0', + gdpr: '1', + gdpr_consent: consentData.gdpr.consentString, + us_privacy: consentData.uspConsent + }; + const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]); + + expect(ajaxStub.firstCall.args[0].indexOf(`${PROD_ENDPOINT}?`)).to.equal(0); + expect(requestQueryParams).to.deep.equal(expectedParams); + expect(ajaxStub.firstCall.args[3]).to.deep.equal({method: 'GET', withCredentials: true}); + }); + + it('Makes an ajax GET request to the production API endpoint with pixelId and puid query params', () => { invokeGetIdAPI({ + puid: PUBLISHER_USER_ID, + pixelId: PIXEL_ID + }, consentData); + + const expectedParams = { + puid: PUBLISHER_USER_ID, + pixelId: PIXEL_ID, + '1p': '0', + gdpr: '1', + gdpr_consent: consentData.gdpr.consentString, + us_privacy: consentData.uspConsent + }; + const requestQueryParams = parseQS(ajaxStub.firstCall.args[0].split('?')[1]); + + expect(ajaxStub.firstCall.args[0].indexOf(`${PROD_ENDPOINT}?`)).to.equal(0); + expect(requestQueryParams).to.deep.equal(expectedParams); + expect(ajaxStub.firstCall.args[3]).to.deep.equal({method: 'GET', withCredentials: true}); + }); + + it('Makes an ajax GET request to the production API endpoint with pixelId, puid and he query params', () => { + invokeGetIdAPI({ + puid: PUBLISHER_USER_ID, he: HASHED_EMAIL, pixelId: PIXEL_ID }, consentData); const expectedParams = { + puid: PUBLISHER_USER_ID, he: HASHED_EMAIL, pixelId: PIXEL_ID, '1p': '0', @@ -185,6 +278,16 @@ describe('Yahoo ConnectID Submodule', () => { }); describe('decode()', () => { + let userHasOptedOutStub; + beforeEach(() => { + userHasOptedOutStub = sinon.stub(connectIdSubmodule, 'userHasOptedOut'); + userHasOptedOutStub.returns(false); + }); + + afterEach(() => { + userHasOptedOutStub.restore() + }); + const VALID_API_RESPONSES = [{ key: 'connectid', expected: '4567', @@ -205,5 +308,72 @@ describe('Yahoo ConnectID Submodule', () => { expect(connectIdSubmodule.decode(response)).to.be.undefined; }); }); + + it('should return undefined if user has utilised the easy opt-out mechanism', () => { + userHasOptedOutStub.returns(true); + expect(connectIdSubmodule.decode(VALID_API_RESPONSES[0].payload)).to.be.undefined; + }) + }); + + describe('getAjaxFn()', () => { + it('should return a function', () => { + expect(connectIdSubmodule.getAjaxFn()).to.be.a('function'); + }); + }); + + describe('isEUConsentRequired()', () => { + it('should return a function', () => { + expect(connectIdSubmodule.isEUConsentRequired).to.be.a('function'); + }); + + it('should be false if consent data is empty', () => { + expect(connectIdSubmodule.isEUConsentRequired({})).to.be.false; + }); + + it('should be false if consent data.gdpr object is empty', () => { + expect(connectIdSubmodule.isEUConsentRequired({ + gdpr: {} + })).to.be.false; + }); + + it('should return false if consent data.gdpr.applies is false', () => { + expect(connectIdSubmodule.isEUConsentRequired({ + gdpr: { + gdprApplies: false + } + })).to.be.false; + }); + + it('should return true if consent data.gdpr.applies is true', () => { + expect(connectIdSubmodule.isEUConsentRequired({ + gdpr: { + gdprApplies: true + } + })).to.be.true; + }); + }); + + describe('userHasOptedOut()', () => { + afterEach(() => { + localStorage.removeItem('connectIdOptOut'); + }); + + it('should return a function', () => { + expect(connectIdSubmodule.userHasOptedOut).to.be.a('function'); + }); + + it('should return false when local storage key has not been set function', () => { + expect(connectIdSubmodule.userHasOptedOut()).to.be.false; + }); + + it('should return true when local storage key has been set to "1"', () => { + localStorage.setItem('connectIdOptOut', '1'); + expect(connectIdSubmodule.userHasOptedOut()).to.be.true; + }); + + it('should return false when local storage key has not been set to "1"', () => { + localStorage.setItem('connectIdOptOut', 'hello'); + expect(connectIdSubmodule.userHasOptedOut()).to.be.false; + }); }); }); From 08f61b25ba9892c2fe6f8cce3c69589fe7fcaf8f Mon Sep 17 00:00:00 2001 From: shahinrahbariasl <56240400+shahinrahbariasl@users.noreply.github.com> Date: Sat, 29 Oct 2022 07:28:32 -0400 Subject: [PATCH 071/367] feat: increase request size limit [PB-1214] (#9168) feat: increase request size limit [PB-1214] feat: increase request size limit [PB-1214] feat: increase request size limit [PB-1214] feat: increase request size limit [PB-1214] feat: increase request size limit [PB-1214] feat: increase request size limit [PB-1214] feat: increase request size limit [PB-1214] feat: increase request size limit [PB-1214] feat: increase request size limit [PB-1214] Co-authored-by: shahin.rahbariasl --- modules/ixBidAdapter.js | 10 ++- test/spec/modules/ixBidAdapter_spec.js | 100 +++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 4efed90d147..a8ffc4be721 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -38,7 +38,6 @@ const BANNER_TIME_TO_LIVE = 300; const VIDEO_TIME_TO_LIVE = 3600; // 1hr const NATIVE_TIME_TO_LIVE = 3600; // Since native can have video, use ttl same as video const NET_REVENUE = true; -const MAX_REQUEST_SIZE = 8000; const MAX_REQUEST_LIMIT = 4; const OUTSTREAM_MINIMUM_PLAYER_SIZE = [144, 144]; const PRICE_TO_DOLLAR_FACTOR = { @@ -586,6 +585,12 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { let userEids = eidInfo.toSend; const pageUrl = deepAccess(bidderRequest, 'refererInfo.page'); + let MAX_REQUEST_SIZE = 8000; + // Modify request size limit if its FT is enabeld. + if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_32kb_size_limit')) { + MAX_REQUEST_SIZE = 32000 + } + // RTI ids will be included in the bid request if the function getIdentityInfo() is loaded // and if the data for the partner exist if (window.headertag && typeof window.headertag.getIdentityInfo === 'function') { @@ -642,6 +647,9 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { r.ext.ixdiag.err = cachedErrors; } + // Add number of available imps to ixDiag. + r.ext.ixdiag.imps = Object.keys(impressions).length; + // set source.tid to auctionId for outgoing request to Exchange. r.source = { tid: validBidRequests[0].auctionId, diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index a2698fa2cdc..ec749398019 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -1563,6 +1563,13 @@ describe('IndexexchangeAdapter', function () { expect(r.ext.ixdiag.tmax).to.be.undefined }); + it('should set ixdiag.imps to number of impressions', function () { + const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID)[0]; + const r = extractPayload(request); + + expect(r.ext.ixdiag.imps).to.equal(1); + }); + it('should not send information that is not part of openRTB spec v2.5 using ortb2', function () { const ortb2 = { site: { @@ -3388,6 +3395,99 @@ describe('IndexexchangeAdapter', function () { expect(FEATURE_TOGGLES.isFeatureEnabled('test')).to.be.undefined; expect(FEATURE_TOGGLES.featureToggles).to.deep.equal({}); }); + + it('should set request size limit to 32KB when its feature enabled', () => { + sandbox.stub(storage, 'localStorageIsEnabled').returns(true); + serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { + activated: true + }; + FEATURE_TOGGLES.setFeatureToggles(serverResponse); + const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); + bid.bidderRequestId = Array(10000).join('#'); + + expect(spec.isBidRequestValid(bid)).to.be.true; + spec.buildRequests([bid], {}); + const lsData = JSON.parse(storage.getDataFromLocalStorage(LOCAL_STORAGE_FEATURE_TOGGLES_KEY)); + expect(lsData.features.pbjs_use_32kb_size_limit.activated).to.be.true; + }); + + it('6 ad units should generate only 2 requests if 32kb size limit FT is enabled', function () { + sandbox.stub(storage, 'localStorageIsEnabled').returns(true); + serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { + activated: true + }; + serverResponse.body.ext.features.pbjs_enable_post = { + activated: true + }; + FEATURE_TOGGLES.setFeatureToggles(serverResponse); + + const bid1 = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); + bid1.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; + bid1.params.siteId = '121'; + bid1.adUnitCode = 'div-gpt-1' + bid1.transactionId = 'tr1'; + bid1.bidId = '2f6g5s5e'; + + const bid2 = utils.deepClone(bid1); + bid2.transactionId = 'tr2'; + + const bid3 = utils.deepClone(bid1); + bid3.transactionId = 'tr3'; + + const bid4 = utils.deepClone(bid1); + bid4.transactionId = 'tr4'; + + const bid5 = utils.deepClone(bid1); + bid5.transactionId = 'tr5'; + + const bid6 = utils.deepClone(bid1); + bid6.transactionId = 'tr6'; + + const requests = spec.buildRequests([bid1, bid2, bid3, bid4, bid5, bid6], DEFAULT_OPTION); + + expect(requests).to.be.an('array'); + // 32KB size limit causes only 2 requests to get generated. + expect(requests).to.have.lengthOf(2); + for (let request of requests) { + expect(request.method).to.equal('POST'); + } + }); + + it('4 ad units should generate only 1 requests if 32kb size limit FT is enabled', function () { + sandbox.stub(storage, 'localStorageIsEnabled').returns(true); + serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { + activated: true + }; + serverResponse.body.ext.features.pbjs_enable_post = { + activated: true + }; + FEATURE_TOGGLES.setFeatureToggles(serverResponse); + + const bid1 = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); + bid1.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; + bid1.params.siteId = '121'; + bid1.adUnitCode = 'div-gpt-1' + bid1.transactionId = 'tr1'; + bid1.bidId = '2f6g5s5e'; + + const bid2 = utils.deepClone(bid1); + bid2.transactionId = 'tr2'; + + const bid3 = utils.deepClone(bid1); + bid3.transactionId = 'tr3'; + + const bid4 = utils.deepClone(bid1); + bid4.transactionId = 'tr4'; + + const requests = spec.buildRequests([bid1, bid2, bid3, bid4], DEFAULT_OPTION); + + expect(requests).to.be.an('array'); + // 32KB size limit causes only 1 requests to get generated. + expect(requests).to.have.lengthOf(1); + for (let request of requests) { + expect(request.method).to.equal('POST'); + } + }); }); describe('LocalStorage error codes', () => { From 36e6be20f85707fc5c83b9eaac0a9798506166f5 Mon Sep 17 00:00:00 2001 From: velichkin Date: Mon, 31 Oct 2022 10:12:27 +0200 Subject: [PATCH 072/367] Mgid RTD Module : add new RTD module (#9120) * Mgid RTD provider * Mgid RTD provider * Mgid RTD provider. Fix endpoint URL * Mgid RTD provider. Fix gdprApplies * Mgid RTD provider. Fix warnings * Mgid RTD provider. Remove unnecessary script * Mgid RTD provider. Add module to .submodules.json * Mgid RTD provider. Changes to .md doc --- .../gpt/mgidRtdProvider_example.html | 143 +++++++ modules/.submodules.json | 1 + modules/mgidRtdProvider.js | 190 +++++++++ modules/mgidRtdProvider.md | 51 +++ test/spec/modules/mgidRtdProvider_spec.js | 366 ++++++++++++++++++ 5 files changed, 751 insertions(+) create mode 100644 integrationExamples/gpt/mgidRtdProvider_example.html create mode 100644 modules/mgidRtdProvider.js create mode 100644 modules/mgidRtdProvider.md create mode 100644 test/spec/modules/mgidRtdProvider_spec.js diff --git a/integrationExamples/gpt/mgidRtdProvider_example.html b/integrationExamples/gpt/mgidRtdProvider_example.html new file mode 100644 index 00000000000..e3e4f720586 --- /dev/null +++ b/integrationExamples/gpt/mgidRtdProvider_example.html @@ -0,0 +1,143 @@ + + + + + + + + + + +JS Bin + + + +

Basic Prebid.js Example

+
Div-1
+ +
+ +
+ + + diff --git a/modules/.submodules.json b/modules/.submodules.json index e4d09b8c9df..aad778be67b 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -64,6 +64,7 @@ "iasRtdProvider", "jwplayerRtdProvider", "medianetRtdProvider", + "mgidRtdProvider", "oneKeyRtdProvider", "optimeraRtdProvider", "permutiveRtdProvider", diff --git a/modules/mgidRtdProvider.js b/modules/mgidRtdProvider.js new file mode 100644 index 00000000000..f30f14ea528 --- /dev/null +++ b/modules/mgidRtdProvider.js @@ -0,0 +1,190 @@ +import { submodule } from '../src/hook.js'; +import {ajax} from '../src/ajax.js'; +import {deepAccess, logError, logInfo, mergeDeep} from '../src/utils.js'; +import {getStorageManager} from '../src/storageManager.js'; +import {getRefererInfo} from '../src/refererDetection.js'; + +const MODULE_NAME = 'realTimeData'; +const SUBMODULE_NAME = 'mgid'; +const MGID_RTD_API_URL = 'https://servicer.mgid.com/sda'; +const MGUID_LOCAL_STORAGE_KEY = 'mguid'; +const ORTB2_NAME = 'www.mgid.com' + +const GVLID = 358; +/** @type {?Object} */ +export const storage = getStorageManager({ + gvlid: GVLID, + moduleName: SUBMODULE_NAME +}); + +function init(moduleConfig) { + if (!moduleConfig?.params?.clientSiteId) { + logError('Mgid clientSiteId is not set!'); + return false; + } + return true; +} + +function getBidRequestData(reqBidsConfigObj, onDone, moduleConfig, userConsent) { + let mguid; + try { + mguid = storage.getDataFromLocalStorage(MGUID_LOCAL_STORAGE_KEY); + } catch (e) { + logInfo(`Can't get mguid from localstorage`); + } + + const params = [ + { + name: 'gdprApplies', + data: typeof userConsent?.gdpr?.gdprApplies !== 'undefined' ? userConsent?.gdpr?.gdprApplies + '' : undefined, + }, + { + name: 'consentData', + data: userConsent?.gdpr?.consentString, + }, + { + name: 'uspString', + data: userConsent?.usp, + }, + { + name: 'cxurl', + data: encodeURIComponent(getContextUrl()), + }, + { + name: 'muid', + data: mguid, + }, + { + name: 'clientSiteId', + data: moduleConfig?.params?.clientSiteId, + }, + { + name: 'cxlang', + data: deepAccess(reqBidsConfigObj.ortb2Fragments.global, 'site.content.language'), + }, + ]; + + const url = MGID_RTD_API_URL + '?' + params.filter((p) => p.data).map((p) => p.name + '=' + p.data).join('&'); + + let isDone = false; + + ajax(url, { + success: (response, req) => { + if (req.status === 200) { + try { + const data = JSON.parse(response); + const ortb2 = reqBidsConfigObj?.ortb2Fragments?.global || {}; + + mergeDeep(ortb2, getDataForMerge(data)); + + if (data?.muid) { + try { + mguid = storage.setDataInLocalStorage(MGUID_LOCAL_STORAGE_KEY, data.muid); + } catch (e) { + logInfo(`Can't set mguid to localstorage`); + } + } + + onDone(); + isDone = true; + } catch (e) { + onDone(); + isDone = true; + + logError('Unable to parse Mgid RTD data', e); + } + } else { + onDone(); + isDone = true; + + logError('Mgid RTD wrong response status'); + } + }, + error: () => { + onDone(); + isDone = true; + + logError('Unable to get Mgid RTD data'); + } + }, + null, { + method: 'GET', + withCredentials: false, + }); + + setTimeout(function () { + if (!isDone) { + onDone(); + logInfo('Mgid RTD timeout'); + isDone = true; + } + }, moduleConfig.params.timeout || 1000); +} + +function getContextUrl() { + const refererInfo = getRefererInfo(); + + let resultUrl = refererInfo.canonicalUrl || refererInfo.topmostLocation; + + const metaElements = document.getElementsByTagName('meta'); + for (let i = 0; i < metaElements.length; i++) { + if (metaElements[i].getAttribute('property') === 'og:url') { + resultUrl = metaElements[i].content; + } + } + + return resultUrl; +} + +function getDataForMerge(responseData) { + let siteData = { + name: ORTB2_NAME + }; + let userData = { + name: ORTB2_NAME + }; + + if (responseData.siteSegments) { + siteData.segment = responseData.siteSegments.map((segmentId) => ({ id: segmentId })); + } + if (responseData.siteSegtax) { + siteData.ext = { + segtax: responseData.siteSegtax + } + } + + if (responseData.userSegments) { + userData.segment = responseData.userSegments.map((segmentId) => ({ id: segmentId })); + } + if (responseData.userSegtax) { + userData.ext = { + segtax: responseData.userSegtax + } + } + + let result = {}; + if (siteData.segment || siteData.ext) { + result.site = { + content: { + data: [siteData], + } + } + } + + if (userData.segment || userData.ext) { + result.user = { + data: [userData], + } + } + + return result; +} + +/** @type {RtdSubmodule} */ +export const mgidSubmodule = { + name: SUBMODULE_NAME, + init: init, + getBidRequestData: getBidRequestData, +}; + +submodule(MODULE_NAME, mgidSubmodule); diff --git a/modules/mgidRtdProvider.md b/modules/mgidRtdProvider.md new file mode 100644 index 00000000000..58d4564e14e --- /dev/null +++ b/modules/mgidRtdProvider.md @@ -0,0 +1,51 @@ +# Overview + +``` +Module Name: Mgid RTD Provider +Module Type: RTD Provider +Maintainer: prebid@mgid.com +``` + +# Description + +Mgid RTD module allows you to enrich bid data with contextual and audience signals, based on IAB taxonomies. + +## Configuration + +This module is configured as part of the `realTimeData.dataProviders` object. + +{: .table .table-bordered .table-striped } +| Name | Scope | Description | Example | Type | +|------------|----------|----------------------------------------|---------------|----------| +| `name ` | required | Real time data module name | `'mgid'` | `string` | +| `params` | required | | | `Object` | +| `params.clientSiteId` | required | The client site id provided by Mgid. | `'123456'` | `string` | +| `params.timeout` | optional | Maximum amount of milliseconds allowed for module to finish working | `1000` | `number` | + +#### Example + +```javascript +pbjs.setConfig({ + realTimeData: { + dataProviders: [{ + name: 'mgid', + params: { + clientSiteId: '123456' + } + }] + } +}); +``` + +## Integration +To install the module, follow these instructions: + +#### Step 1: Prepare the base Prebid file + +- Option 1: Use Prebid [Download](/download.html) page to build the prebid package. Ensure that you do check *Mgid Realtime Module* module + +- Option 2: From the command line, run `gulp build --modules=mgidRtdProvider,...` + +#### Step 2: Set configuration + +Enable Mgid Real Time Module using `pbjs.setConfig`. Example is provided in Configuration section. diff --git a/test/spec/modules/mgidRtdProvider_spec.js b/test/spec/modules/mgidRtdProvider_spec.js new file mode 100644 index 00000000000..4f70b4d8b7c --- /dev/null +++ b/test/spec/modules/mgidRtdProvider_spec.js @@ -0,0 +1,366 @@ +import { mgidSubmodule, storage } from '../../../modules/mgidRtdProvider.js'; +import {expect} from 'chai'; +import * as refererDetection from '../../../src/refererDetection'; + +describe('Mgid RTD submodule', () => { + let server; + let clock; + let getRefererInfoStub; + let getDataFromLocalStorageStub; + + beforeEach(() => { + server = sinon.fakeServer.create(); + + clock = sinon.useFakeTimers(); + + getRefererInfoStub = sinon.stub(refererDetection, 'getRefererInfo'); + getRefererInfoStub.returns({ + canonicalUrl: 'https://www.test.com/abc' + }); + + getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage').returns('qwerty654321'); + }); + + afterEach(() => { + server.restore(); + clock.restore(); + getRefererInfoStub.restore(); + getDataFromLocalStorageStub.restore(); + }); + + it('init is successfull, when clientSiteId is defined', () => { + expect(mgidSubmodule.init({params: {clientSiteId: 123}})).to.be.true; + }); + + it('init is unsuccessfull, when clientSiteId is not defined', () => { + expect(mgidSubmodule.init({})).to.be.false; + }); + + it('getBidRequestData send all params to our endpoint and succesfully modifies ortb2', () => { + const responseObj = { + userSegments: ['100', '200'], + userSegtax: 5, + siteSegments: ['300', '400'], + siteSegtax: 7, + muid: 'qwerty654321', + }; + + let reqBidsConfigObj = { + ortb2Fragments: { + global: { + site: { + content: { + language: 'en', + } + } + }, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + { + gdpr: { + gdprApplies: true, + consentString: 'testConsent', + }, + usp: '1YYY', + } + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + JSON.stringify(responseObj) + ); + + const requestUrl = new URL(server.requests[0].url); + expect(requestUrl.host).to.be.eq('servicer.mgid.com'); + expect(requestUrl.searchParams.get('gdprApplies')).to.be.eq('true'); + expect(requestUrl.searchParams.get('consentData')).to.be.eq('testConsent'); + expect(requestUrl.searchParams.get('uspString')).to.be.eq('1YYY'); + expect(requestUrl.searchParams.get('muid')).to.be.eq('qwerty654321'); + expect(requestUrl.searchParams.get('clientSiteId')).to.be.eq('123'); + expect(requestUrl.searchParams.get('cxurl')).to.be.eq('https://www.test.com/abc'); + expect(requestUrl.searchParams.get('cxlang')).to.be.eq('en'); + + assert.deepInclude( + reqBidsConfigObj.ortb2Fragments.global, + { + site: { + content: { + language: 'en', + data: [ + { + name: 'www.mgid.com', + ext: { + segtax: 7 + }, + segment: [ + { id: '300' }, + { id: '400' }, + ] + } + ], + } + }, + user: { + data: [ + { + name: 'www.mgid.com', + ext: { + segtax: 5 + }, + segment: [ + { id: '100' }, + { id: '200' }, + ] + } + ], + }, + }); + }); + + it('getBidRequestData doesn\'t send params (consent and cxlang), if we haven\'t received them', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + JSON.stringify({}) + ); + + const requestUrl = new URL(server.requests[0].url); + expect(requestUrl.host).to.be.eq('servicer.mgid.com'); + expect(requestUrl.searchParams.get('gdprApplies')).to.be.null; + expect(requestUrl.searchParams.get('consentData')).to.be.null; + expect(requestUrl.searchParams.get('uspString')).to.be.null; + expect(requestUrl.searchParams.get('muid')).to.be.eq('qwerty654321'); + expect(requestUrl.searchParams.get('clientSiteId')).to.be.eq('123'); + expect(requestUrl.searchParams.get('cxurl')).to.be.eq('https://www.test.com/abc'); + expect(requestUrl.searchParams.get('cxlang')).to.be.null; + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData send gdprApplies event if it is false', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + { + gdpr: { + gdprApplies: false, + consentString: 'testConsent', + }, + usp: '1YYY', + } + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + JSON.stringify({}) + ); + + const requestUrl = new URL(server.requests[0].url); + expect(requestUrl.host).to.be.eq('servicer.mgid.com'); + expect(requestUrl.searchParams.get('gdprApplies')).to.be.eq('false'); + expect(requestUrl.searchParams.get('consentData')).to.be.eq('testConsent'); + expect(requestUrl.searchParams.get('uspString')).to.be.eq('1YYY'); + expect(requestUrl.searchParams.get('muid')).to.be.eq('qwerty654321'); + expect(requestUrl.searchParams.get('clientSiteId')).to.be.eq('123'); + expect(requestUrl.searchParams.get('cxurl')).to.be.eq('https://www.test.com/abc'); + expect(requestUrl.searchParams.get('cxlang')).to.be.null; + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData use og:url for cxurl, if it is available', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + let metaStub = sinon.stub(document, 'getElementsByTagName').returns([ + { getAttribute: () => 'og:test', content: 'fake' }, + { getAttribute: () => 'og:url', content: 'https://realOgUrl.com/' } + ]); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + JSON.stringify({}) + ); + + const requestUrl = new URL(server.requests[0].url); + expect(requestUrl.searchParams.get('cxurl')).to.be.eq('https://realOgUrl.com/'); + expect(onDone.calledOnce).to.be.true; + + metaStub.restore(); + }); + + it('getBidRequestData use topMostLocation for cxurl, if nothing else left', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + getRefererInfoStub.returns({ + topmostLocation: 'https://www.test.com/topMost' + }); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + JSON.stringify({}) + ); + + const requestUrl = new URL(server.requests[0].url); + expect(requestUrl.searchParams.get('cxurl')).to.be.eq('https://www.test.com/topMost'); + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData won\'t modify ortb2 if response is broken', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + '{' + ); + + assert.deepEqual(reqBidsConfigObj.ortb2Fragments.global, {}); + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData won\'t modify ortb2 if response status is not 200', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 204, + {'Content-Type': 'application/json'}, + '{}' + ); + + assert.deepEqual(reqBidsConfigObj.ortb2Fragments.global, {}); + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData won\'t modify ortb2 if response results in error', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123}}, + {} + ); + + server.requests[0].respond( + 500, + {'Content-Type': 'application/json'}, + '{}' + ); + + assert.deepEqual(reqBidsConfigObj.ortb2Fragments.global, {}); + expect(onDone.calledOnce).to.be.true; + }); + + it('getBidRequestData won\'t modify ortb2 if response time hits timeout', () => { + let reqBidsConfigObj = { + ortb2Fragments: { + global: {}, + } + }; + + let onDone = sinon.stub(); + + mgidSubmodule.getBidRequestData( + reqBidsConfigObj, + onDone, + {params: {clientSiteId: 123, timeout: 500}}, + {} + ); + + clock.tick(510); + + assert.deepEqual(reqBidsConfigObj.ortb2Fragments.global, {}); + expect(onDone.calledOnce).to.be.true; + }); +}); From bb791e0653f41845c5fcb32576fd3ec3154b4d20 Mon Sep 17 00:00:00 2001 From: Love Sharma Date: Mon, 31 Oct 2022 08:50:01 -0400 Subject: [PATCH 073/367] added support for media type specific siteIds (#9173) Co-authored-by: Love Sharma --- modules/ixBidAdapter.js | 27 +++++-- test/spec/modules/ixBidAdapter_spec.js | 103 +++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 6 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index a8ffc4be721..27e6d0aee02 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -158,7 +158,7 @@ const MEDIA_TYPES = { * @return {object} A impression object that will be sent to ad server. */ function bidToBannerImp(bid) { - const imp = bidToImp(bid); + const imp = bidToImp(bid, BANNER); imp.banner = {}; const impSize = deepAccess(bid, 'params.size'); if (impSize) { @@ -180,7 +180,7 @@ function bidToBannerImp(bid) { * @return {object} A impression object that will be sent to ad server. */ function bidToVideoImp(bid) { - const imp = bidToImp(bid); + const imp = bidToImp(bid, VIDEO); const videoAdUnitRef = deepAccess(bid, 'mediaTypes.video'); const videoParamRef = deepAccess(bid, 'params.video'); const videoParamErrors = checkVideoParams(videoAdUnitRef, videoParamRef); @@ -248,7 +248,7 @@ function bidToVideoImp(bid) { * @return {object} A impression object that will be sent to ad server. */ function bidToNativeImp(bid) { - const imp = bidToImp(bid); + const imp = bidToImp(bid, NATIVE); const request = bid.nativeOrtbRequest request.eventtrackers = [{ @@ -275,13 +275,28 @@ function bidToNativeImp(bid) { * @param {object} bid PBJS bid object * @returns {object} IX impression object */ -function bidToImp(bid) { +function bidToImp(bid, mediaType) { const imp = {}; imp.id = bid.bidId; imp.ext = {}; - imp.ext.siteID = bid.params.siteId.toString(); + + if (deepAccess(bid, `params.${mediaType}.siteId`) && !isNaN(Number(bid.params[mediaType].siteId))) { + switch (mediaType) { + case BANNER: + imp.ext.siteID = bid.params.banner.siteId.toString(); + break; + case VIDEO: + imp.ext.siteID = bid.params.video.siteId.toString(); + break; + case NATIVE: + imp.ext.siteID = bid.params.native.siteId.toString(); + break; + } + } else { + imp.ext.siteID = bid.params.siteId.toString(); + } // populate imp level sid if (bid.params.hasOwnProperty('id') && (typeof bid.params.id === 'string' || typeof bid.params.id === 'number')) { @@ -1426,7 +1441,7 @@ export const spec = { // Step 1: Create impresssions from IX params validBidRequests.forEach((validBidRequest) => { - const adUnitMediaTypes = Object.keys(deepAccess(validBidRequest, 'mediaTypes', {})) + const adUnitMediaTypes = Object.keys(deepAccess(validBidRequest, 'mediaTypes', {})); for (const type in adUnitMediaTypes) { switch (adUnitMediaTypes[type]) { diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index ec749398019..0de300e4a32 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -402,6 +402,78 @@ describe('IndexexchangeAdapter', function () { } ]; + const DEFAULT_MULTIFORMAT_VALID_BID = [ + { + bidder: 'ix', + params: { + tagId: '123', + siteId: '456', + video: { + siteId: '1111' + }, + banner: { + siteId: '2222' + }, + native: { + siteId: '3333' + }, + size: [300, 250] + }, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [[300, 250]], + skippable: false, + mimes: [ + 'video/mp4', + 'video/webm' + ], + minduration: 0, + maxduration: 60, + protocols: [1] + }, + banner: { + sizes: [[300, 250], [300, 600]] + }, + native: { + icon: { + required: false + }, + title: { + len: 25, + required: true + }, + body: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + } + } + }, + ortb2Imp: { + ext: { + tid: '173f49a8-7549-4218-a23c-e7ba59b47230', + data: { + pbadslot: 'div-gpt-ad-1460505748562-0' + } + } + }, + nativeOrtbRequest: { + assets: [{id: 0, required: 0, img: {type: 1}}, {id: 1, required: 1, title: {len: 140}}, {id: 2, required: 1, data: {type: 2}}, {id: 3, required: 1, img: {type: 3}}, {id: 4, required: false, video: {mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6]}}] + }, + adUnitCode: 'div-gpt-ad-1460505748562-0', + transactionId: '273f49a8-7549-4218-a23c-e7ba59b47230', + bidId: '1a2b3c4e', + bidderRequestId: '11a22b33c44e', + auctionId: '1aa2bb3cc4de', + schain: SAMPLE_SCHAIN + } + ]; + const DEFAULT_NATIVE_VALID_BID = [ { bidder: 'ix', @@ -2685,6 +2757,37 @@ describe('IndexexchangeAdapter', function () { expect(diagObj.adunitcode).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].adUnitCode) }); }); + + describe('siteId overrides', function () { + it('should use siteId override', function () { + const validBids = DEFAULT_MULTIFORMAT_VALID_BID; + const request = spec.buildRequests(validBids, {}); + const bannerImps = request[0].data.imp[0]; + const videoImps = request[1].data.imp[0]; + const nativeImps = request[2].data.imp[0]; + expect(videoImps.ext.siteID).to.equal('1111'); + bannerImps.banner.format.map(({ ext }) => { + expect(ext.siteID).to.equal('2222'); + }); + expect(nativeImps.ext.siteID).to.equal('3333'); + }); + + it('should use default siteId if overrides are not provided', function () { + const validBids = DEFAULT_MULTIFORMAT_VALID_BID; + delete validBids[0].params.banner; + delete validBids[0].params.video; + delete validBids[0].params.native; + const request = spec.buildRequests(validBids, {}); + const bannerImps = request[0].data.imp[0]; + const videoImps = request[1].data.imp[0]; + const nativeImps = request[2].data.imp[0]; + expect(videoImps.ext.siteID).to.equal('456'); + bannerImps.banner.format.map(({ ext }) => { + expect(ext.siteID).to.equal('456'); + }); + expect(nativeImps.ext.siteID).to.equal('456'); + }); + }); }); describe('interpretResponse', function () { From d08baa3f4a5cfdb62fc4386695c682203589daf4 Mon Sep 17 00:00:00 2001 From: Fatih Kaya Date: Mon, 31 Oct 2022 17:45:31 +0300 Subject: [PATCH 074/367] Admatic Bid Adapter: initial adapter release (#9133) * Admatic Bidder Adaptor * Update admaticBidAdapter.md * Update admaticBidAdapter.md --- modules/admaticBidAdapter.js | 147 ++++++++++++++++++++ modules/admaticBidAdapter.md | 48 +++++++ src/adloader.js | 1 + test/spec/modules/admaticBidAdapter_spec.js | 46 ++++++ 4 files changed, 242 insertions(+) create mode 100644 modules/admaticBidAdapter.js create mode 100644 modules/admaticBidAdapter.md create mode 100644 test/spec/modules/admaticBidAdapter_spec.js diff --git a/modules/admaticBidAdapter.js b/modules/admaticBidAdapter.js new file mode 100644 index 00000000000..039f27e5de0 --- /dev/null +++ b/modules/admaticBidAdapter.js @@ -0,0 +1,147 @@ +import { getValue, logError, deepAccess, getBidIdParameter, isArray } from '../src/utils.js'; +import { loadExternalScript } from '../src/adloader.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; + +const ENDPOINT_URL = 'https://layer.serve.admatic.com.tr/pb'; +const SYNC_URL = 'https://cdn.serve.admatic.com.tr/showad/sync.js'; +const BIDDER_CODE = 'admatic'; + +export const spec = { + code: 'admatic', + supportedMediaTypes: ['video', '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) { + let isValid = false; + if (typeof bid.params !== 'undefined') { + let isValidNetworkId = _validateId(getValue(bid.params, 'networkId')); + isValid = isValidNetworkId;// && isValidTypeId; + } + + if (!isValid) { + logError('AdMatic networkId parameters are required. Bid aborted.'); + } + return isValid; + }, + /** + * 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 bids = validBidRequests.map(buildRequestObject); + const networkId = getValue(validBidRequests[0].params, 'networkId'); + const currency = getValue(validBidRequests[0].params, 'currency') || 'TRY'; + + setTimeout(() => { + loadExternalScript(SYNC_URL, BIDDER_CODE); + }, bidderRequest.timeout); + + const payload = { + 'user': { + 'ua': navigator.userAgent + }, + 'blacklist': [], + 'site': { + 'page': location.href, + 'ref': location.origin, + 'publisher': { + 'name': location.hostname, + 'publisherId': networkId + } + }, + imp: bids, + ext: { + 'cur': currency, + 'type': 'admatic' + } + }; + + const payloadString = JSON.stringify(payload); + return { + method: 'POST', + url: ENDPOINT_URL, + data: payloadString, + options: { + contentType: 'application/json' + } + }; + }, + /** + * 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: (response, request) => { + const body = response.body || response; + const bidResponses = []; + if (body.data.length > 0) { + body.data.forEach(function (bid) { + const resbid = { + requestId: bid.id, + cpm: bid.price, + width: bid.width, + height: bid.height, + currency: body.cur, + netRevenue: true, + ad: bid.party_tag, + creativeId: bid.creative_id, + meta: { + advertiserDomains: bid && bid.adomain ? bid.adomain : [] + }, + ttl: 360, + bidder: 'admatic', + timeToRespond: 1, + requestTimestamp: 1 + }; + bidResponses.push(resbid); + }); + }; + return bidResponses; + } +}; + +function buildRequestObject(bid) { + const reqObj = {}; + reqObj.size = getSizes(bid); + reqObj.id = getBidIdParameter('bidId', bid); + reqObj.floor = getValue(bid.params, 'floor') || 0.01; + return reqObj; +} + +function getSizes(bid) { + return concatSizes(bid); +} + +function concatSizes(bid) { + let playerSize = deepAccess(bid, 'mediaTypes.video.playerSize'); + let videoSizes = deepAccess(bid, 'mediaTypes.video.sizes'); + let bannerSizes = deepAccess(bid, 'mediaTypes.banner.sizes'); + + if (isArray(bannerSizes) || isArray(playerSize) || isArray(videoSizes)) { + let mediaTypesSizes = [bannerSizes, videoSizes, playerSize]; + return mediaTypesSizes + .reduce(function(acc, currSize) { + if (isArray(currSize)) { + if (isArray(currSize[0])) { + currSize.forEach(function (childSize) { + acc.push({ w: childSize[0], h: childSize[1] }); + }) + } + } + return acc; + }, []); + } +} + +function _validateId(id) { + return (parseInt(id) > 0); +} + +registerBidder(spec); diff --git a/modules/admaticBidAdapter.md b/modules/admaticBidAdapter.md new file mode 100644 index 00000000000..de84998d0af --- /dev/null +++ b/modules/admaticBidAdapter.md @@ -0,0 +1,48 @@ +# Overview + +**Module Name**: Admatic Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: prebid@admatic.com.tr + +# Description + +Use `admatic` as bidder. + +`networkId` is required and must be integer. + +## AdUnits configuration example +``` + var adUnits = [{ + code: 'your-slot_1-div', //use exactly the same code as your slot div id. + sizes: [[300, 250]], + bids: [{ + bidder: 'admatic', + params: { + networkId: 12345, + floor: 0.5 + } + }] + },{ + code: 'your-slot_2-div', //use exactly the same code as your slot div id. + sizes: [[600, 800]], + bids: [{ + bidder: 'admatic', + params: { + networkId: 12345, + floor: 0.5 + } + }] + }]; +``` + +## UserSync example + +``` +pbjs.setConfig({ + userSync: { + iframeEnabled: true, + syncEnabled: true, + syncDelay: 1 + } +}); +``` diff --git a/src/adloader.js b/src/adloader.js index 64408683e9f..330b52b3ed5 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -6,6 +6,7 @@ const _requestCache = new WeakMap(); const _approvedLoadExternalJSList = [ 'debugging', 'adloox', + 'admatic', 'criteo', 'outstream', 'adagio', diff --git a/test/spec/modules/admaticBidAdapter_spec.js b/test/spec/modules/admaticBidAdapter_spec.js new file mode 100644 index 00000000000..c7d391cfaca --- /dev/null +++ b/test/spec/modules/admaticBidAdapter_spec.js @@ -0,0 +1,46 @@ +import {expect} from 'chai'; +import {spec, storage} from 'modules/admaticBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; +import {getStorageManager} from 'src/storageManager'; + +const ENDPOINT = 'https://layer.serve.admatic.com.tr/v1'; + +describe('admaticBidAdapter', () => { + const adapter = newBidder(spec); + + describe('inherited functions', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function() { + let bid = { + 'bidder': 'admatic', + 'params': { + 'networkId': 10433394 + }, + 'adUnitCode': 'adunit-code', + '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 false when required params are not passed', function() { + let bid = Object.assign({}, bid); + delete bid.params; + + bid.params = { + 'networkId': 0 + }; + + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); +}); From 1f29ef517307c2e32cec165a0138ce42e9115ed9 Mon Sep 17 00:00:00 2001 From: southern-growthcode <79725079+southern-growthcode@users.noreply.github.com> Date: Mon, 31 Oct 2022 10:46:18 -0400 Subject: [PATCH 075/367] GrowthCode ID Module: update the user module to expire old user information (#9170) * Initial check-in ofthe GrowthCode Adaptor * Growthcode ID System * Working on test module * Tests for the growthCode Id System * Clean up tests for GrowthCode * Fixed the default values for shareID * Remove Test HTML Page * Remove file * Updated MD file to switch client ID to partner ID * Will now expire LocalStore data * Remove Test Files --- modules/growthCodeIdSystem.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/growthCodeIdSystem.js b/modules/growthCodeIdSystem.js index 68fe2c7e925..edd7cd33012 100644 --- a/modules/growthCodeIdSystem.js +++ b/modules/growthCodeIdSystem.js @@ -10,7 +10,7 @@ import {ajax} from '../src/ajax.js'; import { submodule } from '../src/hook.js' import { getStorageManager } from '../src/storageManager.js'; -const GCID_EXPIRY = 45; +const GCID_EXPIRY = 7; const MODULE_NAME = 'growthCodeId'; const GC_DATA_KEY = '_gc_data'; const ENDPOINT_URL = 'https://p2.gcprivacy.com/v1/pb?' @@ -24,11 +24,15 @@ export const storage = getStorageManager({ gvlid: undefined, moduleName: MODULE_ */ export function readData(key) { try { + let payload + if (storage.cookiesAreEnabled()) { + payload = tryParse(storage.getCookie(key)) + } if (storage.hasLocalStorage()) { - return storage.getDataFromLocalStorage(key); + payload = tryParse(storage.getDataFromLocalStorage(key)) } - if (storage.cookiesAreEnabled()) { - return storage.getCookie(key); + if ((payload.expire_at !== undefined) && (payload.expire_at > (Date.now() / 1000))) { + return payload } } catch (error) { logError(error); @@ -122,7 +126,7 @@ export const growthCodeIdSubmodule = { } const resp = function(callback) { - let gcData = tryParse(readData(GC_DATA_KEY)); + let gcData = readData(GC_DATA_KEY); if (gcData) { callback(gcData); } else { From a91e0579dc12079df93c31891f96e2cb2ae97f99 Mon Sep 17 00:00:00 2001 From: Jason Lydon <95770514+ftxmoJason@users.noreply.github.com> Date: Mon, 31 Oct 2022 15:11:40 -0400 Subject: [PATCH 076/367] FtrackId: correcting the eid object schema (#9174) * JDB-564: fixing the schema returned via pbjs.getUserIdsAsEids() * JDB-564: WHY U NO LINT HAPPY? * JDB: EIDS logic cleanup Co-authored-by: Jason Lydon --- modules/userId/eids.js | 13 ++---- test/spec/modules/eids_spec.js | 17 ++++--- test/spec/modules/ftrackIdSystem_spec.js | 56 ++++++++++++++---------- 3 files changed, 47 insertions(+), 39 deletions(-) diff --git a/modules/userId/eids.js b/modules/userId/eids.js index e0a076c313f..bae5071e4b2 100644 --- a/modules/userId/eids.js +++ b/modules/userId/eids.js @@ -88,13 +88,13 @@ export const USER_IDS_CONFIG = { atype: 1, getValue: function(data) { let value = ''; - if (data.DeviceID) { - value = data.DeviceID.join(','); + if (data && data.ext && data.ext.DeviceID) { + value = data.ext.DeviceID; } return value; }, getUidExt: function(data) { - return 'DeviceID'; + return data && data.ext; } }, @@ -418,13 +418,6 @@ export function createEidsArray(bidRequestUserId) { if (bidRequestUserId.hasOwnProperty(subModuleKey)) { if (subModuleKey === 'pubProvidedId') { eids = eids.concat(bidRequestUserId['pubProvidedId']); - } else if (subModuleKey === 'ftrackId') { - // Schema based on the return value of ftrack decode() method - eids.push({ - atype: 1, - ext: bidRequestUserId.ftrackId.ext, - id: bidRequestUserId.ftrackId.uid - }); } else if (Array.isArray(bidRequestUserId[subModuleKey])) { bidRequestUserId[subModuleKey].forEach((config, index, arr) => { const eid = createEidObject(config, subModuleKey); diff --git a/test/spec/modules/eids_spec.js b/test/spec/modules/eids_spec.js index ba9210dcb71..78c8f2b3148 100644 --- a/test/spec/modules/eids_spec.js +++ b/test/spec/modules/eids_spec.js @@ -461,13 +461,16 @@ describe('eids array generation for known sub-modules', function() { ipsum: '' } })).to.deep.equal([{ - atype: 1, - id: 'test-device-id', - ext: { - DeviceID: 'test-device-id', - SingleDeviceID: 'test-single-device-id', - HHID: 'test-household-id' - } + source: 'flashtalking.com', + uids: [{ + atype: 1, + id: 'test-device-id', + ext: { + DeviceID: 'test-device-id', + SingleDeviceID: 'test-single-device-id', + HHID: 'test-household-id' + } + }] }]); }); }); diff --git a/test/spec/modules/ftrackIdSystem_spec.js b/test/spec/modules/ftrackIdSystem_spec.js index 79a11845a0f..ecd610a12fb 100644 --- a/test/spec/modules/ftrackIdSystem_spec.js +++ b/test/spec/modules/ftrackIdSystem_spec.js @@ -450,13 +450,16 @@ describe('FTRACK ID System', () => { }); expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ - id: 'device_test_id', - atype: 1, - ext: { - HHID: 'household_test_id', - DeviceID: 'device_test_id', - SingleDeviceID: 'single_device_test_id' - } + source: 'flashtalking.com', + uids: [{ + id: 'device_test_id', + atype: 1, + ext: { + HHID: 'household_test_id', + DeviceID: 'device_test_id', + SingleDeviceID: 'single_device_test_id' + } + }] }]); }); @@ -481,11 +484,14 @@ describe('FTRACK ID System', () => { }); expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ - id: 'device_test_id', - atype: 1, - ext: { - DeviceID: 'device_test_id' - } + source: 'flashtalking.com', + uids: [{ + id: 'device_test_id', + atype: 1, + ext: { + DeviceID: 'device_test_id' + } + }] }]); }); @@ -509,11 +515,14 @@ describe('FTRACK ID System', () => { }); expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ - id: '', - atype: 1, - ext: { - HHID: 'household_test_id' - } + source: 'flashtalking.com', + uids: [{ + id: '', + atype: 1, + ext: { + HHID: 'household_test_id' + } + }] }]); }); @@ -537,11 +546,14 @@ describe('FTRACK ID System', () => { }); expect(getGlobal().getUserIdsAsEids()).to.deep.equal([{ - id: '', - atype: 1, - ext: { - SingleDeviceID: 'single_device_test_id' - } + source: 'flashtalking.com', + uids: [{ + id: '', + atype: 1, + ext: { + SingleDeviceID: 'single_device_test_id' + } + }] }]); }); }); From d71173ad49f204277769d6b746aa272ab715244b Mon Sep 17 00:00:00 2001 From: pm-azhar-mulla <75726247+pm-azhar-mulla@users.noreply.github.com> Date: Tue, 1 Nov 2022 17:02:27 +0530 Subject: [PATCH 077/367] removed sizes constraint on native assets (#9179) Co-authored-by: pm-azhar-mulla --- modules/pubmaticBidAdapter.js | 50 +++++++++++++++-------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 02198042474..9e2d2bc55f8 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -392,37 +392,29 @@ function _createNativeRequest(params) { } break; case NATIVE_ASSETS.IMAGE.KEY: - if (params[key].sizes && params[key].sizes.length > 0) { - assetObj = { - id: NATIVE_ASSETS.IMAGE.ID, - required: params[key].required ? 1 : 0, - img: { - type: NATIVE_ASSET_IMAGE_TYPE.IMAGE, - w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : UNDEFINED), - h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : UNDEFINED), - wmin: params[key].wmin || params[key].minimumWidth || (params[key].minsizes ? params[key].minsizes[0] : UNDEFINED), - hmin: params[key].hmin || params[key].minimumHeight || (params[key].minsizes ? params[key].minsizes[1] : UNDEFINED), - mimes: params[key].mimes, - ext: params[key].ext, - } - }; - } else { - logWarn(LOG_WARN_PREFIX + 'Error: Image sizes is required for native ad: ' + JSON.stringify(params)); - } + assetObj = { + id: NATIVE_ASSETS.IMAGE.ID, + required: params[key].required ? 1 : 0, + img: { + type: NATIVE_ASSET_IMAGE_TYPE.IMAGE, + w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : UNDEFINED), + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : UNDEFINED), + wmin: params[key].wmin || params[key].minimumWidth || (params[key].minsizes ? params[key].minsizes[0] : UNDEFINED), + hmin: params[key].hmin || params[key].minimumHeight || (params[key].minsizes ? params[key].minsizes[1] : UNDEFINED), + mimes: params[key].mimes, + ext: params[key].ext, + } + }; break; case NATIVE_ASSETS.ICON.KEY: - if (params[key].sizes && params[key].sizes.length > 0) { - assetObj = { - id: NATIVE_ASSETS.ICON.ID, - required: params[key].required ? 1 : 0, - img: { - type: NATIVE_ASSET_IMAGE_TYPE.ICON, - w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : UNDEFINED), - h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : UNDEFINED), - } - }; - } else { - logWarn(LOG_WARN_PREFIX + 'Error: Icon sizes is required for native ad: ' + JSON.stringify(params)); + assetObj = { + id: NATIVE_ASSETS.ICON.ID, + required: params[key].required ? 1 : 0, + img: { + type: NATIVE_ASSET_IMAGE_TYPE.ICON, + w: params[key].w || params[key].width || (params[key].sizes ? params[key].sizes[0] : UNDEFINED), + h: params[key].h || params[key].height || (params[key].sizes ? params[key].sizes[1] : UNDEFINED), + } }; break; case NATIVE_ASSETS.VIDEO.KEY: From bb5ca05a8934d504ab06ba4c37078a8689a2a5f7 Mon Sep 17 00:00:00 2001 From: nllerandi3lift <75995508+nllerandi3lift@users.noreply.github.com> Date: Tue, 1 Nov 2022 08:22:20 -0400 Subject: [PATCH 078/367] Triplelift Bid Adapter: prioritize topmostLocation (#9178) * prioritize topmostlocation * adds test for topmostlocation / referrer * cleanup * delete param after test --- modules/tripleliftBidAdapter.js | 2 +- test/spec/modules/tripleliftBidAdapter_spec.js | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/modules/tripleliftBidAdapter.js b/modules/tripleliftBidAdapter.js index 7f6ec90c7b9..3fdabcfa6d2 100644 --- a/modules/tripleliftBidAdapter.js +++ b/modules/tripleliftBidAdapter.js @@ -29,7 +29,7 @@ export const tripleliftAdapterSpec = { tlCall = tryAppendQueryString(tlCall, 'v', '$prebid.version$'); if (bidderRequest && bidderRequest.refererInfo) { - let referrer = bidderRequest.refererInfo.page; + let referrer = bidderRequest?.refererInfo?.topmostLocation || bidderRequest?.refererInfo?.page; tlCall = tryAppendQueryString(tlCall, 'referrer', referrer); } diff --git a/test/spec/modules/tripleliftBidAdapter_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js index e485ae3998f..4cab8be7e09 100644 --- a/test/spec/modules/tripleliftBidAdapter_spec.js +++ b/test/spec/modules/tripleliftBidAdapter_spec.js @@ -979,6 +979,20 @@ describe('triplelift adapter', function () { expect(url).to.match(new RegExp('(?:' + prebid.version + ')')) expect(url).to.match(/(?:referrer)/); }); + it('should prioritize topmostLocation for referrer', function () { + bidderRequest.refererInfo.topmostLocation = 'https://topmostlocation.com?foo=bar' + const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); + const url = request.url; + expect(url).to.match(/(\?|&)referrer=https%3A%2F%2Ftopmostlocation.com%3Ffoo%3Dbar/); + delete bidderRequest.refererInfo.topmostLocation + }); + it('should fall back to page for referrer if topmostLocation is unavailable', function () { + bidderRequest.refererInfo.topmostLocation = null + const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); + const url = request.url; + expect(url).to.match(/(\?|&)referrer=https%3A%2F%2Fexamplereferer.com/); + delete bidderRequest.refererInfo.topmostLocation + }); it('should return us_privacy param when CCPA info is available', function() { bidderRequest.uspConsent = '1YYY'; const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); From b3e7525b7f233aaa5b77f3668833ea12c92602c4 Mon Sep 17 00:00:00 2001 From: Nick Jacob Date: Tue, 1 Nov 2022 12:26:58 -0400 Subject: [PATCH 079/367] Adding gvlid for amx bid adapter (#9183) --- modules/amxBidAdapter.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/amxBidAdapter.js b/modules/amxBidAdapter.js index d1bd2edeee4..c7bc99b6aa6 100644 --- a/modules/amxBidAdapter.js +++ b/modules/amxBidAdapter.js @@ -207,6 +207,7 @@ const isTrue = (boolValue) => export const spec = { code: BIDDER_CODE, + gvlid: 737, supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid(bid) { From de98cceb7198abbf040d3a777a705e95770fe3d1 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Wed, 2 Nov 2022 06:00:12 -0700 Subject: [PATCH 080/367] Prebid core: fix exception in rejection logic for bids that have invalid requestId (#9175) --- src/auction.js | 2 +- test/spec/auctionmanager_spec.js | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/auction.js b/src/auction.js index 469cb2adcd1..09fb275afdb 100644 --- a/src/auction.js +++ b/src/auction.js @@ -475,7 +475,7 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM return handleBidResponse(adUnitCode, bid, (done) => { // return a "NO_BID" replacement that the caller can decide to continue with // TODO: remove this in v8; see https://github.com/prebid/Prebid.js/issues/8956 - const noBid = createBid(CONSTANTS.STATUS.NO_BID, bid.getIdentifiers()); + const noBid = createBid(CONSTANTS.STATUS.NO_BID, bid.getIdentifiers?.()); Object.assign(noBid, Object.fromEntries(Object.entries(bid).filter(([k]) => !noBid.hasOwnProperty(k) && ![ 'ad', 'adUrl', diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index a48424b045c..47bdd4a3772 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -1641,6 +1641,15 @@ describe('auctionmanager.js', function () { }); }); + it('should return NO_BID replacement when rejected bid is not a "proper" bid', () => { + const noBid = cbs.addBidResponse.reject(AU_CODE, {}); + sinon.assert.match(noBid, { + status: CONSTANTS.BID_STATUS.BID_REJECTED, + statusMessage: 'Bid returned empty or error response', + cpm: 0, + }); + }) + it('addBidResponse hooks should not be able to reject the same bid twice', () => { cbs.addBidResponse(AU_CODE, bid); expect(auction.addBidRejected.calledOnce).to.be.true; From b762241b59a4f9850d40f1f249608bddc490d1d7 Mon Sep 17 00:00:00 2001 From: Antonio Gargaro <38767071+AntonioGargaro@users.noreply.github.com> Date: Wed, 2 Nov 2022 15:52:51 +0000 Subject: [PATCH 081/367] Permutive Rtd Provider: convert rubicon video targeting to string (#9181) * fix(permutiveRtd): convert video targeting to string * test(permutiveRtd): convert video targeting for Magmite to string * docs(permutiveRtd): add `overwrites` parameter --- modules/permutiveRtdProvider.js | 3 +- modules/permutiveRtdProvider.md | 37 +++++++++- .../spec/modules/permutiveRtdProvider_spec.js | 69 +++++++++++++++++-- 3 files changed, 102 insertions(+), 7 deletions(-) diff --git a/modules/permutiveRtdProvider.js b/modules/permutiveRtdProvider.js index a2cd7847564..c11d1c12436 100644 --- a/modules/permutiveRtdProvider.js +++ b/modules/permutiveRtdProvider.js @@ -238,7 +238,8 @@ function getDefaultBidderFn (bidder) { deepSetValue(bid, 'params.visitor.p_standard', data.ac) } if (data.rubicon && data.rubicon.length) { - deepSetValue(bid, 'params.visitor.permutive', data.rubicon) + const rubiconCohorts = deepAccess(bid, 'params.video') ? data.rubicon.map(String) : data.rubicon + deepSetValue(bid, 'params.visitor.permutive', rubiconCohorts) } return bid diff --git a/modules/permutiveRtdProvider.md b/modules/permutiveRtdProvider.md index f99389f82cc..7d8f073357c 100644 --- a/modules/permutiveRtdProvider.md +++ b/modules/permutiveRtdProvider.md @@ -45,17 +45,52 @@ as well as enabling settings for specific use cases mentioned above (e.g. acbidd | params.acBidders | String[] | An array of bidders which should receive AC cohorts. | `[]` | | params.maxSegs | Integer | Maximum number of cohorts to be included in either the `permutive` or `p_standard` key-value. | `500` | | params.transformations | Object[] | An array of configurations for ORTB2 user data transformations | | +| params.overwrites | Object | An object specifying functions for custom targeting logic for bidders. | - | ##### The `transformations` parameter This array contains configurations for transformations we'll apply to the Permutive object in the ORTB2 `user.data` array. The results of these transformations will be appended to the `user.data` array that's attached to ORTB2 bid requests. -##### Supported transformations +###### Supported transformations | Name | ID | Config structure | Description | |----------------|-----|---------------------------------------------------|--------------------------------------------------------------------------------------| | IAB taxonomies | iab | { segtax: number, iabIds: Object} | Transform segment IDs from Permutive to IAB (note: alpha version, subject to change) | +##### The `overwrites` parameter + +The keys for this object should match a bidder (e.g. `rubicon`), which then can define a function to overwrite the customer targeting logic. + +```javascript +{ + params: { + overwrites: { + rubicon: function customTargeting(bid, data, acEnabled, utils, defaultFn) { + if (defaultFn) { + bid = defaultFn(bid, data, acEnabled) + } + if (data.gam && data.gam.length) { + utils.deepSetValue(bid, 'params.visitor.permutive', data.gam) + } + } + } + } +} +``` + +###### `customTargeting` function parameters + +| Name | Description | +|--------------|--------------------------------------------------------------------------------| +| `bid` | The bid request object. | +| `data` | Permutive's targeting data read from localStorage. | +| `acEnabled` | Boolean stating whether Audience Connect is enabled via `acBidders`. | +| `utils` | An object of helpful utilities. `(deepSetValue, deepAccess, isFn, mergeDeep)`. | +| `defaultFn` | The default targeting function. | + + + + #### Context Permutive is not listed as a TCF vendor as all data collection is on behalf of the publisher and based on consent the publisher has received from the user. diff --git a/test/spec/modules/permutiveRtdProvider_spec.js b/test/spec/modules/permutiveRtdProvider_spec.js index 9282ec3ac24..3f104ee1e2e 100644 --- a/test/spec/modules/permutiveRtdProvider_spec.js +++ b/test/spec/modules/permutiveRtdProvider_spec.js @@ -13,13 +13,13 @@ import { deepAccess, deepSetValue, mergeDeep } from '../../../src/utils.js' import { config } from 'src/config.js' describe('permutiveRtdProvider', function () { - before(function () { + beforeEach(function () { const data = getTargetingData() setLocalStorage(data) config.resetConfig() }) - after(function () { + afterEach(function () { const data = getTargetingData() removeLocalStorage(data) config.resetConfig() @@ -317,6 +317,7 @@ describe('permutiveRtdProvider', function () { }) } }) + it('sets segment targeting for Magnite', function () { const data = transformedTargeting() const adUnits = getAdUnits() @@ -337,6 +338,38 @@ describe('permutiveRtdProvider', function () { }) } }) + + it('sets segment targeting for Magnite video', function () { + const targetingData = getTargetingData() + targetingData._prubicons.push(321) + + setLocalStorage(targetingData) + + const data = transformedTargeting(targetingData) + const config = getConfig() + + const adUnits = getAdUnits().filter(adUnit => adUnit.mediaTypes.video) + expect(adUnits).to.have.lengthOf(1) + + initSegments({ adUnits }, callback, config) + + function callback() { + adUnits.forEach(adUnit => { + adUnit.bids.forEach(bid => { + const { bidder, params } = bid + + if (bidder === 'rubicon') { + expect( + deepAccess(params, 'visitor.permutive'), + 'Should map all targeting values to a string', + ).to.eql(data.rubicon.map(String)) + expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac) + } + }) + }) + } + }) + it('sets segment targeting for Ozone', function () { const data = transformedTargeting() const adUnits = getAdUnits() @@ -516,9 +549,7 @@ function getConfig () { } } -function transformedTargeting () { - const data = getTargetingData() - +function transformedTargeting (data = getTargetingData()) { return { ac: [...data._pcrprs, ...data._ppam, ...data._psegs.filter(seg => seg >= 1000000)], appnexus: data._papns, @@ -640,6 +671,34 @@ function getAdUnits () { } } ] + }, + { + code: 'myVideoAdUnit', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480], + mimes: ['video/mp4', 'video/x-ms-wmv'], + protocols: [2, 3, 5, 6], + api: [2], + maxduration: 30, + linearity: 1 + } + }, + bids: [{ + bidder: 'rubicon', + params: { + accountId: '9840', + siteId: '123564', + zoneId: '583584', + video: { + language: 'en' + }, + visitor: { + test_kv: ['true'] + } + } + }] } ] } From 41f3e0542d8485bf962de32e585f56bd81ff00ee Mon Sep 17 00:00:00 2001 From: Robert Ray Martinez III Date: Wed, 2 Nov 2022 19:05:13 -0700 Subject: [PATCH 082/367] Magnite pass along networkId (#9193) --- modules/magniteAnalyticsAdapter.js | 7 ++++- .../modules/magniteAnalyticsAdapter_spec.js | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/modules/magniteAnalyticsAdapter.js b/modules/magniteAnalyticsAdapter.js index dba847e1b07..44666178e46 100644 --- a/modules/magniteAnalyticsAdapter.js +++ b/modules/magniteAnalyticsAdapter.js @@ -254,9 +254,14 @@ export const parseBidResponse = (bid, previousBidResponse) => { const validAdomains = Array.isArray(adomains) && adomains.filter(domain => typeof domain === 'string'); return validAdomains && validAdomains.length > 0 ? validAdomains.slice(0, 10) : undefined }, + 'networkId', () => { + const networkId = deepAccess(bid, 'meta.networkId'); + // if not a valid after this, set to undefined so it gets filtered out + return (networkId && networkId.toString()) || undefined; + }, 'conversionError', conversionError => conversionError === true || undefined, // only pass if exactly true 'ogCurrency', - 'ogPrice' + 'ogPrice', ]); } diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js index eb9ba190e33..240a5aa51a2 100644 --- a/test/spec/modules/magniteAnalyticsAdapter_spec.js +++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js @@ -602,6 +602,32 @@ describe('magnite analytics adapter', function () { let message = JSON.parse(server.requests[0].requestBody); expect(message.auctions[0].adUnits[0].bids[0].bidResponse.adomains).to.deep.equal(test.expected); }); + + // Network Id tests + [ + { input: 'magnite.com', expected: 'magnite.com' }, + { input: 12345, expected: '12345' }, + { input: ['magnite.com', 12345], expected: 'magnite.com,12345' } + ].forEach((test, index) => { + it(`should handle networkId correctly - #${index + 1}`, function () { + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + + let bidResponse = utils.deepClone(MOCK.BID_RESPONSE); + bidResponse.meta = { + networkId: test.input + }; + + events.emit(BID_RESPONSE, bidResponse); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(BID_WON, MOCK.BID_WON); + clock.tick(rubiConf.analyticsBatchTimeout + 1000); + + let message = JSON.parse(server.requests[0].requestBody); + expect(message.auctions[0].adUnits[0].bids[0].bidResponse.networkId).to.equal(test.expected); + }); + }); }); describe('with session handling', function () { From 454ddc868a77915c1acd5f19174f9e0caf2f4d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udi=20Talias=20=E2=9A=9B=EF=B8=8F?= Date: Thu, 3 Nov 2022 19:35:16 +0200 Subject: [PATCH 083/367] Kueezrtb Bid Adapter: New Bid Adapter (#9065) * feat(client): initial adapter * fix(client): change domain name * feat(client): updated md file * feat(module): remove gvlid * fix(module): added support for getFloor --- modules/kueezRtbBidAdapter.js | 276 +++++++++++++ modules/kueezRtbBidAdapter.md | 35 ++ test/spec/modules/kueezRtbBidAdapter_spec.js | 396 +++++++++++++++++++ 3 files changed, 707 insertions(+) create mode 100644 modules/kueezRtbBidAdapter.js create mode 100644 modules/kueezRtbBidAdapter.md create mode 100644 test/spec/modules/kueezRtbBidAdapter_spec.js diff --git a/modules/kueezRtbBidAdapter.js b/modules/kueezRtbBidAdapter.js new file mode 100644 index 00000000000..55545a8092d --- /dev/null +++ b/modules/kueezRtbBidAdapter.js @@ -0,0 +1,276 @@ +import { _each, deepAccess, parseSizesInput, parseUrl, uniques, isFn } from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const DEFAULT_SUB_DOMAIN = 'exchange'; +const BIDDER_CODE = 'kueezrtb'; +const BIDDER_VERSION = '1.0.0'; +const CURRENCY = 'USD'; +const TTL_SECONDS = 60 * 5; +const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 15; +export const SUPPORTED_ID_SYSTEMS = { + 'britepoolid': 1, + 'criteoId': 1, + 'id5id': 1, + 'idl_env': 1, + 'lipb': 1, + 'netId': 1, + 'parrableId': 1, + 'pubcid': 1, + 'tdid': 1, + 'pubProvidedId': 1 +}; +const storage = getStorageManager({ gvlid: null, bidderCode: BIDDER_CODE }); + +function getTopWindowQueryParams() { + try { + const parsedUrl = parseUrl(window.top.document.URL, { decodeSearchAsString: true }); + return parsedUrl.search; + } catch (e) { + return ''; + } +} + +export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { + return `https://${subDomain}.kueezrtb.com`; +} + +export function extractCID(params) { + return params.cId || params.CID || params.cID || params.CId || params.cid || params.ciD || params.Cid || params.CiD; +} + +export function extractPID(params) { + return params.pId || params.PID || params.pID || params.PId || params.pid || params.piD || params.Pid || params.PiD; +} + +export function extractSubDomain(params) { + return params.subDomain || params.SubDomain || params.Subdomain || params.subdomain || params.SUBDOMAIN || params.subDOMAIN; +} + +function isBidRequestValid(bid) { + const params = bid.params || {}; + return !!(extractCID(params) && extractPID(params)); +} + +function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { + const { params, bidId, userId, adUnitCode, schain } = bid; + let { bidFloor, ext } = params; + const hashUrl = hashCode(topWindowUrl); + const uniqueDealId = getUniqueDealId(hashUrl); + const cId = extractCID(params); + const pId = extractPID(params); + const subDomain = extractSubDomain(params); + + if (isFn(bid.getFloor)) { + const floorInfo = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*' + }); + + if (floorInfo.currency === 'USD') { + bidFloor = floorInfo.floor; + } + } + + let data = { + url: encodeURIComponent(topWindowUrl), + uqs: getTopWindowQueryParams(), + cb: Date.now(), + bidFloor: bidFloor, + bidId: bidId, + referrer: bidderRequest.refererInfo.ref, + adUnitCode: adUnitCode, + publisherId: pId, + sizes: sizes, + uniqueDealId: uniqueDealId, + bidderVersion: BIDDER_VERSION, + prebidVersion: '$prebid.version$', + res: `${screen.width}x${screen.height}`, + schain: schain + }; + + 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 + }; + + _each(ext, (value, key) => { + dto.data['ext.' + key] = value; + }); + + return dto; +} + +function appendUserIdsToRequestPayload(payloadRef, userIds) { + let key; + _each(userIds, (userId, idSystemProviderName) => { + if (SUPPORTED_ID_SYSTEMS[idSystemProviderName]) { + key = `uid.${idSystemProviderName}`; + + switch (idSystemProviderName) { + case 'digitrustid': + payloadRef[key] = deepAccess(userId, 'data.id'); + break; + case 'lipb': + payloadRef[key] = userId.lipbid; + break; + case 'parrableId': + payloadRef[key] = userId.eid; + break; + case 'id5id': + payloadRef[key] = userId.uid; + break; + default: + payloadRef[key] = userId; + } + } + }); +} + +function buildRequests(validBidRequests, bidderRequest) { + const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; + const requests = []; + validBidRequests.forEach(validBidRequest => { + const sizes = parseSizesInput(validBidRequest.sizes); + const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest); + requests.push(request); + }); + return requests; +} + +function interpretResponse(serverResponse, request) { + if (!serverResponse || !serverResponse.body) { + return []; + } + const { bidId } = request.data; + const { results } = serverResponse.body; + + let output = []; + + try { + results.forEach(result => { + const { creativeId, ad, price, exp, width, height, currency, advertiserDomains } = 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, + meta: { + advertiserDomains: advertiserDomains || [] + } + }) + }); + return output; + } catch (e) { + return []; + } +} + +function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '') { + let syncs = []; + const { iframeEnabled, pixelEnabled } = syncOptions; + const { gdprApplies, consentString = '' } = gdprConsent; + + const cidArr = responses.filter(resp => deepAccess(resp, 'body.cid')).map(resp => resp.body.cid).filter(uniques); + const params = `?cid=${encodeURIComponent(cidArr.join(','))}&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}` + if (iframeEnabled) { + syncs.push({ + type: 'iframe', + url: `https://sync.kueezrtb.com/api/sync/iframe/${params}` + }); + } + if (pixelEnabled) { + syncs.push({ + type: 'image', + url: `https://sync.kueezrtb.com/api/sync/image/${params}` + }); + } + return syncs; +} + +export function hashCode(s, prefix = '_') { + const l = s.length; + let h = 0 + let i = 0; + if (l > 0) { + while (i < l) { h = (h << 5) - h + s.charCodeAt(i++) | 0; } + } + return prefix + h; +} + +export function getUniqueDealId(key, expiry = UNIQUE_DEAL_ID_EXPIRY) { + const storageKey = `u_${key}`; + const now = Date.now(); + const data = getStorageItem(storageKey); + let uniqueId; + + if (!data || !data.value || now - data.created > expiry) { + uniqueId = `${key}_${now.toString()}`; + setStorageItem(storageKey, uniqueId); + } else { + uniqueId = data.value; + } + + return uniqueId; +} + +export function getStorageItem(key) { + try { + return tryParseJSON(storage.getDataFromLocalStorage(key)); + } catch (e) { } + + return null; +} + +export function setStorageItem(key, value, timestamp) { + try { + const created = timestamp || Date.now(); + const data = JSON.stringify({ value, created }); + storage.setDataInLocalStorage(key, data); + } catch (e) { } +} + +export function tryParseJSON(value) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } +} + +export const spec = { + code: BIDDER_CODE, + version: BIDDER_VERSION, + supportedMediaTypes: [BANNER], + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs +}; + +registerBidder(spec); diff --git a/modules/kueezRtbBidAdapter.md b/modules/kueezRtbBidAdapter.md new file mode 100644 index 00000000000..52d11aa362a --- /dev/null +++ b/modules/kueezRtbBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +**Module Name:** Kueez RTB Bidder Adapter + +**Module Type:** Bidder Adapter + +**Maintainer:** rtb@kueez.com + +# Description + +Module that connects to Kueez's demand sources. + +# Test Parameters +```js +var adUnits = [ + { + code: 'test-ad', + sizes: [[300, 250]], + bids: [ + { + bidder: 'kueezrtb', + params: { + cId: '562524b21b1c1f08117fc7f9', + pId: '59ac17c192832d0011283fe3', + bidFloor: 0.0001, + ext: { + param1: 'loremipsum', + param2: 'dolorsitamet' + } + } + } + ] + } +]; +``` diff --git a/test/spec/modules/kueezRtbBidAdapter_spec.js b/test/spec/modules/kueezRtbBidAdapter_spec.js new file mode 100644 index 00000000000..f9b2cd41a43 --- /dev/null +++ b/test/spec/modules/kueezRtbBidAdapter_spec.js @@ -0,0 +1,396 @@ +import {expect} from 'chai'; +import { + spec as adapter, + SUPPORTED_ID_SYSTEMS, + createDomain, + hashCode, + extractPID, + extractCID, + extractSubDomain, + getStorageItem, + setStorageItem, + tryParseJSON, + getUniqueDealId, +} from 'modules/kueezRtbBidAdapter.js'; +import * as utils from 'src/utils.js'; +import {version} from 'package.json'; +import {useFakeTimers} from 'sinon'; + +const SUB_DOMAIN = 'exchange'; + +const BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': 'div-gpt-ad-12345-0', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '59db6b3b4ffaa70004f45cdc', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1, + 'ext': { + 'param1': 'loremipsum', + 'param2': 'dolorsitamet' + } + }, + 'placementCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + 'sizes': [[300, 250], [300, 600]], + 'bidderRequestId': '1fdb5ff1b6eaa7', + 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc' +}; + +const BIDDER_REQUEST = { + 'gdprConsent': { + 'consentString': 'consent_string', + 'gdprApplies': true + }, + 'uspConsent': 'consent_string', + 'refererInfo': { + 'page': 'https://www.greatsite.com', + 'ref': 'https://www.somereferrer.com' + } +}; + +const SERVER_RESPONSE = { + body: { + cid: 'testcid123', + results: [{ + 'ad': '', + 'price': 0.8, + 'creativeId': '12610997325162499419', + 'exp': 30, + 'width': 300, + 'height': 250, + 'advertiserDomains': ['securepubads.g.doubleclick.net'], + 'cookies': [{ + 'src': 'https://sync.com', + 'type': 'iframe' + }, { + 'src': 'https://sync.com', + 'type': 'img' + }] + }] + } +}; + +const REQUEST = { + data: { + width: 300, + height: 250, + bidId: '2d52001cabd527' + } +}; + +function getTopWindowQueryParams() { + try { + const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true}); + return parsedUrl.search; + } catch (e) { + return ''; + } +} + +describe('KueezRtbBidAdapter', function () { + describe('validtae spec', function () { + it('exists and is a function', function () { + expect(adapter.isBidRequestValid).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.buildRequests).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.interpretResponse).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.getUserSyncs).to.exist.and.to.be.a('function'); + }); + + it('exists and is a string', function () { + expect(adapter.code).to.exist.and.to.be.a('string'); + }); + }); + + describe('validate bid requests', function () { + it('should require cId', function () { + const isValid = adapter.isBidRequestValid({ + params: { + pId: 'pid' + } + }); + expect(isValid).to.be.false; + }); + + it('should require pId', function () { + const isValid = adapter.isBidRequestValid({ + params: { + cId: 'cid' + } + }); + expect(isValid).to.be.false; + }); + + it('should validate correctly', function () { + const isValid = adapter.isBidRequestValid({ + params: { + cId: 'cid', + pId: 'pid' + } + }); + expect(isValid).to.be.true; + }); + }); + + describe('build requests', function () { + let sandbox; + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + kueezrtb: { + storageAllowed: true + } + }; + sandbox = sinon.sandbox.create(); + sandbox.stub(Date, 'now').returns(1000); + }); + + it('should build request for each size', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + const requests = adapter.buildRequests([BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/59db6b3b4ffaa70004f45cdc`, + data: { + gdprConsent: 'consent_string', + gdpr: 1, + usPrivacy: 'consent_string', + sizes: ['300x250', '300x600'], + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + cb: 1000, + bidFloor: 0.1, + bidId: '2d52001cabd527', + adUnitCode: 'div-gpt-ad-12345-0', + publisherId: '59ac17c192832d0011283fe3', + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + bidderVersion: adapter.version, + prebidVersion: version, + schain: BID.schain, + res: `${window.top.screen.width}x${window.top.screen.height}`, + uqs: getTopWindowQueryParams(), + 'ext.param1': 'loremipsum', + 'ext.param2': 'dolorsitamet', + } + }); + }); + + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + sandbox.restore(); + }); + }); + describe('getUserSyncs', function () { + it('should have valid user sync with iframeEnabled', function () { + const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + + expect(result).to.deep.equal([{ + type: 'iframe', + url: 'https://sync.kueezrtb.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' + }]); + }); + + it('should have valid user sync with cid on response', function () { + const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + expect(result).to.deep.equal([{ + type: 'iframe', + url: 'https://sync.kueezrtb.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' + }]); + }); + + it('should have valid user sync with pixelEnabled', function () { + const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]); + + expect(result).to.deep.equal([{ + 'url': 'https://sync.kueezrtb.com/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=', + 'type': 'image' + }]); + }) + }); + + describe('interpret response', function () { + it('should return empty array when there is no response', function () { + const responses = adapter.interpretResponse(null); + expect(responses).to.be.empty; + }); + + it('should return empty array when there is no ad', function () { + const responses = adapter.interpretResponse({price: 1, ad: ''}); + expect(responses).to.be.empty; + }); + + it('should return empty array when there is no price', function () { + const responses = adapter.interpretResponse({price: null, ad: 'great ad'}); + expect(responses).to.be.empty; + }); + + it('should return an array of interpreted responses', function () { + const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 0.8, + width: 300, + height: 250, + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 30, + ad: '', + meta: { + advertiserDomains: ['securepubads.g.doubleclick.net'] + } + }); + }); + + it('should take default TTL', function () { + const serverResponse = utils.deepClone(SERVER_RESPONSE); + delete serverResponse.body.results[0].exp; + const responses = adapter.interpretResponse(serverResponse, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0].ttl).to.equal(300); + }); + }); + + describe('user id system', function () { + Object.keys(SUPPORTED_ID_SYSTEMS).forEach((idSystemProvider) => { + const id = Date.now().toString(); + const bid = utils.deepClone(BID); + + const userId = (function () { + switch (idSystemProvider) { + case 'lipb': + return {lipbid: id}; + case 'parrableId': + return {eid: id}; + case 'id5id': + return {uid: id}; + default: + return id; + } + })(); + + bid.userId = { + [idSystemProvider]: userId + }; + + it(`should include 'uid.${idSystemProvider}' in request params`, function () { + const requests = adapter.buildRequests([bid], BIDDER_REQUEST); + expect(requests[0].data[`uid.${idSystemProvider}`]).to.equal(id); + }); + }); + }); + + describe('alternate param names extractors', function () { + it('should return undefined when param not supported', function () { + const cid = extractCID({'c_id': '1'}); + const pid = extractPID({'p_id': '1'}); + const subDomain = extractSubDomain({'sub_domain': 'prebid'}); + expect(cid).to.be.undefined; + expect(pid).to.be.undefined; + expect(subDomain).to.be.undefined; + }); + + it('should return value when param supported', function () { + const cid = extractCID({'cID': '1'}); + const pid = extractPID({'Pid': '2'}); + const subDomain = extractSubDomain({'subDOMAIN': 'prebid'}); + expect(cid).to.be.equal('1'); + expect(pid).to.be.equal('2'); + expect(subDomain).to.be.equal('prebid'); + }); + }); + + describe('unique deal id', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + kueezrtb: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + const key = 'myKey'; + let uniqueDealId; + beforeEach(() => { + uniqueDealId = getUniqueDealId(key, 0); + }) + + it('should get current unique deal id', function (done) { + // waiting some time so `now` will become past + setTimeout(() => { + const current = getUniqueDealId(key); + expect(current).to.be.equal(uniqueDealId); + done(); + }, 200); + }); + + it('should get new unique deal id on expiration', function (done) { + setTimeout(() => { + const current = getUniqueDealId(key, 100); + expect(current).to.not.be.equal(uniqueDealId); + done(); + }, 200) + }); + }); + + describe('storage utils', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + kueezrtb: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + it('should get value from storage with create param', function () { + const now = Date.now(); + const clock = useFakeTimers({ + shouldAdvanceTime: true, + now + }); + setStorageItem('myKey', 2020); + const {value, created} = getStorageItem('myKey'); + expect(created).to.be.equal(now); + expect(value).to.be.equal(2020); + expect(typeof value).to.be.equal('number'); + expect(typeof created).to.be.equal('number'); + clock.restore(); + }); + + it('should get external stored value', function () { + const value = 'superman' + window.localStorage.setItem('myExternalKey', value); + const item = getStorageItem('myExternalKey'); + expect(item).to.be.equal(value); + }); + + it('should parse JSON value', function () { + const data = JSON.stringify({event: 'send'}); + const {event} = tryParseJSON(data); + expect(event).to.be.equal('send'); + }); + + it('should get original value on parse fail', function () { + const value = 21; + const parsed = tryParseJSON(value); + expect(typeof parsed).to.be.equal('number'); + expect(parsed).to.be.equal(value); + }); + }); +}); From f7bba1dfa44e3d19a04fbd377bcb38ac6599a825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udi=20Talias=20=E2=9A=9B=EF=B8=8F?= Date: Thu, 3 Nov 2022 20:13:11 +0200 Subject: [PATCH 084/367] added gvlid code (#9199) --- modules/kueezRtbBidAdapter.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/kueezRtbBidAdapter.js b/modules/kueezRtbBidAdapter.js index 55545a8092d..1ee3b7331cb 100644 --- a/modules/kueezRtbBidAdapter.js +++ b/modules/kueezRtbBidAdapter.js @@ -3,6 +3,7 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { getStorageManager } from '../src/storageManager.js'; +const GVLID = 1165; const DEFAULT_SUB_DOMAIN = 'exchange'; const BIDDER_CODE = 'kueezrtb'; const BIDDER_VERSION = '1.0.0'; @@ -21,7 +22,7 @@ export const SUPPORTED_ID_SYSTEMS = { 'tdid': 1, 'pubProvidedId': 1 }; -const storage = getStorageManager({ gvlid: null, bidderCode: BIDDER_CODE }); +const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }); function getTopWindowQueryParams() { try { @@ -266,6 +267,7 @@ export function tryParseJSON(value) { export const spec = { code: BIDDER_CODE, version: BIDDER_VERSION, + gvlid: GVLID, supportedMediaTypes: [BANNER], isBidRequestValid, buildRequests, From 530017f8d293ad7ae651edf238e92c661899680c Mon Sep 17 00:00:00 2001 From: Jason Quaccia Date: Thu, 3 Nov 2022 11:17:25 -0700 Subject: [PATCH 085/367] updated docs for adRenderSucceeded event (#9195) --- src/adRendering.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adRendering.js b/src/adRendering.js index a645ec77244..0a847d7cc25 100644 --- a/src/adRendering.js +++ b/src/adRendering.js @@ -23,7 +23,7 @@ export function emitAdRenderFail({ reason, message, bid, id }) { /** * Emit the AD_RENDER_SUCCEEDED event. - * + * (Note: Invocation of this function indicates that the render function did not generate an error, it does not guarantee that tracking for this event has occurred yet.) * @param doc document object that was used to `.write` the ad. Should be `null` if unavailable (e.g. for documents in * a cross-origin frame). * @param bid bid response object for the ad that was rendered From 338b9c671f293f07742b647135de3e352d982e5b Mon Sep 17 00:00:00 2001 From: John Ivan Bauzon Date: Fri, 4 Nov 2022 02:19:33 +0800 Subject: [PATCH 086/367] gumgum Bid Adapter: support coppa config (#9192) * ADJS-1227-add-coppa-flag-to-gumgum-adapter * added tests for coppa config for gumgumBidAdapter Co-authored-by: John Bauzon --- modules/gumgumBidAdapter.js | 4 ++++ test/spec/modules/gumgumBidAdapter_spec.js | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/modules/gumgumBidAdapter.js b/modules/gumgumBidAdapter.js index fe15602c0c0..93306984ab1 100644 --- a/modules/gumgumBidAdapter.js +++ b/modules/gumgumBidAdapter.js @@ -294,6 +294,7 @@ function buildRequests(validBidRequests, bidderRequest) { const gdprConsent = bidderRequest && bidderRequest.gdprConsent; const uspConsent = bidderRequest && bidderRequest.uspConsent; const timeout = config.getConfig('bidderTimeout'); + const coppa = config.getConfig('coppa') === true ? 1 : 0; const topWindowUrl = bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.page; _each(validBidRequests, bidRequest => { const { @@ -386,6 +387,9 @@ function buildRequests(validBidRequests, bidderRequest) { if (uspConsent) { data.uspConsent = uspConsent; } + if (coppa) { + data.coppa = coppa; + } if (schain && schain.nodes) { data.schain = _serializeSupplyChainObj(schain); } diff --git a/test/spec/modules/gumgumBidAdapter_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js index 17fff31f132..a2dacb16b73 100644 --- a/test/spec/modules/gumgumBidAdapter_spec.js +++ b/test/spec/modules/gumgumBidAdapter_spec.js @@ -1,5 +1,6 @@ import { BANNER, VIDEO } from 'src/mediaTypes.js'; +import { config } from 'src/config.js'; import { expect } from 'chai'; import { newBidder } from 'src/adapters/bidderFactory.js'; import { spec } from 'modules/gumgumBidAdapter.js'; @@ -484,6 +485,20 @@ describe('gumgumAdapter', function () { const bidRequest = spec.buildRequests(bidRequests, fakeBidRequest)[0]; expect(bidRequest.data).to.not.include.any.keys('gdprConsent') }); + it('should not set coppa parameter if coppa config is set to false', function () { + config.setConfig({ + coppa: false + }); + const bidRequest = spec.buildRequests(bidRequests)[0]; + expect(bidRequest.data.coppa).to.eq(undefined); + }); + it('should set coppa parameter to 1 if coppa config is set to true', function () { + config.setConfig({ + coppa: true + }); + const bidRequest = spec.buildRequests(bidRequests)[0]; + expect(bidRequest.data.coppa).to.eq(1); + }); it('should add uspConsent parameter if it is present in the bidderRequest', function () { const noUspBidRequest = spec.buildRequests(bidRequests)[0]; const uspConsentObj = { uspConsent: '1YYY' }; From 7a46ed1e9b79224dfa28832b74349984cae9429f Mon Sep 17 00:00:00 2001 From: Chris Huie Date: Thu, 3 Nov 2022 12:40:44 -0600 Subject: [PATCH 087/367] Dependencies : update outdated dependencies and automated security alerts (#9172) * update package-lock * Fix wdio version Co-authored-by: Demetrio Girardi --- package-lock.json | 16356 +++++++++++++++++++++++++++++--------------- package.json | 14 +- 2 files changed, 10662 insertions(+), 5708 deletions(-) diff --git a/package-lock.json b/package-lock.json index d37403f06e1..7567271b07f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.23.0-pre", + "version": "7.24.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -26,13 +26,13 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.16.5", - "@wdio/browserstack-service": "^7.16.0", - "@wdio/cli": "^7.5.2", - "@wdio/concise-reporter": "^7.5.2", - "@wdio/local-runner": "^7.5.2", - "@wdio/mocha-framework": "^7.5.2", - "@wdio/spec-reporter": "^7.19.0", - "@wdio/sync": "^7.5.2", + "@wdio/browserstack-service": "~7.16.0", + "@wdio/cli": "~7.5.2", + "@wdio/concise-reporter": "~7.5.2", + "@wdio/local-runner": "~7.5.2", + "@wdio/mocha-framework": "~7.5.2", + "@wdio/spec-reporter": "~7.19.0", + "@wdio/sync": "~7.5.2", "ajv": "6.12.3", "assert": "^2.0.0", "babel-loader": "^8.0.5", @@ -115,11 +115,12 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" @@ -137,28 +138,28 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", - "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -174,12 +175,12 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", - "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", "dev": true, "dependencies": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", "semver": "^6.3.0" }, @@ -192,11 +193,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.1.tgz", + "integrity": "sha512-u1dMdBUmA7Z0rBB97xh8pIhviK7oItYOkjbsCxTWMknyvbQRBwX7/gn4JXurRdirWMFh+ZtYARqkA6ydogVZpg==", "dependencies": { - "@babel/types": "^7.19.0", + "@babel/types": "^7.20.0", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -204,37 +205,50 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", - "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", "dependencies": { - "@babel/compat-data": "^7.19.0", + "@babel/compat-data": "^7.20.0", "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", + "browserslist": "^4.21.3", "semver": "^6.3.0" }, "engines": { @@ -245,17 +259,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", - "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -265,12 +279,12 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" }, "engines": { "node": ">=6.9.0" @@ -280,14 +294,12 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -306,11 +318,11 @@ } }, "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -340,11 +352,11 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -362,87 +374,91 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", - "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.19.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.20.0" }, "engines": { "node": ">=6.9.0" @@ -460,17 +476,17 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "engines": { "node": ">=6.9.0" } @@ -484,27 +500,27 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", "dependencies": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", "dependencies": { "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" }, "engines": { "node": ">=6.9.0" @@ -524,9 +540,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", - "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.1.tgz", + "integrity": "sha512-hp0AYxaZJhxULfM1zyp7Wgr+pSUKBcP3M+PHnSzWGdXOzg/kHWIgiUWARvubhUKGOEw3xqY4x+lyZ9ytBVcELw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -535,11 +551,11 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -549,13 +565,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -565,12 +581,13 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz", + "integrity": "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -581,12 +598,12 @@ } }, "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -596,12 +613,12 @@ } }, "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", - "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -612,11 +629,11 @@ } }, "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -627,11 +644,11 @@ } }, "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -642,11 +659,11 @@ } }, "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -657,11 +674,11 @@ } }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -672,11 +689,11 @@ } }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -687,11 +704,11 @@ } }, "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -702,15 +719,15 @@ } }, "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", - "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", "dependencies": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" + "@babel/plugin-transform-parameters": "^7.18.8" }, "engines": { "node": ">=6.9.0" @@ -720,11 +737,11 @@ } }, "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -735,12 +752,12 @@ } }, "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -751,12 +768,12 @@ } }, "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -766,13 +783,13 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -783,12 +800,12 @@ } }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=4" @@ -855,6 +872,20 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@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", @@ -961,11 +992,11 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -975,13 +1006,13 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -991,11 +1022,11 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1005,11 +1036,11 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.0.tgz", + "integrity": "sha512-sXOohbpHZSk7GjxK9b3dKB7CfqUD5DwOH+DggKzOQ7TXYP+RCSbRykfjQmn/zq+rBjycVRtLf9pYhAaEJA786w==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1019,17 +1050,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", "globals": "^11.1.0" }, "engines": { @@ -1040,11 +1072,11 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1054,11 +1086,11 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.0.tgz", + "integrity": "sha512-1dIhvZfkDVx/zn2S1aFwlruspTt4189j7fEkH0Y0VyuDM6bQt7bD6kLcz3l4IlLG+e5OReaBz9ROAbttRtUHqA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1068,12 +1100,12 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1083,11 +1115,11 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1097,12 +1129,12 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1112,11 +1144,11 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1126,13 +1158,13 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "dependencies": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1142,11 +1174,11 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1156,11 +1188,11 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1170,13 +1202,12 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1186,14 +1217,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" }, "engines": { "node": ">=6.9.0" @@ -1203,15 +1233,14 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", "dependencies": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" }, "engines": { "node": ">=6.9.0" @@ -1221,12 +1250,12 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1236,11 +1265,12 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1250,11 +1280,11 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1264,12 +1294,12 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1279,11 +1309,11 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.1.tgz", + "integrity": "sha512-nDvKLrAvl+kf6BOy1UJ3MGwzzfTMgppxwiD2Jb4LO3xjYyZq30oQzDNJbCQpMdG9+j2IXHoiMrw5Cm/L6ZoxXQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1293,11 +1323,11 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1307,11 +1337,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", "dependencies": { - "regenerator-transform": "^0.14.2" + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" }, "engines": { "node": ">=6.9.0" @@ -1321,11 +1352,11 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1335,15 +1366,15 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.9.tgz", - "integrity": "sha512-wS8uJwBt7/b/mzE13ktsJdmS4JP/j7PQSaADtnb4I2wL0zK51MQ0pmF8/Jy0wUIS96fr+fXT6S/ifiPXnvrlSg==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", "dependencies": { "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.9", - "babel-plugin-polyfill-corejs2": "^0.3.1", - "babel-plugin-polyfill-corejs3": "^0.5.2", - "babel-plugin-polyfill-regenerator": "^0.3.1", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", "semver": "^6.3.0" }, "engines": { @@ -1354,11 +1385,11 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1368,12 +1399,12 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1383,11 +1414,11 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1397,11 +1428,11 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1411,11 +1442,11 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1425,11 +1456,11 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1439,12 +1470,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1454,36 +1485,37 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz", + "integrity": "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==", "dependencies": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.19.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.19.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -1493,44 +1525,44 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.19.4", + "@babel/plugin-transform-classes": "^7.19.0", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.19.4", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", + "@babel/types": "^7.19.4", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", "semver": "^6.3.0" }, "engines": { @@ -1556,20 +1588,28 @@ } }, "node_modules/@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", + "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", "dependencies": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.13.10" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/runtime/node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "node_modules/@babel/runtime-corejs3": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.20.1.tgz", + "integrity": "sha512-CGulbEDcg/ND1Im7fUNRZdGXmX2MTWVVZacQi/6DiKE5HNwZ3aVTm5PV4lO8HHz0B2h8WQyvKKjbX5XgTtydsg==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.10" + }, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/template": { "version": "7.18.10", @@ -1585,18 +1625,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", - "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", + "@babel/generator": "^7.20.1", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.0", - "@babel/types": "^7.19.0", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1605,12 +1645,12 @@ } }, "node_modules/@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.0.tgz", + "integrity": "sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==", "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1663,9 +1703,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1774,7 +1814,7 @@ "node_modules/@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=", + "integrity": "sha512-o/EatdaGt8+x2qpb0vFLC/2Gug/xYPRXb6a+ET1wGYKozKN3krDWC/zZFZAtrzxJHuDL12mwdfEFKcKMNvc55A==", "dev": true, "dependencies": { "normalize-path": "^2.0.1", @@ -1787,7 +1827,7 @@ "node_modules/@gulp-sourcemaps/map-sources/node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -1869,76 +1909,6 @@ "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/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, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/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, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/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, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/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, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/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, - "engines": { - "node": ">=6" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/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, - "engines": { - "node": ">=8" - } - }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -1949,19 +1919,19 @@ } }, "node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", + "@types/yargs": "^15.0.0", "chalk": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/@jest/types/node_modules/ansi-styles": { @@ -2013,6 +1983,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@jest/types/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/types/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2026,22 +2005,21 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "engines": { "node": ">=6.0.0" } @@ -2064,18 +2042,41 @@ "@jridgewell/trace-mapping": "^0.3.9" } }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" } }, "node_modules/@polka/url": { @@ -2126,19 +2127,16 @@ } }, "node_modules/@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==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, - "node_modules/@socket.io/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", @@ -2153,9 +2151,9 @@ } }, "node_modules/@types/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", "dev": true }, "node_modules/@types/cacheable-request": { @@ -2170,12 +2168,6 @@ "@types/responselike": "*" } }, - "node_modules/@types/component-emitter": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", - "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==", - "dev": true - }, "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -2210,15 +2202,15 @@ "dev": true }, "node_modules/@types/ejs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.0.tgz", - "integrity": "sha512-DCg+Ka+uDQ31lJ/UtEXVlaeV3d6t81gifaVWKJy4MYVVgvJttyX/viREy+If7fz+tK/gVxTGMtyrFPnm4gjrVA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.1.tgz", + "integrity": "sha512-RQul5wEfY7BjWm0sYY86cmUN/pcXWGyVxWX93DFFJvcrxax5zKlieLwA3T77xJGwNcZW0YW6CYG70p1m8xPFmA==", "dev": true }, "node_modules/@types/eslint": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", - "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "version": "8.4.9", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.9.tgz", + "integrity": "sha512-jFCSo4wJzlHQLCpceUhUnXdrPuCNOjGFMQ8Eg6JXxlz3QaCKOb7eGi2cephQdM4XTYsNej69P9JDJ1zqNIbncQ==", "dev": true, "dependencies": { "@types/estree": "*", @@ -2226,9 +2218,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", "dev": true, "dependencies": { "@types/eslint": "*", @@ -2290,13 +2282,13 @@ "dev": true }, "node_modules/@types/inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-BNoMetRf3gmkpAlV5we+kxyZTle7YibdOntIZbU5pyIfMdcwy784KfeZDAcuyMznkh5OLa17RVXZOGA5LTlkgQ==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-HhxyLejTHMfohAuhRun4csWigAMjXTmRyiJTU1Y/I1xmggikFMkOUoMQRlFm+zQcPEGHSs3io/0FAmNZf8EymQ==", "dev": true, "dependencies": { "@types/through": "*", - "rxjs": "^7.2.0" + "rxjs": "^6.4.0" } }, "node_modules/@types/istanbul-lib-coverage": { @@ -2324,54 +2316,55 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "node_modules/@types/keyv": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", - "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-4.2.0.tgz", + "integrity": "sha512-xoBtGl5R9jeKUhc8ZqeYaRDx04qqJ10yhhXYGmJ4Jr8qKpvMsDQQrNUvF/wUJ4klOtmJeJM+p2Xo3zp9uaC3tw==", + "deprecated": "This is a stub types definition. keyv provides its own type definitions, so you do not need this installed.", "dev": true, "dependencies": { - "@types/node": "*" + "keyv": "*" } }, "node_modules/@types/lodash": { - "version": "4.14.179", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz", - "integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==", + "version": "4.14.187", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.187.tgz", + "integrity": "sha512-MrO/xLXCaUgZy3y96C/iOsaIqZSeupyTImKClHunL5GrmaiII2VwvWmLBu2hwa0Kp0sV19CsyjtrTc/Fx8rg/A==", "dev": true }, "node_modules/@types/lodash.flattendeep": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.6.tgz", - "integrity": "sha512-uLm2MaRVlqJSGsMK0RZpP5T3KqReq+9WbYDHCUhBhp98v56hMG/Yht52bsoTSui9xz2mUvQ9NfG3LrNGDL92Ng==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.7.tgz", + "integrity": "sha512-1h6GW/AeZw/Wej6uxrqgmdTDZX1yFS39lRsXYkg+3kWvOWWrlGCI6H7lXxlUHOzxDT4QeYGmgPpQ3BX9XevzOg==", "dev": true, "dependencies": { "@types/lodash": "*" } }, "node_modules/@types/lodash.pickby": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.6.tgz", - "integrity": "sha512-NFa13XxlMd9eFi0UFZFWIztpMpXhozbijrx3Yb1viYZphT7jyopIFVoIRF4eYMjruWNEG1rnyrRmg/8ej9T8Iw==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.7.tgz", + "integrity": "sha512-4ebXRusuLflfscbD0PUX4eVknDHD9Yf+uMtBIvA/hrnTqeAzbuHuDjvnYriLjUrI9YrhCPVKUf4wkRSXJQ6gig==", "dev": true, "dependencies": { "@types/lodash": "*" } }, "node_modules/@types/lodash.union": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.6.tgz", - "integrity": "sha512-Wu0ZEVNcyCz8eAn6TlUbYWZoGbH9E+iOHxAZbwUoCEXdUiy6qpcz5o44mMXViM4vlPLLCPlkAubEP1gokoSZaw==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.7.tgz", + "integrity": "sha512-6HXM6tsnHJzKgJE0gA/LhTGf/7AbjUk759WZ1MziVm+OBNAATHhdgj+a3KVE8g76GCLAnN4ZEQQG1EGgtBIABA==", "dev": true, "dependencies": { "@types/lodash": "*" @@ -2386,16 +2379,10 @@ "@types/unist": "*" } }, - "node_modules/@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", - "dev": true - }, "node_modules/@types/mocha": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", - "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", + "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==", "dev": true }, "node_modules/@types/ms": { @@ -2405,9 +2392,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -2423,18 +2410,18 @@ "dev": true }, "node_modules/@types/puppeteer": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.5.tgz", - "integrity": "sha512-lxCjpDEY+DZ66+W3x5Af4oHnEmUXt0HuaRzkBGE2UZiZEp/V1d3StpLPlmNVu/ea091bdNmVPl44lu8Wy/0ZCA==", + "version": "5.4.7", + "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.7.tgz", + "integrity": "sha512-JdGWZZYL0vKapXF4oQTC5hLVNfOgdPrqeZ1BiQnGk5cB7HeE91EWUiTdVSdQPobRN8rIcdffjiOgCYJ/S8QrnQ==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/recursive-readdir": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.0.tgz", - "integrity": "sha512-HGk753KRu2N4mWduovY4BLjYq4jTOL29gV2OfGdGxHcPSWGFkC5RRIdk+VTs5XmYd7MVAD+JwKrcb5+5Y7FOCg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.1.tgz", + "integrity": "sha512-Xd+Ptc4/F2ueInqy5yK2FI5FxtwwbX2+VZpcg+9oYsFJVen8qQKGapCr+Bi5wQtHU1cTXT8s+07lo/nKPgu8Gg==", "dev": true, "dependencies": { "@types/node": "*" @@ -2514,9 +2501,9 @@ "dev": true }, "node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -2529,9 +2516,9 @@ "dev": true }, "node_modules/@types/yauzl": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", - "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, "optional": true, "dependencies": { @@ -2545,9 +2532,9 @@ "dev": true }, "node_modules/@videojs/http-streaming": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.2.tgz", - "integrity": "sha512-K1raSfO/pq5r8iUas3OSYni0kXOj91n8ealIpV02khghzGv9LQ6O3YUqYd/eAhJ1HIrmZWOnrYpK/P+mhUExXQ==", + "version": "2.14.3", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.3.tgz", + "integrity": "sha512-2tFwxCaNbcEZzQugWf8EERwNMyNtspfHnvxRGRABQs09W/5SqmkWFuGWfUAm4wQKlXGfdPyAJ1338ASl459xAA==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", @@ -2594,14 +2581,14 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.38.tgz", - "integrity": "sha512-/FsvnSu7Z+lkd/8KXMa4yYNUiqQrI22135gfsQYVGuh5tqEgOB0XqrUdb/KnCLa5+TmQLPwvyUnKMyCpu+SX3Q==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.41.tgz", + "integrity": "sha512-oA4mH6SA78DT+96/nsi4p9DX97PHcNROxs51lYk7gb9Z4BPKQ3Mh+BLn6CQZBw857Iuhu28BfMSRHAlPvD4vlw==", "dev": true, "optional": true, "dependencies": { "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.38", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "source-map": "^0.6.1" } @@ -2617,29 +2604,29 @@ } }, "node_modules/@vue/compiler-dom": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.38.tgz", - "integrity": "sha512-zqX4FgUbw56kzHlgYuEEJR8mefFiiyR3u96498+zWPsLeh1WKvgIReoNE+U7gG8bCUdvsrJ0JRmev0Ky6n2O0g==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.41.tgz", + "integrity": "sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw==", "dev": true, "optional": true, "dependencies": { - "@vue/compiler-core": "3.2.38", - "@vue/shared": "3.2.38" + "@vue/compiler-core": "3.2.41", + "@vue/shared": "3.2.41" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.38.tgz", - "integrity": "sha512-KZjrW32KloMYtTcHAFuw3CqsyWc5X6seb8KbkANSWt3Cz9p2qA8c1GJpSkksFP9ABb6an0FLCFl46ZFXx3kKpg==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.41.tgz", + "integrity": "sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w==", "dev": true, "optional": true, "dependencies": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.38", - "@vue/compiler-dom": "3.2.38", - "@vue/compiler-ssr": "3.2.38", - "@vue/reactivity-transform": "3.2.38", - "@vue/shared": "3.2.38", + "@vue/compiler-core": "3.2.41", + "@vue/compiler-dom": "3.2.41", + "@vue/compiler-ssr": "3.2.41", + "@vue/reactivity-transform": "3.2.41", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "magic-string": "^0.25.7", "postcss": "^8.1.10", @@ -2657,34 +2644,34 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.38.tgz", - "integrity": "sha512-bm9jOeyv1H3UskNm4S6IfueKjUNFmi2kRweFIGnqaGkkRePjwEcfCVqyS3roe7HvF4ugsEkhf4+kIvDhip6XzQ==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.41.tgz", + "integrity": "sha512-Y5wPiNIiaMz/sps8+DmhaKfDm1xgj6GrH99z4gq2LQenfVQcYXmHIOBcs5qPwl7jaW3SUQWjkAPKMfQemEQZwQ==", "dev": true, "optional": true, "dependencies": { - "@vue/compiler-dom": "3.2.38", - "@vue/shared": "3.2.38" + "@vue/compiler-dom": "3.2.41", + "@vue/shared": "3.2.41" } }, "node_modules/@vue/reactivity-transform": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.38.tgz", - "integrity": "sha512-3SD3Jmi1yXrDwiNJqQ6fs1x61WsDLqVk4NyKVz78mkaIRh6d3IqtRnptgRfXn+Fzf+m6B1KxBYWq1APj6h4qeA==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.41.tgz", + "integrity": "sha512-mK5+BNMsL4hHi+IR3Ft/ho6Za+L3FA5j8WvreJ7XzHrqkPq8jtF/SMo7tuc9gHjLDwKZX1nP1JQOKo9IEAn54A==", "dev": true, "optional": true, "dependencies": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.38", - "@vue/shared": "3.2.38", + "@vue/compiler-core": "3.2.41", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "magic-string": "^0.25.7" } }, "node_modules/@vue/shared": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.38.tgz", - "integrity": "sha512-dTyhTIRmGXBjxJE+skC8tTWCGLCVc4wQgRRLt8+O9p5ewBAjoBwtCAkLPrtToSr1xltoe3st21Pv953aOZ7alg==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.41.tgz", + "integrity": "sha512-W9mfWLHmJhkfAmV+7gDjcHeAWALQtgGT3JErxULl0oz6R6+3ug91I7IErs93eCFhPCZPHBs4QJS7YWEV7A3sxw==", "dev": true, "optional": true }, @@ -2708,37 +2695,224 @@ "@wdio/cli": "^7.0.0" } }, - "node_modules/@wdio/cli": { + "node_modules/@wdio/browserstack-service/node_modules/@wdio/config": { "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.16.16.tgz", - "integrity": "sha512-Wz/e5zm1UNHB9RAIsJIM7ioDzVllUwTvhVWOrI7HR/53GmO/cIvAVjpnlglizJNgK8WlbnM/cKNVIXxqxrnFmw==", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.16.16.tgz", + "integrity": "sha512-K/ObPuo6Da2liz++OKOIfbdpFwI7UWiFcBylfJkCYbweuXCoW1aUqlKI6rmKPwCH9Uqr/RHWu6p8eo0zWe6xVA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.14", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/@wdio/protocols": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.16.7.tgz", + "integrity": "sha512-Wv40pNQcLiPzQ3o98Mv4A8T1EBQ6k4khglz/e2r16CTm+F3DDYh8eLMAsU5cgnmuwwDKX1EyOiFwieykBn5MCg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/@wdio/repl": { + "version": "7.16.14", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.16.14.tgz", + "integrity": "sha512-Ezih0Y+lsGkKv3H3U56hdWgZiQGA3VaAYguSLd9+g1xbQq+zMKqSmfqECD9bAy+OgCCiVTRstES6lHZxJVPhAg==", + "dev": true, + "dependencies": { + "@wdio/utils": "7.16.14" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/@wdio/utils": { + "version": "7.16.14", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.16.14.tgz", + "integrity": "sha512-wwin8nVpIlhmXJkq6GJw9aDDzgLOJKgXTcEua0T2sdXjoW78u5Ly/GZrFXTjMGhacFvoZfitTrjyfyy4CxMVvw==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.14", + "p-iteration": "^1.1.8" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/devtools": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", + "integrity": "sha512-M0kzkuSgfEhpqIis3gdtWsNjn/HQ+vRAmEzDnbYx/7FfjFxhSv1d+rOOT20pvd60soItMYpsOova1igACEGkGQ==", + "dev": true, + "dependencies": { + "@types/node": "^17.0.4", + "@types/ua-parser-js": "^0.7.33", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "chrome-launcher": "^0.15.0", + "edge-paths": "^2.1.0", + "puppeteer-core": "^13.1.3", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.1", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/devtools-protocol": { + "version": "0.0.973690", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.973690.tgz", + "integrity": "sha512-myh3hSFp0YWa2GED11PmbLhV4dv9RdO7YUz27XJrbQLnP5bMbZL6dfOOILTHO57yH0kX5GfuOZBsg/4NamfPvQ==", + "dev": true + }, + "node_modules/@wdio/browserstack-service/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/ua-parser-js": { + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", + "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriver": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.16.16.tgz", + "integrity": "sha512-x8UoG9k/P8KDrfSh1pOyNevt9tns3zexoMxp9cKnyA/7HYSErhZYTLGlgxscAXLtQG41cMH/Ba/oBmOx7Hgd8w==", + "dev": true, + "dependencies": { + "@types/node": "^17.0.4", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "got": "^11.0.2", + "ky": "^0.29.0", + "lodash.merge": "^4.6.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/browserstack-service/node_modules/webdriverio": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.16.16.tgz", + "integrity": "sha512-caPaEWyuD3Qoa7YkW4xCCQA4v9Pa9wmhFGPvNZh3ERtjMCNi8L/XXOdkekWNZmFh3tY0kFguBj7+fAwSY7HAGw==", + "dev": true, + "dependencies": { + "@types/aria-query": "^5.0.0", + "@types/node": "^17.0.4", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/repl": "7.16.14", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "archiver": "^5.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.16.16", + "devtools-protocol": "^0.0.973690", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "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", + "minimatch": "^5.0.0", + "puppeteer-core": "^13.1.3", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.16.16" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/cli": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.5.7.tgz", + "integrity": "sha512-nOQJLskrY+UECDd3NxE7oBzb6cDA7e7x02YWQugOlOgnZ4a+PJmkFoSsO8C2uNCpdFngy5rJKGUo5vbtAHEF9Q==", "dev": true, "dependencies": { "@types/ejs": "^3.0.5", "@types/fs-extra": "^9.0.4", - "@types/inquirer": "^8.1.2", + "@types/inquirer": "^7.3.1", "@types/lodash.flattendeep": "^4.4.6", "@types/lodash.pickby": "^4.6.6", "@types/lodash.union": "^4.6.6", - "@types/node": "^17.0.4", "@types/recursive-readdir": "^2.2.0", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "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": "^10.0.0", - "inquirer": "8.1.5", + "inquirer": "^8.0.0", "lodash.flattendeep": "^4.4.0", "lodash.pickby": "^4.6.0", "lodash.union": "^4.6.0", "mkdirp": "^1.0.4", "recursive-readdir": "^2.2.2", - "webdriverio": "7.16.16", + "webdriverio": "7.5.7", "yargs": "^17.0.0", "yarn-install": "^1.0.0" }, @@ -2749,6 +2923,39 @@ "node": ">=12.0.0" } }, + "node_modules/@wdio/cli/node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "node_modules/@wdio/cli/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@wdio/cli/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2764,6 +2971,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/@wdio/cli/node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, "node_modules/@wdio/cli/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2780,6 +3000,32 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@wdio/cli/node_modules/chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "dependencies": { + "@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" + } + }, + "node_modules/@wdio/cli/node_modules/chrome-launcher/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/@wdio/cli/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2798,6 +3044,72 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@wdio/cli/node_modules/devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "dependencies": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "dev": true + }, + "node_modules/@wdio/cli/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/cli/node_modules/puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "engines": { + "node": ">=10.18.1" + } + }, + "node_modules/@wdio/cli/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + }, "node_modules/@wdio/cli/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2810,13 +3122,82 @@ "node": ">=8" } }, + "node_modules/@wdio/cli/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/cli/node_modules/webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", + "dev": true, + "dependencies": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "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", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@wdio/cli/node_modules/yargs": { - "version": "17.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", - "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -2829,13 +3210,13 @@ } }, "node_modules/@wdio/concise-reporter": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/concise-reporter/-/concise-reporter-7.16.14.tgz", - "integrity": "sha512-CR+9+skJ3mXPIdRo0AnIJTJHOArrWdKlXTnyZ/DD6M9VrNk5aiTWQyphT/IeHV5+fxjHlMNIf/KgIhj1ewschQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/concise-reporter/-/concise-reporter-7.5.7.tgz", + "integrity": "sha512-964i7eQ4sboSla2bdR8714Er82QBgS6u39GmDFX8Izy9Ge38xaE75HuF5S7mnOWGzSojCWgqtwy5k7Rfg6GE3g==", "dev": true, "dependencies": { - "@wdio/reporter": "7.16.14", - "@wdio/types": "7.16.14", + "@wdio/reporter": "7.5.7", + "@wdio/types": "7.5.3", "chalk": "^4.0.0", "pretty-ms": "^7.0.0" }, @@ -2846,6 +3227,18 @@ "@wdio/cli": "^7.0.0" } }, + "node_modules/@wdio/concise-reporter/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@wdio/concise-reporter/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2895,6 +3288,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@wdio/concise-reporter/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/concise-reporter/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2908,13 +3310,13 @@ } }, "node_modules/@wdio/config": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.16.16.tgz", - "integrity": "sha512-K/ObPuo6Da2liz++OKOIfbdpFwI7UWiFcBylfJkCYbweuXCoW1aUqlKI6rmKPwCH9Uqr/RHWu6p8eo0zWe6xVA==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.5.3.tgz", + "integrity": "sha512-udvVizYoilOxuWj/BmoN6y7ZCd4wPdYNlSfWznrbCezAdaLZ4/pNDOO0WRWx2C4+q1wdkXZV/VuQPUGfL0lEHQ==", "dev": true, "dependencies": { - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", "deepmerge": "^4.0.0", "glob": "^7.1.2" }, @@ -2922,19 +3324,116 @@ "node": ">=12.0.0" } }, + "node_modules/@wdio/config/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/config/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/config/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wdio/config/node_modules/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 + }, + "node_modules/@wdio/config/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/local-runner": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.16.16.tgz", - "integrity": "sha512-AJaOyM842PWgMffrrXyHJjouVseLHoiL5U1sw2VVproi3ORWHbltl1AMnreU/lrGu9L0CVKHYT1pxu5UbSOCxQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.5.7.tgz", + "integrity": "sha512-aYc0XUV+/e3cg8Fp+CWlC4FbwSSG3mKAv1iuy/+Hwzg2kJE+aa+Rf2p2BQYc7HPRtKNW0bM8o+aCImZLAiPM+A==", "dev": true, "dependencies": { "@types/stream-buffers": "^3.0.3", - "@wdio/logger": "7.16.0", - "@wdio/repl": "7.16.14", - "@wdio/runner": "7.16.16", - "@wdio/types": "7.16.14", + "@wdio/logger": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/runner": "7.5.7", + "@wdio/types": "7.5.3", "async-exit-hook": "^2.0.1", - "split2": "^4.0.0", + "split2": "^3.2.2", "stream-buffers": "^3.0.2" }, "engines": { @@ -2944,6 +3443,103 @@ "@wdio/cli": "^7.0.0" } }, + "node_modules/@wdio/local-runner/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/local-runner/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/local-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/local-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/local-runner/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wdio/local-runner/node_modules/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 + }, + "node_modules/@wdio/local-runner/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/local-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/logger": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.16.0.tgz", @@ -3008,6 +3604,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@wdio/logger/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/logger/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3021,22 +3626,58 @@ } }, "node_modules/@wdio/mocha-framework": { - "version": "7.16.15", - "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.16.15.tgz", - "integrity": "sha512-XRya85/RYPZk4MZ7Cvl3oudTdrOo+RyO8b5Ff+dH8hD3GBCACaWgW9AjbsyhvbSTdUlF0gNLPdqOCsxV5XyM3w==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.5.3.tgz", + "integrity": "sha512-96QCVWsiyZxEgOZP3oTq2B2T7zne5dCdehLa2n4q/BLjk96Rj0jifidJZfd/1+vdNPKX0gWWAzpy98Znn8MVMw==", "dev": true, "dependencies": { - "@types/mocha": "^9.0.0", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", - "expect-webdriverio": "^3.0.0", - "mocha": "^9.0.0" + "@types/mocha": "^8.0.0", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "expect-webdriverio": "^2.0.0", + "mocha": "^8.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/@wdio/mocha-framework/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/@wdio/mocha-framework/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -3074,16 +3715,36 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@wdio/mocha-framework/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@wdio/mocha-framework/node_modules/chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" }, "engines": { - "node": ">=8" + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.1" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "node_modules/@wdio/mocha-framework/node_modules/color-convert": { @@ -3104,6 +3765,32 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@wdio/mocha-framework/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@wdio/mocha-framework/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/@wdio/mocha-framework/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3132,10 +3819,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@wdio/mocha-framework/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/mocha-framework/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", "dev": true, "dependencies": { "argparse": "^2.0.1" @@ -3160,19 +3876,15 @@ } }, "node_modules/@wdio/mocha-framework/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "chalk": "^4.0.0" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@wdio/mocha-framework/node_modules/minimatch": { @@ -3188,32 +3900,33 @@ } }, "node_modules/@wdio/mocha-framework/node_modules/mocha": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", - "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", "dev": true, "dependencies": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.3", + "chokidar": "3.5.1", + "debug": "4.3.1", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.2.0", + "glob": "7.1.6", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", "minimatch": "3.0.4", "ms": "2.1.3", - "nanoid": "3.2.0", - "serialize-javascript": "6.0.0", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", "which": "2.0.2", - "workerpool": "6.2.0", + "wide-align": "1.1.3", + "workerpool": "6.1.0", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" @@ -3223,23 +3936,38 @@ "mocha": "bin/mocha" }, "engines": { - "node": ">= 12.0.0" + "node": ">= 10.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mochajs" } }, - "node_modules/@wdio/mocha-framework/node_modules/ms": { + "node_modules/@wdio/mocha-framework/node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/@wdio/mocha-framework/node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/@wdio/mocha-framework/node_modules/nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -3278,13 +4006,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/mocha-framework/node_modules/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==", + "node_modules/@wdio/mocha-framework/node_modules/readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">=8" + "node": ">=8.10.0" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" } }, "node_modules/@wdio/mocha-framework/node_modules/strip-json-comments": { @@ -3299,6 +4039,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@wdio/mocha-framework/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, "node_modules/@wdio/mocha-framework/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -3327,75 +4085,347 @@ } }, "node_modules/@wdio/protocols": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.16.7.tgz", - "integrity": "sha512-Wv40pNQcLiPzQ3o98Mv4A8T1EBQ6k4khglz/e2r16CTm+F3DDYh8eLMAsU5cgnmuwwDKX1EyOiFwieykBn5MCg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.5.3.tgz", + "integrity": "sha512-lpNaKwxYhDSL6neDtQQYXvzMAw+u4PXx65ryeMEX82mkARgzSZps5Kyrg9ub7X4T17K1NPfnY6UhZEWg6cKJCg==", "dev": true, "engines": { "node": ">=12.0.0" } }, "node_modules/@wdio/repl": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.16.14.tgz", - "integrity": "sha512-Ezih0Y+lsGkKv3H3U56hdWgZiQGA3VaAYguSLd9+g1xbQq+zMKqSmfqECD9bAy+OgCCiVTRstES6lHZxJVPhAg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.5.3.tgz", + "integrity": "sha512-jfNJwNoc2nWdnLsFoGHmOJR9zaWfDTBMWM3W1eR5kXIjevD6gAfWsB5ZoA4IdybujCXxdnhlsm4o2jIzp/6f7A==", "dev": true, "dependencies": { - "@wdio/utils": "7.16.14" + "@wdio/utils": "7.5.3" }, "engines": { "node": ">=12.0.0" } }, "node_modules/@wdio/reporter": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.16.14.tgz", - "integrity": "sha512-e/I2oGfqjx9+zI4NT/garqxm7Afnos1EcrGSNu75WmP3PNJt4i+9DKkROu4PM6XWcpUB4v2UF7Mv/NrL3TU9aA==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.5.7.tgz", + "integrity": "sha512-9PXqZtCXDtU6UYLNDPu9MZQ8BiABGnRlJTrlbYB3gBfZDibMkJMvwXzPderipBv2+ifDZXmGe3Njf1ao2TkbFA==", "dev": true, "dependencies": { - "@types/diff": "^5.0.0", - "@types/node": "^17.0.4", - "@types/object-inspect": "^1.8.0", - "@types/supports-color": "^8.1.0", - "@types/tmp": "^0.2.0", - "@wdio/types": "7.16.14", - "diff": "^5.0.0", - "fs-extra": "^10.0.0", - "object-inspect": "^1.10.3", - "supports-color": "8.1.1" + "@wdio/types": "7.5.3", + "fs-extra": "^10.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/reporter/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" }, "engines": { "node": ">=12.0.0" } }, "node_modules/@wdio/runner": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.16.16.tgz", - "integrity": "sha512-Tt2ja6GukGPq1m98WP26yOWUGwzK1y7gPTLy6rKlamz3mOBC7koL0T9+iqcFREquUe4CMy2jWp1lqvPlwMbu7g==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.5.7.tgz", + "integrity": "sha512-RzVXd+xnwK/thkx1/xo9K5iscQ0Ofobgsx5dNVtwLDVMn9V7jCW/WX4dSCPAPaVSqnUCmkcQp3P5AoSBPpCZnQ==", "dev": true, "dependencies": { - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "deepmerge": "^4.0.0", "gaze": "^1.1.2", - "webdriver": "7.16.16", - "webdriverio": "7.16.16" + "webdriver": "7.5.3", + "webdriverio": "7.5.7" }, "engines": { "node": ">=12.0.0" } }, - "node_modules/@wdio/spec-reporter": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.19.1.tgz", - "integrity": "sha512-qnZkn3VcyBPtcorUtpyCFE8v5ubyWmR7mFETXNzyriHyvjvk+NeFCWaFcIehpXYXiAmNpAwyfnZoIY6tkKQixQ==", + "node_modules/@wdio/runner/node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "node_modules/@wdio/runner/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", "dev": true, "dependencies": { - "@types/easy-table": "^0.0.33", - "@wdio/reporter": "7.19.1", - "@wdio/types": "7.19.1", + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/runner/node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@wdio/runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/runner/node_modules/chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "dependencies": { + "@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" + } + }, + "node_modules/@wdio/runner/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/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 + }, + "node_modules/@wdio/runner/node_modules/devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "dependencies": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "dev": true + }, + "node_modules/@wdio/runner/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/runner/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/@wdio/runner/node_modules/puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "engines": { + "node": ">=10.18.1" + } + }, + "node_modules/@wdio/runner/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + }, + "node_modules/@wdio/runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/runner/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/runner/node_modules/webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", + "dev": true, + "dependencies": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "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", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@wdio/spec-reporter": { + "version": "7.19.7", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.19.7.tgz", + "integrity": "sha512-BDBZU2EK/GuC9VxtfqPtoW43FmvKxYDsvcDVDi3F7o+9fkcuGSJiWbw1AX251ZzzVQ7YP9ImTitSpdpUKXkilQ==", + "dev": true, + "dependencies": { + "@types/easy-table": "^0.0.33", + "@wdio/reporter": "7.19.7", + "@wdio/types": "7.19.5", "chalk": "^4.0.0", "easy-table": "^1.1.1", "pretty-ms": "^7.0.0" @@ -3408,9 +4438,9 @@ } }, "node_modules/@wdio/spec-reporter/node_modules/@wdio/reporter": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.19.1.tgz", - "integrity": "sha512-sWmBBV4dPCZkGk9Qq0m35T/vHGen0N10nH4osQcVP3IZJqpo2eLIH4w+X6EUbjZ2GdgOA2bLMMzb1bl9JqnGPg==", + "version": "7.19.7", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.19.7.tgz", + "integrity": "sha512-Dum19gpfru66FnIq78/4HTuW87B7ceLDp6PJXwQM5kXyN7Gb7zhMgp6FZTM0FCYLyi6U/zXZSvpNUYl77caS6g==", "dev": true, "dependencies": { "@types/diff": "^5.0.0", @@ -3418,7 +4448,7 @@ "@types/object-inspect": "^1.8.0", "@types/supports-color": "^8.1.0", "@types/tmp": "^0.2.0", - "@wdio/types": "7.19.1", + "@wdio/types": "7.19.5", "diff": "^5.0.0", "fs-extra": "^10.0.0", "object-inspect": "^1.10.3", @@ -3428,7 +4458,93 @@ "node": ">=12.0.0" } }, - "node_modules/@wdio/spec-reporter/node_modules/@wdio/reporter/node_modules/supports-color": { + "node_modules/@wdio/spec-reporter/node_modules/@wdio/types": { + "version": "7.19.5", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.19.5.tgz", + "integrity": "sha512-S1lC0pmtEO7NVH/2nM1c7NHbkgxLZH3VVG/z6ym3Bbxdtcqi2LMsEvvawMAU/fmhyiIkMsGZCO8vxG9cRw4z4A==", + "dev": true, + "dependencies": { + "@types/node": "^17.0.4", + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "^4.6.2" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/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 + }, + "node_modules/@wdio/spec-reporter/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", @@ -3443,23 +4559,57 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/@wdio/spec-reporter/node_modules/@wdio/types": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.19.1.tgz", - "integrity": "sha512-mOodKlmvYxpj8P5BhjggEGpXuiRSlsyn2ClG8QqJ3lfXgOtOVEzFNfv/Ai7TkHr+lHDQNXLjllCjSqoCHhwlqg==", + "node_modules/@wdio/sync": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-7.5.7.tgz", + "integrity": "sha512-Zu/AYLjwqbFSbaOU1US7ownv3ov8JrtoGHq51JfJ4masefJDXNkHix2cZ0qEgl3IvkkWQ0ewL0G8GTXb3KOemA==", "dev": true, "dependencies": { - "@types/node": "^17.0.4", - "got": "^11.8.1" + "@types/fibers": "^3.1.0", + "@types/puppeteer": "^5.4.0", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "fibers": "^5.0.0", + "webdriverio": "7.5.7" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "node_modules/@wdio/sync/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" }, "engines": { "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" }, - "peerDependencies": { - "typescript": "^4.6.2" + "engines": { + "node": ">=12.0.0" } }, - "node_modules/@wdio/spec-reporter/node_modules/ansi-styles": { + "node_modules/@wdio/sync/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -3474,7 +4624,20 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@wdio/spec-reporter/node_modules/chalk": { + "node_modules/@wdio/sync/node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@wdio/sync/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -3490,7 +4653,21 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@wdio/spec-reporter/node_modules/color-convert": { + "node_modules/@wdio/sync/node_modules/chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "dependencies": { + "@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" + } + }, + "node_modules/@wdio/sync/node_modules/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==", @@ -3502,13 +4679,91 @@ "node": ">=7.0.0" } }, - "node_modules/@wdio/spec-reporter/node_modules/color-name": { + "node_modules/@wdio/sync/node_modules/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 }, - "node_modules/@wdio/spec-reporter/node_modules/supports-color": { + "node_modules/@wdio/sync/node_modules/devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "dependencies": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "dev": true + }, + "node_modules/@wdio/sync/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/sync/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/@wdio/sync/node_modules/puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "engines": { + "node": ">=10.18.1" + } + }, + "node_modules/@wdio/sync/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + }, + "node_modules/@wdio/sync/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -3520,21 +4775,73 @@ "node": ">=8" } }, - "node_modules/@wdio/sync": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-7.16.16.tgz", - "integrity": "sha512-MbVFAteaAOxHLKkMiMzOnh1hzINAK2U41GDIfy1yaPumcw1pNuJIhWrBYxprNMlqt8srk++wqQWgj5XpFjCL6g==", + "node_modules/@wdio/sync/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/sync/node_modules/webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", "dev": true, "dependencies": { - "@types/fibers": "^3.1.0", - "@types/puppeteer": "^5.4.0", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "fibers": "^5.0.0", - "webdriverio": "7.16.16" + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "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", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" }, "engines": { - "node": ">=12.0.0 <16" + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/sync/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/@wdio/types": { @@ -3551,19 +4858,115 @@ } }, "node_modules/@wdio/utils": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.16.14.tgz", - "integrity": "sha512-wwin8nVpIlhmXJkq6GJw9aDDzgLOJKgXTcEua0T2sdXjoW78u5Ly/GZrFXTjMGhacFvoZfitTrjyfyy4CxMVvw==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.5.3.tgz", + "integrity": "sha512-nlLDKr8v8abLOHCKroBwQkGPdCIxjID2MllgWX23xqkYZylM9RdwPBdL8osQt9m3rq2TxiPAT4OlbzNt2WtN6Q==", "dev": true, "dependencies": { - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "p-iteration": "^1.1.8" + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/utils/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/@wdio/utils/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/utils/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wdio/utils/node_modules/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 + }, + "node_modules/@wdio/utils/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -3711,9 +5114,9 @@ } }, "node_modules/@xmldom/xmldom": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.6.tgz", - "integrity": "sha512-HHXP9hskkFQHy8QxxUXkS7946FFIhYVfGqsk0WLwllmexN9x/+R4UBLvurHEuyXRfVEObVR8APuQehykLviwSQ==", + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.8.tgz", + "integrity": "sha512-PrJx38EfpitFhwmILRl37jAdBlsww6AZ6rRVK4QS7T7RHLhX7mSs647sTmgr9GIxe3qjXdesmomEgbgaokrVFg==", "dev": true, "engines": { "node": ">=10.0.0" @@ -3734,7 +5137,7 @@ "node_modules/abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", "dev": true }, "node_modules/accepts": { @@ -3770,6 +5173,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/aes-decrypter": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz", @@ -3783,10 +5195,13 @@ } }, "node_modules/agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, + "dependencies": { + "debug": "4" + }, "engines": { "node": ">= 6.0.0" } @@ -3807,10 +5222,19 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, "node_modules/amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", "dev": true, "optional": true, "engines": { @@ -3818,9 +5242,9 @@ } }, "node_modules/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==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "engines": { "node": ">=6" @@ -3856,7 +5280,7 @@ "node_modules/ansi-gray": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", "dev": true, "dependencies": { "ansi-wrap": "0.1.0" @@ -3900,7 +5324,7 @@ "node_modules/ansi-wrap": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -3922,7 +5346,7 @@ "node_modules/append-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", "dev": true, "dependencies": { "buffer-equal": "^1.0.0" @@ -3932,13 +5356,13 @@ } }, "node_modules/archiver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz", - "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", "dev": true, "dependencies": { "archiver-utils": "^2.1.0", - "async": "^3.2.0", + "async": "^3.2.3", "buffer-crc32": "^0.2.1", "readable-stream": "^3.6.0", "readdir-glob": "^1.0.0", @@ -3971,9 +5395,9 @@ } }, "node_modules/archiver/node_modules/async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", "dev": true }, "node_modules/archiver/node_modules/readable-stream": { @@ -3993,7 +5417,7 @@ "node_modules/archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, "node_modules/argparse": { @@ -4006,18 +5430,31 @@ } }, "node_modules/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "dev": true, - "engines": { - "node": ">=6.0" + "dependencies": { + "deep-equal": "^2.0.5" } }, "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-diff/node_modules/array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4026,7 +5463,7 @@ "node_modules/arr-filter": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", "dev": true, "dependencies": { "make-iterator": "^1.0.0" @@ -4047,7 +5484,7 @@ "node_modules/arr-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", "dev": true, "dependencies": { "make-iterator": "^1.0.0" @@ -4057,9 +5494,9 @@ } }, "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4068,7 +5505,7 @@ "node_modules/array-differ": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4077,7 +5514,7 @@ "node_modules/array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4086,23 +5523,23 @@ "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/array-from": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==", "dev": true }, "node_modules/array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", "get-intrinsic": "^1.1.1", "is-string": "^1.0.7" }, @@ -4116,7 +5553,7 @@ "node_modules/array-initial": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", "dev": true, "dependencies": { "array-slice": "^1.0.0", @@ -4182,7 +5619,7 @@ "node_modules/array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4191,21 +5628,22 @@ "node_modules/array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -4238,7 +5676,7 @@ "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "engines": { "node": ">=0.8" @@ -4256,7 +5694,7 @@ "node_modules/assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4274,7 +5712,7 @@ "node_modules/async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", "dev": true }, "node_modules/async-done": { @@ -4310,7 +5748,7 @@ "node_modules/async-settle": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", "dev": true, "dependencies": { "async-done": "^1.2.2" @@ -4322,7 +5760,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "node_modules/atob": { @@ -4352,7 +5790,7 @@ "node_modules/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=", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, "engines": { "node": "*" @@ -4367,7 +5805,7 @@ "node_modules/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=", + "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", "dev": true, "dependencies": { "chalk": "^1.1.3", @@ -4378,7 +5816,7 @@ "node_modules/babel-code-frame/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4387,7 +5825,7 @@ "node_modules/babel-code-frame/node_modules/ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4396,7 +5834,7 @@ "node_modules/babel-code-frame/node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "dependencies": { "ansi-styles": "^2.2.1", @@ -4412,13 +5850,13 @@ "node_modules/babel-code-frame/node_modules/js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", "dev": true }, "node_modules/babel-code-frame/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -4430,7 +5868,7 @@ "node_modules/babel-code-frame/node_modules/supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "engines": { "node": ">=0.8.0" @@ -4475,7 +5913,7 @@ "node_modules/babel-core/node_modules/json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -4484,18 +5922,9 @@ "node_modules/babel-core/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/babel-core/node_modules/slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/babel-generator": { "version": "6.26.1", "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", @@ -4512,22 +5941,10 @@ "trim-right": "^1.0.1" } }, - "node_modules/babel-generator/node_modules/detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "dependencies": { - "repeating": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/babel-generator/node_modules/jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "integrity": "sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA==", "dev": true, "bin": { "jsesc": "bin/jsesc" @@ -4536,7 +5953,7 @@ "node_modules/babel-helpers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "integrity": "sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ==", "dev": true, "dependencies": { "babel-runtime": "^6.22.0", @@ -4544,13 +5961,13 @@ } }, "node_modules/babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", "dev": true, "dependencies": { "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", + "loader-utils": "^2.0.0", "make-dir": "^3.1.0", "schema-utils": "^2.6.5" }, @@ -4562,49 +5979,15 @@ "webpack": ">=2" } }, - "node_modules/babel-loader/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/babel-loader/node_modules/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, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/babel-messages": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==", "dev": true, "dependencies": { "babel-runtime": "^6.22.0" } }, - "node_modules/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==", - "dependencies": { - "object.assign": "^4.1.0" - } - }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -4621,29 +6004,13 @@ "node": ">=8" } }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", "semver": "^6.1.1" }, "peerDependencies": { @@ -4651,23 +6018,23 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.3.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -4676,7 +6043,7 @@ "node_modules/babel-register": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "integrity": "sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A==", "dev": true, "dependencies": { "babel-core": "^6.26.0", @@ -4708,19 +6075,10 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/babel-register/node_modules/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, - "dependencies": { - "source-map": "^0.5.6" - } - }, "node_modules/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=", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", "dev": true, "dependencies": { "core-js": "^2.4.0", @@ -4735,10 +6093,16 @@ "dev": true, "hasInstallScript": true }, + "node_modules/babel-runtime/node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, "node_modules/babel-template": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==", "dev": true, "dependencies": { "babel-runtime": "^6.26.0", @@ -4751,7 +6115,7 @@ "node_modules/babel-traverse": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==", "dev": true, "dependencies": { "babel-code-frame": "^6.26.0", @@ -4786,13 +6150,13 @@ "node_modules/babel-traverse/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/babel-types": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", "dev": true, "dependencies": { "babel-runtime": "^6.26.0", @@ -4804,7 +6168,7 @@ "node_modules/babel-types/node_modules/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=", + "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4822,7 +6186,7 @@ "node_modules/bach": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", "dev": true, "dependencies": { "arr-filter": "^1.1.1", @@ -4876,7 +6240,7 @@ "node_modules/base/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -4926,16 +6290,22 @@ "node": ">= 0.8" } }, + "node_modules/basic-auth/node_modules/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==", + "dev": true + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, "dependencies": { "tweetnacl": "^0.14.3" @@ -4944,7 +6314,7 @@ "node_modules/beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", + "integrity": "sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4971,7 +6341,7 @@ "node_modules/binary": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", "dev": true, "dependencies": { "buffers": "~0.1.1", @@ -5040,13 +6410,13 @@ "node_modules/bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", "dev": true }, "node_modules/body": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", "dev": true, "dependencies": { "continuable-cache": "^0.3.1", @@ -5056,23 +6426,26 @@ } }, "node_modules/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/body-parser/node_modules/debug": { @@ -5086,18 +6459,18 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/body/node_modules/bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", + "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", "dev": true }, "node_modules/body/node_modules/raw-body": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", - "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", + "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", "dev": true, "dependencies": { "bytes": "1", @@ -5110,7 +6483,7 @@ "node_modules/body/node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true }, "node_modules/brace-expansion": { @@ -5142,9 +6515,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "funding": [ { "type": "opencollective", @@ -5156,10 +6529,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" + "update-browserslist-db": "^1.0.9" }, "bin": { "browserslist": "cli.js" @@ -5178,12 +6551,13 @@ } }, "node_modules/browserstack-local": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.4.9.tgz", - "integrity": "sha512-V+q8HQwRQFr9nd32xR66ZZ3VDWa3Kct4IMMudhKgcuD7cWrvvFARZOibx71II+Rf7P5nMQpWWxl9z/3p927nbg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.5.1.tgz", + "integrity": "sha512-T/wxyWDzvBHbDvl7fZKpFU7mYze6nrUkBhNy+d+8bXBqgQX10HTYvajIGO0wb49oGSLCPM0CMZTV/s7e6LF0sA==", "dev": true, "dependencies": { - "https-proxy-agent": "^4.0.0", + "agent-base": "^6.0.2", + "https-proxy-agent": "^5.0.1", "is-running": "^2.1.0", "ps-tree": "=1.2.0", "temp-fs": "^0.9.9" @@ -5224,9 +6598,9 @@ } }, "node_modules/browserstacktunnel-wrapper": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.4.tgz", - "integrity": "sha512-GCV599FUUxNOCFl3WgPnfc5dcqq9XTmMXoxWpqkvmk0R9TOIoqmjENNU6LY6DtgIL6WfBVbg/jmWtnM5K6UYSg==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.5.tgz", + "integrity": "sha512-oociT3nl+FhQnyJbAb1RM4oQ5pN7aKeXEURkTkiEVm/Rji2r0agl3Wbw5V23VFn9lCU5/fGyDejRZPtGYsEcFw==", "dev": true, "dependencies": { "https-proxy-agent": "^2.2.1", @@ -5297,19 +6671,22 @@ "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, "engines": { "node": "*" } }, "node_modules/buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/buffer-from": { @@ -5330,7 +6707,7 @@ "node_modules/buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", "dev": true, "engines": { "node": ">=0.2.0" @@ -5347,7 +6724,7 @@ "node_modules/cac": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/cac/-/cac-3.0.4.tgz", - "integrity": "sha1-bSTO7Dcu/lybeYgIvH9JtHJCpO8=", + "integrity": "sha512-hq4rxE3NT5PlaEiVV39Z45d6MoFcQZG5dsgJqtAUeOz3408LEQAElToDkf9i5IYSCOmK0If/81dLg7nKxqPR0w==", "dev": true, "dependencies": { "camelcase-keys": "^3.0.0", @@ -5365,7 +6742,7 @@ "node_modules/cac/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5374,38 +6751,16 @@ "node_modules/cac/node_modules/ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/cac/node_modules/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, - "dependencies": { - "camelcase": "^3.0.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cac/node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "dependencies": { "ansi-styles": "^2.2.1", @@ -5421,7 +6776,7 @@ "node_modules/cac/node_modules/find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "dependencies": { "path-exists": "^2.0.0", @@ -5431,19 +6786,28 @@ "node": ">=0.10.0" } }, - "node_modules/cac/node_modules/indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "node_modules/cac/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/cac/node_modules/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, - "engines": { - "node": ">=4" + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "node_modules/cac/node_modules/path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, "dependencies": { "pinkie-promise": "^2.0.0" @@ -5455,7 +6819,7 @@ "node_modules/cac/node_modules/read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "dependencies": { "load-json-file": "^1.0.0", @@ -5469,7 +6833,7 @@ "node_modules/cac/node_modules/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=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "dependencies": { "find-up": "^1.0.0", @@ -5479,10 +6843,19 @@ "node": ">=0.10.0" } }, + "node_modules/cac/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/cac/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -5494,7 +6867,7 @@ "node_modules/cac/node_modules/supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "engines": { "node": ">=0.8.0" @@ -5592,6 +6965,28 @@ "node": ">=6" } }, + "node_modules/camelcase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-3.0.0.tgz", + "integrity": "sha512-U4E6A6aFyYnNW+tDt5/yIUKQURKXe3WMFPfX4FxrQFcwZ/R08AUk1xWcUtlr7oq6CV07Ji+aa69V2g7BSpblnQ==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/can-autoplay": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/can-autoplay/-/can-autoplay-3.0.2.tgz", @@ -5599,9 +6994,9 @@ "dev": true }, "node_modules/caniuse-lite": { - "version": "1.0.30001390", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001390.tgz", - "integrity": "sha512-sS4CaUM+/+vqQUlCvCJ2WtDlV81aWtHhqeEVkLokVJJa3ViN4zDxAGfq9R8i1m90uGHxo99cy10Od+lvn3hf0g==", + "version": "1.0.30001429", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz", + "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==", "funding": [ { "type": "opencollective", @@ -5616,7 +7011,7 @@ "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "node_modules/ccount": { @@ -5650,7 +7045,7 @@ "node_modules/chainsaw": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", "dev": true, "dependencies": { "traverse": ">=0.3.0 <0.4" @@ -5672,25 +7067,6 @@ "node": ">=4" } }, - "node_modules/chalk/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -5730,7 +7106,7 @@ "node_modules/check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", "dev": true, "engines": { "node": "*" @@ -5770,9 +7146,9 @@ "dev": true }, "node_modules/chrome-launcher": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.0.tgz", - "integrity": "sha512-ZQqX5kb9H0+jy1OqLnWampfocrtSZaGl7Ny3F9GRha85o4odbL8x55paUzh51UC7cEmZ5obp3H2Mm70uC2PpRA==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.1.tgz", + "integrity": "sha512-UugC8u59/w2AyX5sHLZUHoxBAiSiunUhZa3zZwMH6zPVis0C3dDKiRWyUGIo14tTbZHGVviWxv3PQWZ7taZ4fg==", "dev": true, "dependencies": { "@types/node": "*", @@ -5823,10 +7199,19 @@ "node": ">=0.10.0" } }, + "node_modules/class-utils/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/class-utils/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -5838,7 +7223,7 @@ "node_modules/class-utils/node_modules/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=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -5850,7 +7235,7 @@ "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -5868,7 +7253,7 @@ "node_modules/class-utils/node_modules/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=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -5880,7 +7265,7 @@ "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -5916,9 +7301,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", "dev": true, "engines": { "node": ">=6" @@ -5937,20 +7322,23 @@ } }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", "dev": true, "engines": { "node": ">=0.8" @@ -5959,25 +7347,28 @@ "node_modules/clone-buffer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", "dev": true, "engines": { "node": ">= 0.10" } }, "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "dev": true, "dependencies": { "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/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=", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", "dev": true }, "node_modules/cloneable-readable": { @@ -5994,7 +7385,7 @@ "node_modules/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=", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -6003,7 +7394,7 @@ "node_modules/collection-map": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", "dev": true, "dependencies": { "arr-map": "^2.0.2", @@ -6017,7 +7408,7 @@ "node_modules/collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dev": true, "dependencies": { "map-visit": "^1.0.0", @@ -6038,7 +7429,7 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/color-support": { "version": "1.1.3", @@ -6080,10 +7471,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/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 + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, "node_modules/component-emitter": { @@ -6124,7 +7521,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "node_modules/concat-stream": { @@ -6193,12 +7590,51 @@ "ms": "2.0.0" } }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -6210,25 +7646,6 @@ "node": ">= 0.6" } }, - "node_modules/content-disposition/node_modules/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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -6240,21 +7657,18 @@ "node_modules/continuable-cache": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", - "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", + "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", "dev": true }, "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dependencies": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "engines": { "node": ">= 0.6" } @@ -6262,12 +7676,12 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -6284,10 +7698,9 @@ } }, "node_modules/core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz", + "integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -6295,31 +7708,21 @@ } }, "node_modules/core-js-compat": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", - "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", "dependencies": { - "browserslist": "^4.19.1", - "semver": "7.0.0" + "browserslist": "^4.21.4" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/core-js-pure": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", - "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==", - "deprecated": "core-js-pure@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js-pure.", + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz", + "integrity": "sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -6365,14 +7768,10 @@ } }, "node_modules/crc-32": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.1.tgz", - "integrity": "sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "dev": true, - "dependencies": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.3.1" - }, "bin": { "crc32": "bin/crc32.njs" }, @@ -6460,7 +7859,7 @@ "node_modules/css-value": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", - "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=", + "integrity": "sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==", "dev": true }, "node_modules/css/node_modules/source-map": { @@ -6475,7 +7874,7 @@ "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true }, "node_modules/d": { @@ -6491,7 +7890,7 @@ "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" @@ -6501,9 +7900,9 @@ } }, "node_modules/date-format": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.4.tgz", - "integrity": "sha512-/jyf4rhB17ge328HJuJjAcmRtCsGd+NDeAtahRBTaK6vSPR6MO5HlrAit3Nn7dVjaa6sowW0WXt8yQtLyZQFRg==", + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, "engines": { "node": ">=4.0" @@ -6512,7 +7911,7 @@ "node_modules/dateformat": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", + "integrity": "sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==", "dev": true, "engines": { "node": "*" @@ -6526,9 +7925,9 @@ "optional": true }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -6562,12 +7961,15 @@ } }, "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/decode-named-character-reference": { @@ -6586,7 +7988,7 @@ "node_modules/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=", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", "dev": true, "engines": { "node": ">=0.10" @@ -6687,25 +8089,28 @@ "node_modules/default-resolution": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", "dev": true, "engines": { "node": ">= 0.10" } }, "node_modules/defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, "dependencies": { "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/defaults/node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, "engines": { "node": ">=0.8" @@ -6721,14 +8126,19 @@ } }, "node_modules/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==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, "dependencies": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-property": { @@ -6747,18 +8157,18 @@ "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "engines": { "node": ">=0.4.0" } }, "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/dequal": { @@ -6771,23 +8181,39 @@ } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, "node_modules/detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==", + "dev": true, + "dependencies": { + "repeating": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true, "bin": { "detect-libc": "bin/detect-libc.js" @@ -6799,46 +8225,237 @@ "node_modules/detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/devtools": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", - "integrity": "sha512-M0kzkuSgfEhpqIis3gdtWsNjn/HQ+vRAmEzDnbYx/7FfjFxhSv1d+rOOT20pvd60soItMYpsOova1igACEGkGQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.25.4.tgz", + "integrity": "sha512-R6/S/dCqxoX4Y6PxIGM9JFAuSRZzUeV5r+CoE/frhmno6mTe7dEEgwkJlfit3LkKRoul8n4DsL2A3QtWOvq5IA==", "dev": true, "dependencies": { - "@types/node": "^17.0.4", + "@types/node": "^18.0.0", "@types/ua-parser-js": "^0.7.33", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", "chrome-launcher": "^0.15.0", "edge-paths": "^2.1.0", "puppeteer-core": "^13.1.3", "query-selector-shadow-dom": "^1.0.0", "ua-parser-js": "^1.0.1", - "uuid": "^8.0.0" + "uuid": "^9.0.0" }, "engines": { "node": ">=12.0.0" } }, "node_modules/devtools-protocol": { - "version": "0.0.973690", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.973690.tgz", - "integrity": "sha512-myh3hSFp0YWa2GED11PmbLhV4dv9RdO7YUz27XJrbQLnP5bMbZL6dfOOILTHO57yH0kX5GfuOZBsg/4NamfPvQ==", + "version": "0.0.1061995", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1061995.tgz", + "integrity": "sha512-pKZZWTjWa/IF4ENCg6GN8bu/AxSZgdhjSa26uc23wz38Blt2Tnm9icOPcSG3Cht55rMq35in1w3rWVPcZ60ArA==", + "dev": true + }, + "node_modules/devtools/node_modules/@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", "dev": true }, + "node_modules/devtools/node_modules/@wdio/config": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.25.4.tgz", + "integrity": "sha512-vb0emDtD9FbFh/yqW6oNdo2iuhQp8XKj6GX9fyy9v4wZgg3B0HPMVJxhIfcoHz7LMBWlHSo9YdvhFI5EQHRLBA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "deepmerge": "^4.0.0", + "glob": "^8.0.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/devtools/node_modules/@wdio/logger": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.19.0.tgz", + "integrity": "sha512-xR7SN/kGei1QJD1aagzxs3KMuzNxdT/7LYYx+lt6BII49+fqL/SO+5X0FDCZD0Ds93AuQvvz9eGyzrBI2FFXmQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/devtools/node_modules/@wdio/protocols": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.22.0.tgz", + "integrity": "sha512-8EXRR+Ymdwousm/VGtW3H1hwxZ/1g1H99A1lF0U4GuJ5cFWHCd0IVE5H31Z52i8ZruouW8jueMkGZPSo2IIUSQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/devtools/node_modules/@wdio/types": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.25.4.tgz", + "integrity": "sha512-muvNmq48QZCvocctnbe0URq2FjJjUPIG4iLoeMmyF0AQgdbjaUkMkw3BHYNHVTbSOU9WMsr2z8alhj/I2H6NRQ==", + "dev": true, + "dependencies": { + "@types/node": "^18.0.0", + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "^4.6.2" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/devtools/node_modules/@wdio/utils": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.25.4.tgz", + "integrity": "sha512-8iwQDk+foUqSzKZKfhLxjlCKOkfRJPNHaezQoevNgnrTq/t0ek+ldZCATezb9B8jprAuP4mgS9xi22akc6RkzA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "p-iteration": "^1.1.8" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/devtools/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/devtools/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/devtools/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/devtools/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/devtools/node_modules/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 + }, + "node_modules/devtools/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/devtools/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/devtools/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/devtools/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/devtools/node_modules/ua-parser-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", - "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==", + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", + "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", "dev": true, "funding": [ { @@ -6855,9 +8472,9 @@ } }, "node_modules/devtools/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "dev": true, "bin": { "uuid": "dist/bin/uuid" @@ -6866,25 +8483,25 @@ "node_modules/di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", "dev": true, "engines": { "node": ">=0.3.1" } }, "node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/dlv": { @@ -6987,9 +8604,9 @@ } }, "node_modules/documentation/node_modules/chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz", + "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -6998,15 +8615,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/documentation/node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/documentation/node_modules/glob": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", @@ -7026,15 +8634,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/documentation/node_modules/ini": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/documentation/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -7059,25 +8658,13 @@ "node": ">=10" } }, - "node_modules/documentation/node_modules/strip-json-comments": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", - "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/documentation/node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -7092,7 +8679,7 @@ "node_modules/dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "dependencies": { "custom-event": "~1.0.0", @@ -7122,14 +8709,38 @@ "dev": true }, "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", "dev": true, "dependencies": { - "readable-stream": "^2.0.2" + "readable-stream": "~1.1.9" + } + }, + "node_modules/duplexer2/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" } }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, "node_modules/duplexify": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", @@ -7199,7 +8810,7 @@ "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "dependencies": { "jsbn": "~0.1.0", @@ -7219,7 +8830,7 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/ejs": { "version": "3.1.8", @@ -7237,14 +8848,14 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.243", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.243.tgz", - "integrity": "sha512-BgLD2gBX43OSXwlT01oYRRD5NIB4n3okTRxkzEAC6G0SZG4TTlyrWMjbOo0fajCwqwpRtMHXQNMjtRN6qpNtfw==" + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" }, "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "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 }, "node_modules/emojis-list": { @@ -7259,7 +8870,7 @@ "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "engines": { "node": ">= 0.8" } @@ -7274,9 +8885,9 @@ } }, "node_modules/engine.io": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", - "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", "dev": true, "dependencies": { "@types/cookie": "^0.4.1", @@ -7295,21 +8906,27 @@ } }, "node_modules/engine.io-parser": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", - "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", "dev": true, - "dependencies": { - "@socket.io/base64-arraybuffer": "~1.0.2" - }, "engines": { "node": ">=10.0.0" } }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/enhanced-resolve": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", - "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -7334,7 +8951,7 @@ "node_modules/ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", "dev": true }, "node_modules/errno": { @@ -7368,31 +8985,35 @@ } }, "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7426,6 +9047,15 @@ "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -7459,9 +9089,9 @@ } }, "node_modules/es5-shim": { - "version": "4.6.5", - "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.5.tgz", - "integrity": "sha512-vfQ4UAai8szn0sAubCy97xnZ4sJVDD1gt/Grn736hg8D7540wemIb1YPrYZSTqlM2H69EQX1or4HU/tSwRTI3w==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.7.tgz", + "integrity": "sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==", "dev": true, "engines": { "node": ">=0.4.0" @@ -7470,7 +9100,7 @@ "node_modules/es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", "dev": true, "dependencies": { "d": "1", @@ -7481,7 +9111,7 @@ "node_modules/es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", "dev": true }, "node_modules/es6-promise": { @@ -7493,7 +9123,7 @@ "node_modules/es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "dev": true, "dependencies": { "es6-promise": "^4.0.3" @@ -7532,12 +9162,12 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/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=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { "node": ">=0.8.0" } @@ -7545,7 +9175,7 @@ "node_modules/escodegen": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", "dev": true, "dependencies": { "esprima": "^2.7.1", @@ -7567,7 +9197,7 @@ "node_modules/escodegen/node_modules/estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -7576,7 +9206,7 @@ "node_modules/escodegen/node_modules/levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dev": true, "dependencies": { "prelude-ls": "~1.1.2", @@ -7606,7 +9236,7 @@ "node_modules/escodegen/node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -7615,7 +9245,7 @@ "node_modules/escodegen/node_modules/source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", "dev": true, "optional": true, "dependencies": { @@ -7628,7 +9258,7 @@ "node_modules/escodegen/node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "dev": true, "dependencies": { "prelude-ls": "~1.1.2" @@ -7697,7 +9327,7 @@ "node_modules/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=", + "integrity": "sha512-UkFojTV1o0GOe1edOEiuI5ccYLJSuNngtqSeClNzhsmG8KPJ+7mRxgtp2oYhqZAK/brlXMoCd+VgXViE0AfyKw==", "dev": true, "peerDependencies": { "eslint": ">=3.19.0", @@ -7727,16 +9357,20 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "debug": "^3.2.7" }, "engines": { "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, "node_modules/eslint-module-utils/node_modules/debug": { @@ -7768,9 +9402,9 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "dependencies": { "array-includes": "^3.1.4", @@ -7778,14 +9412,14 @@ "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "engines": { "node": ">=4" @@ -7818,7 +9452,7 @@ "node_modules/eslint-plugin-import/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/eslint-plugin-node": { @@ -7930,22 +9564,6 @@ "@babel/highlight": "^7.10.4" } }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -8008,9 +9626,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -8022,10 +9640,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -8099,7 +9726,7 @@ "node_modules/esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", "dev": true, "bin": { "esparse": "bin/esparse.js", @@ -8178,7 +9805,7 @@ "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "engines": { "node": ">= 0.6" } @@ -8186,7 +9813,7 @@ "node_modules/event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", "dev": true, "dependencies": { "d": "1", @@ -8196,7 +9823,7 @@ "node_modules/event-stream": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==", "dev": true, "dependencies": { "duplexer": "~0.1.1", @@ -8211,7 +9838,7 @@ "node_modules/event-stream/node_modules/map-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==", "dev": true }, "node_modules/eventemitter3": { @@ -8266,7 +9893,7 @@ "node_modules/execa/node_modules/path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, "engines": { "node": ">=4" @@ -8284,7 +9911,7 @@ "node_modules/execa/node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "dependencies": { "shebang-regex": "^1.0.0" @@ -8296,7 +9923,7 @@ "node_modules/execa/node_modules/shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -8314,19 +9941,10 @@ "which": "bin/which" } }, - "node_modules/exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "dev": true, "dependencies": { "debug": "^2.3.3", @@ -8353,7 +9971,7 @@ "node_modules/expand-brackets/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -8365,7 +9983,7 @@ "node_modules/expand-brackets/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -8377,7 +9995,7 @@ "node_modules/expand-brackets/node_modules/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=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -8389,7 +10007,7 @@ "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -8407,7 +10025,7 @@ "node_modules/expand-brackets/node_modules/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=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -8419,7 +10037,7 @@ "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -8445,7 +10063,7 @@ "node_modules/expand-brackets/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -8454,13 +10072,13 @@ "node_modules/expand-brackets/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, "dependencies": { "homedir-polyfill": "^1.0.1" @@ -8470,62 +10088,98 @@ } }, "node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/expect-webdriverio": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-3.1.4.tgz", - "integrity": "sha512-65FTS3bmxcIp0cq6fLb/72TrCQXBCpwPLC7SwMWdpPlLq461mXcK1BPKJJjnIC587aXSKD+3E4hvnlCtwDmXfg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-2.0.2.tgz", + "integrity": "sha512-dst0tqP1aZ2p7TPmbatqoIQ+7hRTw+IeKNi830XxKhu2DNNe5vQ85i9ttf9rpXgbnUf91HxKcocn4G7A5bQxDA==", "dev": true, "dependencies": { - "expect": "^27.0.2", - "jest-matcher-utils": "^27.0.2" + "expect": "^26.6.2", + "jest-matcher-utils": "^26.6.2" } }, + "node_modules/expect/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/expect/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/expect/node_modules/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 + }, "node_modules/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.2", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.2", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.9.7", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.18.0", + "serve-static": "1.15.0", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -8545,40 +10199,21 @@ "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/express/node_modules/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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", "dev": true, "dependencies": { - "type": "^2.5.0" + "type": "^2.7.2" } }, "node_modules/ext/node_modules/type": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", - "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", "dev": true }, "node_modules/extend": { @@ -8588,18 +10223,26 @@ "dev": true }, "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", "dev": true, "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "kind-of": "^1.1.0" }, "engines": { "node": ">=0.10.0" } }, + "node_modules/extend-shallow/node_modules/kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -8614,18 +10257,6 @@ "node": ">=4" } }, - "node_modules/external-editor/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -8648,7 +10279,7 @@ "node_modules/extglob/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -8660,7 +10291,7 @@ "node_modules/extglob/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -8672,7 +10303,7 @@ "node_modules/extglob/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -8716,7 +10347,7 @@ "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, "engines": [ "node >=0.6.0" @@ -8758,13 +10389,13 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "node_modules/faye-websocket": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", "dev": true, "dependencies": { "websocket-driver": ">=0.5.1" @@ -8776,16 +10407,16 @@ "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "dependencies": { "pend": "~1.2.0" } }, "node_modules/fibers": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.1.tgz", - "integrity": "sha512-VMC7Frt87Oo0AOJ6EcPFbi+tZmkQ4tD85aatwyWL6I9cYMJmm2e+pXUJsfGZ36U7MffXtjou2XIiWJMtHriErw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.3.tgz", + "integrity": "sha512-/qYTSoZydQkM21qZpGLDLuCq8c+B8KhuCQ1kLPvnRNhxhVbvrpmH9l2+Lblf5neDuEsY4bfT7LeO553TXQDvJw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -8872,16 +10503,16 @@ } }, "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { @@ -8899,7 +10530,7 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/find-cache-dir": { "version": "3.3.2", @@ -8919,15 +10550,16 @@ } }, "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { - "locate-path": "^2.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/findup-sync": { @@ -8945,6 +10577,182 @@ "node": ">= 0.10" } }, + "node_modules/findup-sync/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/braces/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/fill-range/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/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 + }, + "node_modules/findup-sync/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fined": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", @@ -9005,9 +10813,9 @@ } }, "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "node_modules/flush-write-stream": { @@ -9021,9 +10829,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "dev": true, "funding": [ { @@ -9040,10 +10848,19 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9052,7 +10869,7 @@ "node_modules/for-own": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", "dev": true, "dependencies": { "for-in": "^1.0.1" @@ -9061,22 +10878,16 @@ "node": ">=0.10.0" } }, - "node_modules/foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, "node_modules/foreachasync": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", - "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=", + "integrity": "sha512-J+ler7Ta54FwwNcx6wQRDhTIbNeyDcARMkOcguEqnEdtm0jKvN3Li3PDAb2Du3ubJYEWfYL83XMROXdsXAXycw==", "dev": true }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, "engines": { "node": "*" @@ -9085,7 +10896,7 @@ "node_modules/fork-stream": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", - "integrity": "sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=", + "integrity": "sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==", "dev": true }, "node_modules/form-data": { @@ -9113,7 +10924,7 @@ "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "dev": true, "dependencies": { "map-cache": "^0.2.2" @@ -9125,7 +10936,7 @@ "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "engines": { "node": ">= 0.6" } @@ -9133,7 +10944,7 @@ "node_modules/from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", "dev": true }, "node_modules/fs-constants": { @@ -9143,9 +10954,9 @@ "dev": true }, "node_modules/fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -9159,7 +10970,7 @@ "node_modules/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=", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", "dev": true, "dependencies": { "graceful-fs": "^4.1.11", @@ -9182,7 +10993,7 @@ "node_modules/fs.extra": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz", - "integrity": "sha1-3QI/kwE77iRTHxszUUw3sg/ZM0k=", + "integrity": "sha512-Ig401VXtyrWrz23k9KxAx9OrnL8AHSLNhQ8YJH2wSYuH0ZUfxwBeY6zXkd/oOyVRFTlpEu/0n5gHeuZt7aqbkw==", "dev": true, "dependencies": { "fs-extra": "~0.6.1", @@ -9196,7 +11007,7 @@ "node_modules/fs.extra/node_modules/fs-extra": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz", - "integrity": "sha1-9G8MdbeEH40gCzNIzU1pHVoJnRU=", + "integrity": "sha512-5rU898vl/Z948L+kkJedbmo/iltzmiF5bn/eEk0j/SgrPpI+Ydau9xlJPicV7Av2CHYBGz5LAlwTnBU80j1zPQ==", "dev": true, "dependencies": { "jsonfile": "~1.0.1", @@ -9208,20 +11019,20 @@ "node_modules/fs.extra/node_modules/jsonfile": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz", - "integrity": "sha1-6l7+QLg2kLmGZ2FKc5L8YOhCwN0=", + "integrity": "sha512-KbsDJNRfRPF5v49tMNf9sqyyGqGLBcz1v5kZT01kG5ns5mQSltwxCKVmUzVKtEinkUnTDtSrp6ngWpV7Xw0ZlA==", "dev": true }, "node_modules/fs.extra/node_modules/mkdirp": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", "dev": true }, "node_modules/fs.extra/node_modules/rimraf": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", "dev": true, "bin": { "rimraf": "bin.js" @@ -9230,7 +11041,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "node_modules/fsevents": { @@ -9262,12 +11073,12 @@ } }, "node_modules/fstream/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -9298,12 +11109,39 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/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=", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "dev": true }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gaze": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", @@ -9336,20 +11174,20 @@ "node_modules/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=", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", "dev": true, "engines": { "node": "*" } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9407,7 +11245,7 @@ "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9416,7 +11254,7 @@ "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" @@ -9448,15 +11286,15 @@ "dev": true }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -9513,7 +11351,7 @@ "node_modules/glob-stream/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -9559,7 +11397,7 @@ "node_modules/glob-watcher/node_modules/anymatch/node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -9568,6 +11406,15 @@ "node": ">=0.10.0" } }, + "node_modules/glob-watcher/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/glob-watcher/node_modules/binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -9624,7 +11471,7 @@ "node_modules/glob-watcher/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -9636,7 +11483,7 @@ "node_modules/glob-watcher/node_modules/fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "dev": true, "dependencies": { "extend-shallow": "^2.0.1", @@ -9680,7 +11527,7 @@ "node_modules/glob-watcher/node_modules/glob-parent/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -9692,7 +11539,7 @@ "node_modules/glob-watcher/node_modules/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=", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", "dev": true, "dependencies": { "binary-extensions": "^1.0.0" @@ -9701,10 +11548,110 @@ "node": ">=0.10.0" } }, + "node_modules/glob-watcher/node_modules/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 + }, "node_modules/glob-watcher/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/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, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/micromatch/node_modules/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, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-watcher/node_modules/micromatch/node_modules/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, "engines": { "node": ">=0.10.0" @@ -9727,7 +11674,7 @@ "node_modules/glob-watcher/node_modules/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=", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, "dependencies": { "is-number": "^3.0.0", @@ -9764,7 +11711,7 @@ "node_modules/global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", "dev": true, "dependencies": { "expand-tilde": "^2.0.2", @@ -9777,6 +11724,12 @@ "node": ">=0.10.0" } }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/global-prefix/node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -9804,13 +11757,13 @@ "dev": true }, "node_modules/globule": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz", - "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", "dev": true, "dependencies": { "glob": "~7.1.1", - "lodash": "~4.17.10", + "lodash": "^4.17.21", "minimatch": "~3.0.2" }, "engines": { @@ -9887,9 +11840,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/grapheme-splitter": { @@ -9941,74 +11894,6 @@ "node": ">=0.9" } }, - "node_modules/gulp-clean/node_modules/arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", - "dev": true, - "dependencies": { - "kind-of": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-clean/node_modules/plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/gulp-clean/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -10078,7 +11963,7 @@ "node_modules/gulp-cli/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -10087,7 +11972,7 @@ "node_modules/gulp-cli/node_modules/camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -10096,7 +11981,7 @@ "node_modules/gulp-cli/node_modules/cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", "dev": true, "dependencies": { "string-width": "^1.0.1", @@ -10104,10 +11989,19 @@ "wrap-ansi": "^2.0.0" } }, + "node_modules/gulp-cli/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-cli/node_modules/find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "dependencies": { "path-exists": "^2.0.0", @@ -10123,10 +12017,16 @@ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, + "node_modules/gulp-cli/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, "node_modules/gulp-cli/node_modules/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=", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "dev": true, "dependencies": { "number-is-nan": "^1.0.0" @@ -10135,10 +12035,22 @@ "node": ">=0.10.0" } }, + "node_modules/gulp-cli/node_modules/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, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "node_modules/gulp-cli/node_modules/path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, "dependencies": { "pinkie-promise": "^2.0.0" @@ -10150,7 +12062,7 @@ "node_modules/gulp-cli/node_modules/read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "dependencies": { "load-json-file": "^1.0.0", @@ -10164,7 +12076,7 @@ "node_modules/gulp-cli/node_modules/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=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "dependencies": { "find-up": "^1.0.0", @@ -10174,16 +12086,19 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/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 + "node_modules/gulp-cli/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } }, "node_modules/gulp-cli/node_modules/string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dev": true, "dependencies": { "code-point-at": "^1.0.0", @@ -10197,7 +12112,7 @@ "node_modules/gulp-cli/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -10206,16 +12121,10 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/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 - }, "node_modules/gulp-cli/node_modules/wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", "dev": true, "dependencies": { "string-width": "^1.0.1", @@ -10265,7 +12174,7 @@ "node_modules/gulp-concat": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", - "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", + "integrity": "sha512-a2scActrQrDBpBbR3WUZGyGS1JEPLg5PZJdIa7/Bi3GuKAmPYDK6SFhy/NZq5R8KsKKFvtfR0fakbUCcKGCCjg==", "dev": true, "dependencies": { "concat-with-sourcemaps": "^1.0.0", @@ -10324,10 +12233,25 @@ "ms": "2.0.0" } }, + "node_modules/gulp-connect/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/gulp-connect/node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "dev": true + }, "node_modules/gulp-connect/node_modules/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=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "dependencies": { "depd": "~1.1.2", @@ -10342,7 +12266,7 @@ "node_modules/gulp-connect/node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "node_modules/gulp-connect/node_modules/mime": { @@ -10357,9 +12281,21 @@ "node_modules/gulp-connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/gulp-connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/gulp-connect/node_modules/send": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", @@ -10410,6 +12346,18 @@ "plugin-error": "^1.0.1" } }, + "node_modules/gulp-eslint/node_modules/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, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-eslint/node_modules/ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -10419,6 +12367,24 @@ "node": ">=6" } }, + "node_modules/gulp-eslint/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-eslint/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-eslint/node_modules/astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -10552,22 +12518,6 @@ "node": ">=4" } }, - "node_modules/gulp-eslint/node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/gulp-eslint/node_modules/eslint/node_modules/strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -10594,6 +12544,19 @@ "node": ">=6.0.0" } }, + "node_modules/gulp-eslint/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-eslint/node_modules/file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", @@ -10641,6 +12604,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gulp-eslint/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/gulp-eslint/node_modules/inquirer": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", @@ -10756,6 +12728,21 @@ "node": ">=4" } }, + "node_modules/gulp-eslint/node_modules/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, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/gulp-eslint/node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -10786,18 +12773,6 @@ "rimraf": "bin.js" } }, - "node_modules/gulp-eslint/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, "node_modules/gulp-eslint/node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -10955,7 +12930,7 @@ "node_modules/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=", + "integrity": "sha512-F+53crhLb78CTlG7ZZJFWzP0+/4q0vt2/pULXFkTMs6AGBo0Eh5cx+eWsqqHv8hrNIUsuTab3Se8rOOzP/6+EQ==", "dev": true, "dependencies": { "through2": "^0.6.3" @@ -10964,13 +12939,13 @@ "node_modules/gulp-js-escape/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "node_modules/gulp-js-escape/node_modules/readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", "dev": true, "dependencies": { "core-util-is": "~1.0.0", @@ -10982,13 +12957,13 @@ "node_modules/gulp-js-escape/node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true }, "node_modules/gulp-js-escape/node_modules/through2": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", "dev": true, "dependencies": { "readable-stream": ">=1.0.33-1 <1.1.0-0", @@ -11021,9 +12996,9 @@ } }, "node_modules/gulp-replace/node_modules/@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", + "version": "14.18.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", + "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", "dev": true }, "node_modules/gulp-shell": { @@ -11043,6 +13018,18 @@ "node": ">=10.0.0" } }, + "node_modules/gulp-shell/node_modules/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, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-shell/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -11058,6 +13045,24 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/gulp-shell/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-shell/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gulp-shell/node_modules/chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -11089,6 +13094,43 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/gulp-shell/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-shell/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/gulp-shell/node_modules/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, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/gulp-shell/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -11179,6 +13221,64 @@ "node": ">=10" } }, + "node_modules/gulp-terser/node_modules/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, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-terser/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-terser/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-terser/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-terser/node_modules/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, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/gulp-util": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", @@ -11212,7 +13312,7 @@ "node_modules/gulp-util/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -11221,7 +13321,7 @@ "node_modules/gulp-util/node_modules/ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -11230,7 +13330,7 @@ "node_modules/gulp-util/node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "dependencies": { "ansi-styles": "^2.2.1", @@ -11246,7 +13346,7 @@ "node_modules/gulp-util/node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, "engines": { "node": ">=0.8" @@ -11255,18 +13355,9 @@ "node_modules/gulp-util/node_modules/clone-stats": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", "dev": true }, - "node_modules/gulp-util/node_modules/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, - "dependencies": { - "lodash._root": "^3.0.0" - } - }, "node_modules/gulp-util/node_modules/lodash.template": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", @@ -11287,7 +13378,7 @@ "node_modules/gulp-util/node_modules/lodash.templatesettings": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "integrity": "sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ==", "dev": true, "dependencies": { "lodash._reinterpolate": "^3.0.0", @@ -11297,7 +13388,7 @@ "node_modules/gulp-util/node_modules/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=", + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -11306,7 +13397,7 @@ "node_modules/gulp-util/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -11318,7 +13409,7 @@ "node_modules/gulp-util/node_modules/supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "engines": { "node": ">=0.8.0" @@ -11337,7 +13428,7 @@ "node_modules/gulp-util/node_modules/vinyl": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "integrity": "sha512-P5zdf3WB9uzr7IFoVQ2wZTmUwHL8cMZWJGzLBNCHNZ3NB6HTMsYABtt7z8tAGIINLXyAob9B9a1yzVGMFOYKEA==", "dev": true, "dependencies": { "clone": "^1.0.0", @@ -11351,7 +13442,7 @@ "node_modules/gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", "dev": true, "dependencies": { "glogg": "^1.0.0" @@ -11408,7 +13499,7 @@ "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, "engines": { "node": ">=4" @@ -11428,22 +13519,6 @@ "node": ">=6" } }, - "node_modules/har-validator/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -11458,7 +13533,7 @@ "node_modules/has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -11470,34 +13545,33 @@ "node_modules/has-ansi/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/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, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-gulplog": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==", "dev": true, "dependencies": { "sparkles": "^1.0.0" @@ -11506,6 +13580,18 @@ "node": ">= 0.10" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -11535,7 +13621,7 @@ "node_modules/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "dev": true, "dependencies": { "get-value": "^2.0.6", @@ -11549,7 +13635,7 @@ "node_modules/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=", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "dev": true, "dependencies": { "is-number": "^3.0.0", @@ -11565,10 +13651,34 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/has-values/node_modules/kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -11657,7 +13767,7 @@ "node_modules/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=", + "integrity": "sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg==", "dev": true, "dependencies": { "os-homedir": "^1.0.0", @@ -11680,10 +13790,16 @@ } }, "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } }, "node_modules/html-escaper": { "version": "2.0.2", @@ -11708,24 +13824,24 @@ "dev": true }, "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dependencies": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/http-parser-js": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", - "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "node_modules/http-proxy": { @@ -11745,7 +13861,7 @@ "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "dependencies": { "assert-plus": "^1.0.0", @@ -11771,16 +13887,16 @@ } }, "node_modules/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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "dependencies": { - "agent-base": "5", + "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 6" } }, "node_modules/iconv-lite": { @@ -11851,12 +13967,21 @@ "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "engines": { "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/individual": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz", @@ -11866,7 +13991,7 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { "once": "^1.3.0", @@ -11879,15 +14004,18 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } }, "node_modules/inquirer": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", - "integrity": "sha512-G6/9xUqmt/r+UvufSyrPpt84NYwhKZ9jLsgMbQzlx804XErNupor8WQdBnBRrXmBfTPpuwf1sV+ss2ovjgdXIg==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", "dev": true, "dependencies": { "ansi-escapes": "^4.2.1", @@ -11900,13 +14028,14 @@ "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^7.2.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=12.0.0" } }, "node_modules/inquirer/node_modules/ansi-styles": { @@ -11958,6 +14087,24 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/inquirer/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/inquirer/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -11970,6 +14117,12 @@ "node": ">=8" } }, + "node_modules/inquirer/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true + }, "node_modules/internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -12005,7 +14158,7 @@ "node_modules/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=", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12072,7 +14225,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "node_modules/is-bigint": { @@ -12139,9 +14292,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "engines": { "node": ">= 0.4" @@ -12151,9 +14304,9 @@ } }, "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dependencies": { "has": "^1.0.3" }, @@ -12262,7 +14415,7 @@ "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12359,7 +14512,7 @@ "node_modules/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=", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12378,21 +14531,18 @@ } }, "node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, "engines": { - "node": ">=0.10.0" + "node": ">=0.12.0" } }, "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -12404,24 +14554,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-number/node_modules/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 - }, - "node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -12480,7 +14612,7 @@ "node_modules/is-running": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz", - "integrity": "sha1-MKc/9cw4VOT8JUkICen1q/jeCeA=", + "integrity": "sha512-mjJd3PujZMl7j+D395WTIO5tU5RIDBfVSRtRR4VOJou3H66E38UjbjvDGh3slJzPuolsb+yQFqwHNNdyp5jg3w==", "dev": true }, "node_modules/is-set": { @@ -12493,10 +14625,13 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12513,7 +14648,7 @@ "node_modules/is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12550,15 +14685,15 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", + "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0" }, "engines": { @@ -12571,7 +14706,7 @@ "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "node_modules/is-unc-path": { @@ -12601,13 +14736,13 @@ "node_modules/is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", "dev": true }, "node_modules/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=", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12675,9 +14810,9 @@ "dev": true }, "node_modules/isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, "engines": { "node": ">= 8.0.0" @@ -12689,13 +14824,13 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12704,13 +14839,13 @@ "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "node_modules/istanbul": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", - "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "integrity": "sha512-nMtdn4hvK0HjUlzr1DrKSUY8ychprt8dzHOgY2KXsIhHu5PuQQEOTM27gV9Xblyon7aUH/TSFIjRHEODF/FRPg==", "deprecated": "This module is no longer maintained, try this instead:\n npm i nyc\nVisit https://istanbul.js.org/integrations for other alternatives.", "dev": true, "dependencies": { @@ -12742,6 +14877,22 @@ "node": ">=8" } }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", @@ -12756,6 +14907,15 @@ "node": ">=8" } }, + "node_modules/istanbul-lib-report/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -12792,9 +14952,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -12807,7 +14967,7 @@ "node_modules/istanbul/node_modules/glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", "dev": true, "dependencies": { "inflight": "^1.0.4", @@ -12823,19 +14983,19 @@ "node_modules/istanbul/node_modules/has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/istanbul/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -12844,13 +15004,13 @@ "node_modules/istanbul/node_modules/resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", "dev": true }, "node_modules/istanbul/node_modules/supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", "dev": true, "dependencies": { "has-flag": "^1.0.0" @@ -12960,6 +15120,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/jake/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/jake/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -12973,18 +15142,18 @@ } }, "node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-diff/node_modules/ansi-styles": { @@ -13036,6 +15205,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/jest-diff/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-diff/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13049,27 +15227,27 @@ } }, "node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-matcher-utils/node_modules/ansi-styles": { @@ -13121,6 +15299,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/jest-matcher-utils/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-matcher-utils/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13134,23 +15321,23 @@ } }, "node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "stack-utils": "^2.0.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-message-util/node_modules/ansi-styles": { @@ -13202,17 +15389,22 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/jest-message-util/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "node_modules/jest-message-util/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, "engines": { - "node": ">=8.6" + "node": ">=8" } }, "node_modules/jest-message-util/node_modules/supports-color": { @@ -13227,6 +15419,15 @@ "node": ">=8" } }, + "node_modules/jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "dev": true, + "engines": { + "node": ">= 10.14.2" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -13241,6 +15442,30 @@ "node": ">= 10.13.0" } }, + "node_modules/jest-worker/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -13275,7 +15500,7 @@ "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "node_modules/jsesc": { @@ -13295,12 +15520,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "node_modules/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 - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -13322,13 +15541,13 @@ "node_modules/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=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "node_modules/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=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, "node_modules/json5": { @@ -13372,7 +15591,7 @@ "node_modules/just-clone": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", - "integrity": "sha1-v7P672WqEqMWBYcSlFwyb9jwFDQ=" + "integrity": "sha512-p93GINPwrve0w3HUzpXmpTl7MyzzWz1B5ag44KEtq/hP1mtK8lA2b9Q0VQaPlnY87352osJcE6uBmN0e8kuFMw==" }, "node_modules/just-debounce": { "version": "1.1.0", @@ -13387,9 +15606,9 @@ "dev": true }, "node_modules/karma": { - "version": "6.3.17", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.17.tgz", - "integrity": "sha512-2TfjHwrRExC8yHoWlPBULyaLwAFmXmxQrcuFImt/JsAsSZu1uOWTZ1ZsWjqQtWpHLiatJOHL5jFjXSJIgCd01g==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz", + "integrity": "sha512-Cj57NKOskK7wtFWSlMvZf459iX+kpYIPXmkNUzP2WAFcA7nhr/ALn5R7sw3w+1udFDcpMx/tuB8d5amgm3ijaA==", "dev": true, "dependencies": { "@colors/colors": "1.5.0", @@ -13411,7 +15630,7 @@ "qjobs": "^1.2.0", "range-parser": "^1.2.1", "rimraf": "^3.0.2", - "socket.io": "^4.2.0", + "socket.io": "^4.4.1", "source-map": "^0.6.1", "tmp": "^0.2.1", "ua-parser-js": "^0.7.30", @@ -13453,7 +15672,7 @@ "node_modules/karma-chai": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", - "integrity": "sha1-vuWtQEAFF4Ea40u5RfdikJEIt5o=", + "integrity": "sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg==", "dev": true, "peerDependencies": { "chai": "*", @@ -13461,9 +15680,9 @@ } }, "node_modules/karma-chrome-launcher": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", - "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", "dev": true, "dependencies": { "which": "^1.2.1" @@ -13591,26 +15810,10 @@ "node": ">=0.10.0" } }, - "node_modules/karma-coverage/node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/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=", + "integrity": "sha512-8xU6F2/R6u6HAZ/nlyhhx3WEhj4C6hJorG7FR2REX81pgj2LSo9ADJXxCGIeXg6Qr2BGpxp4hcZcEOYGAwiumg==", "dev": true, "dependencies": { "es5-shim": "^4.0.5" @@ -13629,7 +15832,7 @@ "node_modules/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=", + "integrity": "sha512-ts71ke8pHvw6qdRtq0+7VY3ANLoZuUNNkA8abRaWV13QRPNm7TtSOqyszjHUtuwOWKcsSz4tbUtrNICrQC+SXQ==", "dev": true, "dependencies": { "lodash": "^4.6.1" @@ -13650,7 +15853,7 @@ "node_modules/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=", + "integrity": "sha512-Hr6nhkIp0GIJJrvzY8JFeHpQZNseuIakGac4bpw8K1+5F0tLb6l7uvXRa8mt2Z+NVwYgCct4QAfp2R2QP6o00w==", "dev": true, "dependencies": { "chalk": "^2.1.0", @@ -13673,7 +15876,7 @@ "node_modules/karma-mocha-reporter/node_modules/strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "dev": true, "dependencies": { "ansi-regex": "^3.0.0" @@ -13685,7 +15888,7 @@ "node_modules/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=", + "integrity": "sha512-rdty4FlVIowmUhPuG08TeXKHvaRxeDSzPxGIkWguCF3A32kE0uvXZ6dXW08PuaNjai8Ip3f5Pn9Pm2HlChaxCw==", "dev": true, "peerDependencies": { "karma": ">=0.9" @@ -13694,7 +15897,7 @@ "node_modules/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=", + "integrity": "sha512-qmypLWd6F2qrDJfAETvXDfxHvKDk+nyIjpH9xIeI3/hENr0U3nuqkxaftq73PfXZ4aOuOChA6SnLW4m4AxfRjQ==", "dev": true, "peerDependencies": { "karma": ">=0.9" @@ -13703,7 +15906,7 @@ "node_modules/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=", + "integrity": "sha512-5NRc8KmTBjNPE3dNfpJP90BArnBohYV4//MsLFfUA1e6N+G1/A5WuWctaFBtMQ6MWRybs/oguSej0JwDr8gInA==", "dev": true, "peerDependencies": { "karma": ">=0.9" @@ -13712,7 +15915,7 @@ "node_modules/karma-sinon": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/karma-sinon/-/karma-sinon-1.0.5.tgz", - "integrity": "sha1-TjRD8oMP3s/2JNN0cWPxIX2qKpo=", + "integrity": "sha512-wrkyAxJmJbn75Dqy17L/8aILJWFm7znd1CE8gkyxTBFnjMSOe2XTJ3P30T8SkxWZHmoHX0SCaUJTDBEoXs25Og==", "dev": true, "engines": { "node": ">= 0.10.0" @@ -13734,7 +15937,7 @@ "node_modules/karma-spec-reporter": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.32.tgz", - "integrity": "sha1-LpxyB+pyZ3EmAln4K+y1QyCeRAo=", + "integrity": "sha512-ZXsYERZJMTNRR2F3QN11OWF5kgnT/K2dzhM+oY3CDyMrDI3TjIWqYGG7c15rR9wjmy9lvdC+CCshqn3YZqnNrA==", "dev": true, "dependencies": { "colors": "^1.1.2" @@ -13760,13 +15963,24 @@ "webpack": "^5.0.0" } }, + "node_modules/karma/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/karma/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -13781,6 +15995,18 @@ "node": ">=0.10.0" } }, + "node_modules/karma/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, "node_modules/karma/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -13815,9 +16041,9 @@ "dev": true }, "node_modules/keyv": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.1.1.tgz", - "integrity": "sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz", + "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==", "dev": true, "dependencies": { "json-buffer": "3.0.1" @@ -13866,7 +16092,7 @@ "node_modules/last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", "dev": true, "dependencies": { "default-resolution": "^2.0.0", @@ -13891,7 +16117,7 @@ "node_modules/lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", "dev": true, "dependencies": { "invert-kv": "^1.0.0" @@ -13903,7 +16129,7 @@ "node_modules/lcov-parse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", - "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", + "integrity": "sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==", "dev": true, "bin": { "lcov-parse": "bin/cli.js" @@ -13912,7 +16138,7 @@ "node_modules/lead": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", "dev": true, "dependencies": { "flush-write-stream": "^1.0.2" @@ -13987,7 +16213,7 @@ "node_modules/lighthouse-logger/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/lines-and-columns": { @@ -13999,7 +16225,7 @@ "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", "dev": true }, "node_modules/live-connect-js": { @@ -14069,25 +16295,38 @@ } }, "node_modules/loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, "engines": { "node": ">=6.11.5" } }, + "node_modules/loader-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", + "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/lodash": { @@ -14099,126 +16338,135 @@ "node_modules/lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", "dev": true }, "node_modules/lodash._basetostring": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", + "integrity": "sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA==", "dev": true }, "node_modules/lodash._basevalues": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", + "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==", "dev": true }, "node_modules/lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", "dev": true }, "node_modules/lodash._isiterateecall": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", "dev": true }, "node_modules/lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", + "integrity": "sha512-Sjlavm5y+FUVIF3vF3B75GyXrzsfYV8Dlv3L4mEpuB9leg8N6yf/7rU06iLPx9fY0Mv3khVp9p7Dx0mGV6V5OQ==", "dev": true }, "node_modules/lodash._reevaluate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", + "integrity": "sha512-OrPwdDc65iJiBeUe5n/LIjd7Viy99bKwDdk7Z5ljfZg0uFRFlfQaCy9tZ4YMAag9WAZmlVpe1iZrkIMMSMHD3w==", "dev": true }, "node_modules/lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", "dev": true }, "node_modules/lodash._root": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==", "dev": true }, "node_modules/lodash.clone": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", + "integrity": "sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg==", "dev": true }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", "dev": true }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "node_modules/lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true }, "node_modules/lodash.difference": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", "dev": true }, + "node_modules/lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==", + "dev": true, + "dependencies": { + "lodash._root": "^3.0.0" + } + }, "node_modules/lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "dev": true }, "node_modules/lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, "node_modules/lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "dev": true }, "node_modules/lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", "dev": true }, "node_modules/lodash.isarray": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", "dev": true }, "node_modules/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=", + "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==", "dev": true }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, "node_modules/lodash.keys": { @@ -14241,19 +16489,19 @@ "node_modules/lodash.pickby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=", + "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==", "dev": true }, "node_modules/lodash.restparam": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", "dev": true }, "node_modules/lodash.some": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==", "dev": true }, "node_modules/lodash.template": { @@ -14278,19 +16526,19 @@ "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true }, "node_modules/lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", "dev": true }, "node_modules/lodash.zip": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", - "integrity": "sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", "dev": true }, "node_modules/log-driver": { @@ -14315,16 +16563,16 @@ } }, "node_modules/log4js": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.4.2.tgz", - "integrity": "sha512-k80cggS2sZQLBwllpT1p06GtfvzMmSdUCkW96f0Hj83rKGJDAu2vZjt9B9ag2vx8Zz1IXzxoLgqvRJCdMKybGg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", + "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", "dev": true, "dependencies": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "flatted": "^3.2.5", + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", "rfdc": "^1.3.0", - "streamroller": "^3.0.4" + "streamroller": "^3.1.3" }, "engines": { "node": ">=8.0" @@ -14410,7 +16658,7 @@ "node_modules/lru-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", "dev": true, "dependencies": { "es5-ext": "~0.10.2" @@ -14476,7 +16724,7 @@ "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -14494,13 +16742,13 @@ "node_modules/map-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", "dev": true }, "node_modules/map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, "dependencies": { "object-visit": "^1.0.0" @@ -14520,15 +16768,15 @@ } }, "node_modules/marky": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.4.tgz", - "integrity": "sha512-zd2/GiSn6U3/jeFVZ0J9CA1LzQ8RfIVvXkb/U0swFHF/zT+dVohTAWjmo2DcIuofmIIIROlwTbd+shSeXmxr0w==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", "dev": true }, "node_modules/matchdep": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", "dev": true, "dependencies": { "findup-sync": "^2.0.0", @@ -14540,10 +16788,110 @@ "node": ">= 0.10.0" } }, + "node_modules/matchdep/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/braces/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/fill-range/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/matchdep/node_modules/findup-sync": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", "dev": true, "dependencies": { "detect-file": "^1.0.0", @@ -14555,10 +16903,16 @@ "node": ">= 0.10" } }, + "node_modules/matchdep/node_modules/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 + }, "node_modules/matchdep/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "dependencies": { "is-extglob": "^2.1.0" @@ -14567,6 +16921,76 @@ "node": ">=0.10.0" } }, + "node_modules/matchdep/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/mdast-util-definitions": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", @@ -14708,11 +17132,12 @@ } }, "node_modules/mdast-util-gfm-table": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.4.tgz", - "integrity": "sha512-aEuoPwZyP4iIMkf2cLWXxx3EQ6Bmh2yKy9MVCg4i6Sd3cX80dcLEfXO/V4ul3pGH9czBK4kp+FAl+ZHmSUt9/w==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.6.tgz", + "integrity": "sha512-uHR+fqFq3IvB3Rd4+kzXW8dmpxUhvgCQZep6KdjsLK4O6meK5dYZEayLtIxNus1XO3gfjfcIFe8a7L0HZRGgag==", "dev": true, "dependencies": { + "@types/mdast": "^3.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^1.0.0", "mdast-util-to-markdown": "^1.3.0" @@ -14739,24 +17164,22 @@ "node_modules/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=", + "integrity": "sha512-CcJ0mHa36QYumDKiZ2OIR+ClhfOM7zIzN+Wfy8tRZ1hpH9DKLCS+Mh4DyK5bCxzE9uxMWcbIpeNFWsg1zrj/2g==", "dev": true, "dependencies": { "mdast-util-to-string": "^1.0.0" } }, "node_modules/mdast-util-to-hast": { - "version": "12.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.1.tgz", - "integrity": "sha512-dyindR2P7qOqXO1hQirZeGtVbiX7xlNQbw7gGaAwN4A1dh4+X8xU/JyYmRoyB8Fu1uPXzp7mlL5QwW7k+knvgA==", + "version": "12.2.4", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.4.tgz", + "integrity": "sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==", "dev": true, "dependencies": { "@types/hast": "^2.0.0", "@types/mdast": "^3.0.0", - "@types/mdurl": "^1.0.0", "mdast-util-definitions": "^5.0.0", - "mdurl": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-sanitize-uri": "^1.1.0", "trim-lines": "^3.0.0", "unist-builder": "^3.0.0", "unist-util-generated": "^2.0.0", @@ -14866,16 +17289,10 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "engines": { "node": ">= 0.6" } @@ -14912,7 +17329,7 @@ "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "node_modules/merge-stream": { "version": "2.0.0", @@ -14923,15 +17340,15 @@ "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "engines": { "node": ">= 0.6" } }, "node_modules/micromark": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz", - "integrity": "sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", "dev": true, "funding": [ { @@ -15419,9 +17836,9 @@ } }, "node_modules/micromark-util-sanitize-uri": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz", - "integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", "dev": true, "funding": [ { @@ -15494,118 +17911,16 @@ ] }, "node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/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, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.6" } }, "node_modules/mime": { @@ -15621,19 +17936,19 @@ } }, "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -15679,10 +17994,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mixin-deep": { "version": "1.3.2", @@ -15755,6 +18073,15 @@ "url": "https://opencollective.com/mochajs" } }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/mocha/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -15776,15 +18103,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/mocha/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -15813,6 +18131,17 @@ "node": ">=8" } }, + "node_modules/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/mocha/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -15831,29 +18160,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/mocha/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true, - "dependencies": { - "ms": "2.1.2" - }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=0.3.1" } }, - "node_modules/mocha/node_modules/debug/node_modules/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 - }, "node_modules/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -15882,6 +18197,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/mocha/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -15937,24 +18293,21 @@ "node": ">=10" } }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/mocha/node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/mocha/node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -15985,15 +18338,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/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, - "engines": { - "node": ">=8" - } - }, "node_modules/mocha/node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -16006,11 +18350,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } }, "node_modules/mocha/node_modules/yargs": { "version": "16.2.0", @@ -16064,21 +18417,24 @@ "ms": "2.0.0" } }, - "node_modules/morgan/node_modules/depd": { + "node_modules/morgan/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, "engines": { "node": ">= 0.8" } }, - "node_modules/morgan/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "node_modules/mpd-parser": { "version": "0.21.1", "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.21.1.tgz", @@ -16104,9 +18460,9 @@ } }, "node_modules/mrmime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", - "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", "dev": true, "engines": { "node": ">=10" @@ -16120,45 +18476,12 @@ "node_modules/multipipe": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "integrity": "sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q==", "dev": true, "dependencies": { "duplexer2": "0.0.2" } }, - "node_modules/multipipe/node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "dependencies": { - "readable-stream": "~1.1.9" - } - }, - "node_modules/multipipe/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "node_modules/multipipe/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/multipipe/node_modules/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 - }, "node_modules/mute-stdout": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", @@ -16199,11 +18522,10 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", "dev": true, - "optional": true, "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -16233,6 +18555,28 @@ "node": ">=0.10.0" } }, + "node_modules/nanomatch/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/nanomatch/node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -16245,13 +18589,13 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "node_modules/ncp": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", - "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", + "integrity": "sha512-PfGU8jYWdRl4FqJfCy0IzbkGyFHntfWygZg46nFk/dJD/XRrk2cj0SsKSX9n5u5gE0E0YfEpKWrEkfjnlZSTXA==", "dev": true, "bin": { "ncp": "bin/ncp" @@ -16309,7 +18653,7 @@ "node_modules/nise/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "node_modules/nise/node_modules/lolex": { @@ -16358,7 +18702,7 @@ "node_modules/nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", "dev": true, "dependencies": { "abbrev": "1" @@ -16368,24 +18712,33 @@ } }, "node_modules/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==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/normalize-path": { @@ -16424,7 +18777,7 @@ "node_modules/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=", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", "dev": true, "dependencies": { "path-key": "^2.0.0" @@ -16436,7 +18789,7 @@ "node_modules/npm-run-path/node_modules/path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, "engines": { "node": ">=4" @@ -16445,7 +18798,7 @@ "node_modules/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=", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -16463,7 +18816,7 @@ "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -16472,7 +18825,7 @@ "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, "dependencies": { "copy-descriptor": "^0.1.0", @@ -16486,7 +18839,7 @@ "node_modules/object-copy/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -16498,7 +18851,7 @@ "node_modules/object-copy/node_modules/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=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -16516,7 +18869,7 @@ "node_modules/object-copy/node_modules/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=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -16551,7 +18904,7 @@ "node_modules/object-copy/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -16561,10 +18914,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true, + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -16589,6 +18941,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "engines": { "node": ">= 0.4" } @@ -16596,7 +18949,7 @@ "node_modules/object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, "dependencies": { "isobject": "^3.0.0" @@ -16606,13 +18959,14 @@ } }, "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -16625,7 +18979,7 @@ "node_modules/object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", "dev": true, "dependencies": { "array-each": "^1.0.1", @@ -16640,7 +18994,7 @@ "node_modules/object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", "dev": true, "dependencies": { "for-own": "^1.0.0", @@ -16653,7 +19007,7 @@ "node_modules/object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, "dependencies": { "isobject": "^3.0.1" @@ -16665,7 +19019,7 @@ "node_modules/object.reduce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", "dev": true, "dependencies": { "for-own": "^1.0.0", @@ -16693,9 +19047,9 @@ } }, "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { "ee-first": "1.1.1" }, @@ -16715,7 +19069,7 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "dependencies": { "wrappy": "1" @@ -16760,7 +19114,7 @@ "node_modules/opn/node_modules/is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", "dev": true, "engines": { "node": ">=4" @@ -16855,6 +19209,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/ora/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/ora/node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -16886,7 +19249,7 @@ "node_modules/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=", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", "dev": true, "dependencies": { "readable-stream": "^2.0.1" @@ -16895,7 +19258,7 @@ "node_modules/os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -16904,7 +19267,7 @@ "node_modules/os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", "dev": true, "dependencies": { "lcid": "^1.0.0" @@ -16916,7 +19279,7 @@ "node_modules/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=", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, "engines": { "node": ">=0.10.0" @@ -16934,7 +19297,7 @@ "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "dev": true, "engines": { "node": ">=4" @@ -16950,36 +19313,39 @@ } }, "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "dependencies": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "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, "dependencies": { - "p-limit": "^1.1.0" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "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, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/parent-module": { @@ -16997,7 +19363,7 @@ "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, "dependencies": { "is-absolute": "^1.0.0", @@ -17047,7 +19413,7 @@ "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -17085,7 +19451,7 @@ "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -17094,22 +19460,22 @@ "node_modules/path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", "dev": true }, "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/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=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -17132,7 +19498,7 @@ "node_modules/path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, "dependencies": { "path-root-regex": "^0.1.0" @@ -17144,7 +19510,7 @@ "node_modules/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=", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -17153,7 +19519,7 @@ "node_modules/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=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "node_modules/path-type": { "version": "1.1.0", @@ -17190,7 +19556,7 @@ "node_modules/pause-stream": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", "dev": true, "dependencies": { "through": "~2.3" @@ -17199,13 +19565,13 @@ "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, "node_modules/picocolors": { @@ -17240,7 +19606,7 @@ "node_modules/pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -17249,7 +19615,7 @@ "node_modules/pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "dependencies": { "pinkie": "^2.0.0" @@ -17282,98 +19648,17 @@ "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/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, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/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, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/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, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/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, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/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, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/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, - "engines": { - "node": ">=8" - } - }, "node_modules/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, - "dependencies": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/plugin-error/node_modules/ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", "dev": true, "dependencies": { - "ansi-wrap": "^0.1.0" + "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" }, "engines": { "node": ">=0.10.0" @@ -17382,16 +19667,16 @@ "node_modules/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=", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "version": "8.4.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", + "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", "dev": true, "funding": [ { @@ -17413,6 +19698,19 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "optional": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -17423,35 +19721,57 @@ } }, "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", "react-is": "^17.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10" } }, "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/pretty-format/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pretty-format/node_modules/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 + }, "node_modules/pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", "dev": true, "engines": { "node": ">= 0.8" @@ -17472,18 +19792,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/printj": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.3.1.tgz", - "integrity": "sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg==", - "dev": true, - "bin": { - "printj": "bin/printj.njs" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -17554,7 +19862,7 @@ "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true }, "node_modules/ps-tree": { @@ -17575,13 +19883,13 @@ "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", "dev": true }, "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "node_modules/pump": { @@ -17637,16 +19945,16 @@ } }, "node_modules/puppeteer-core": { - "version": "13.5.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.5.1.tgz", - "integrity": "sha512-dobVqWjV34ilyfQHR3BBnCYaekBYTi5MgegEYBRYd3s3uFy8jUpZEEWbaFjG9ETm+LGzR5Lmr0aF6LLuHtiuCg==", + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.7.0.tgz", + "integrity": "sha512-rXja4vcnAzFAP1OVLq/5dWNfwBGuzcOARJ6qGV7oAZhnLmVRU8G5MsdeQEAOy332ZhkIOnn9jp15R89LKHyp2Q==", "dev": true, "dependencies": { "cross-fetch": "3.1.5", - "debug": "4.3.3", - "devtools-protocol": "0.0.969999", + "debug": "4.3.4", + "devtools-protocol": "0.0.981744", "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", "pkg-dir": "4.2.0", "progress": "2.0.3", "proxy-from-env": "1.1.0", @@ -17659,37 +19967,12 @@ "node": ">=10.18.1" } }, - "node_modules/puppeteer-core/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/puppeteer-core/node_modules/devtools-protocol": { - "version": "0.0.969999", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.969999.tgz", - "integrity": "sha512-6GfzuDWU0OFAuOvBokXpXPLxjOJ5DZ157Ue3sGQQM3LgAamb8m0R0ruSfN0DDu+XG5XJgT50i6zZ/0o8RglreQ==", + "version": "0.0.981744", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", + "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==", "dev": true }, - "node_modules/puppeteer-core/node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/puppeteer-core/node_modules/ws": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", @@ -17714,7 +19997,7 @@ "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", "dev": true, "engines": { "node": ">=0.6.0", @@ -17731,9 +20014,12 @@ } }, "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" }, @@ -17750,7 +20036,7 @@ "node_modules/querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", "dev": true, "engines": { @@ -17793,12 +20079,12 @@ } }, "node_modules/raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dependencies": { "bytes": "3.1.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -17941,48 +20227,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/read-pkg/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -18013,16 +20257,43 @@ "node_modules/readable-stream/node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/readable-stream/node_modules/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==", "dev": true }, "node_modules/readdir-glob": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", - "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.2.tgz", + "integrity": "sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==", "dev": true, "dependencies": { - "minimatch": "^3.0.4" + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/readdirp": { @@ -18040,7 +20311,7 @@ "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, "dependencies": { "resolve": "^1.1.6" @@ -18050,27 +20321,15 @@ } }, "node_modules/recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", "dev": true, "dependencies": { - "minimatch": "3.0.4" + "minimatch": "^3.0.5" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/recursive-readdir/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "node": ">=6.0.0" } }, "node_modules/regenerate": { @@ -18079,9 +20338,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", "dependencies": { "regenerate": "^1.4.2" }, @@ -18090,15 +20349,14 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", + "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" }, "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "dependencies": { "@babel/runtime": "^7.8.4" } @@ -18116,14 +20374,28 @@ "node": ">=0.10.0" } }, + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -18145,14 +20417,14 @@ } }, "node_modules/regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", "dependencies": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" }, @@ -18161,14 +20433,14 @@ } }, "node_modules/regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" }, "node_modules/regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dependencies": { "jsesc": "~0.5.0" }, @@ -18179,7 +20451,7 @@ "node_modules/regjsparser/node_modules/jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "bin": { "jsesc": "bin/jsesc" } @@ -18315,7 +20587,7 @@ "node_modules/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=", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", "dev": true, "dependencies": { "remove-bom-buffer": "^3.0.0", @@ -18339,7 +20611,7 @@ "node_modules/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=", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", "dev": true }, "node_modules/repeat-element": { @@ -18354,7 +20626,7 @@ "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true, "engines": { "node": ">=0.10" @@ -18363,7 +20635,7 @@ "node_modules/repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==", "dev": true, "dependencies": { "is-finite": "^1.0.0" @@ -18375,7 +20647,7 @@ "node_modules/replace-ext": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==", "dev": true, "engines": { "node": ">= 0.4" @@ -18384,7 +20656,7 @@ "node_modules/replace-homedir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", "dev": true, "dependencies": { "homedir-polyfill": "^1.0.1", @@ -18450,7 +20722,7 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -18465,10 +20737,16 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, "node_modules/resolve": { @@ -18496,7 +20774,7 @@ "node_modules/resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, "dependencies": { "expand-tilde": "^2.0.0", @@ -18518,7 +20796,7 @@ "node_modules/resolve-options": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", "dev": true, "dependencies": { "value-or-function": "^3.0.0" @@ -18530,17 +20808,20 @@ "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, "node_modules/responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", "dev": true, "dependencies": { "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/resq": { @@ -18555,7 +20836,7 @@ "node_modules/resq/node_modules/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=", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", "dev": true }, "node_modules/restore-cursor": { @@ -18626,20 +20907,17 @@ } }, "node_modules/rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, "dependencies": { - "tslib": "^2.1.0" + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" } }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -18653,25 +20931,53 @@ } }, "node_modules/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==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/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=", + "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", "dev": true }, "node_modules/safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, "dependencies": { "ret": "~0.1.10" } }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -18718,15 +21024,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/schema-utils/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -18738,7 +21035,7 @@ "node_modules/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=", + "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", "dev": true, "dependencies": { "sver-compat": "^1.5.0" @@ -18748,23 +21045,23 @@ } }, "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" @@ -18781,7 +21078,7 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/send/node_modules/mime": { "version": "1.6.0", @@ -18838,7 +21135,7 @@ "node_modules/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, "dependencies": { "accepts": "~1.3.4", @@ -18862,10 +21159,19 @@ "ms": "2.0.0" } }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/serve-index/node_modules/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=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "dependencies": { "depd": "~1.1.2", @@ -18880,13 +21186,13 @@ "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/serve-index/node_modules/setprototypeof": { @@ -18895,15 +21201,24 @@ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" @@ -18912,7 +21227,7 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, "node_modules/set-value": { @@ -18933,7 +21248,7 @@ "node_modules/set-value/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -18945,7 +21260,7 @@ "node_modules/set-value/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -18966,7 +21281,7 @@ "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "dev": true }, "node_modules/setprototypeof": { @@ -18999,7 +21314,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -19040,27 +21354,6 @@ "node": ">=0.3.1" } }, - "node_modules/sinon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/sinon/node_modules/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, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/sirv": { "version": "1.0.19", "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", @@ -19076,12 +21369,12 @@ } }, "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/slice-ansi": { @@ -19170,7 +21463,7 @@ "node_modules/snapdragon-node/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "dependencies": { "is-descriptor": "^1.0.0" @@ -19200,7 +21493,7 @@ "node_modules/snapdragon-util/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -19221,7 +21514,7 @@ "node_modules/snapdragon/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -19233,7 +21526,7 @@ "node_modules/snapdragon/node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "dependencies": { "is-extendable": "^0.1.0" @@ -19245,7 +21538,7 @@ "node_modules/snapdragon/node_modules/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=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -19257,7 +21550,7 @@ "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -19275,7 +21568,7 @@ "node_modules/snapdragon/node_modules/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=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -19287,7 +21580,7 @@ "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -19313,7 +21606,7 @@ "node_modules/snapdragon/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -19322,7 +21615,7 @@ "node_modules/snapdragon/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/snapdragon/node_modules/source-map-resolve": { @@ -19340,36 +21633,35 @@ } }, "node_modules/socket.io": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", - "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", "dev": true, "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.2", - "engine.io": "~6.1.0", - "socket.io-adapter": "~2.3.3", - "socket.io-parser": "~4.0.4" + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" }, "engines": { "node": ">=10.0.0" } }, "node_modules/socket.io-adapter": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", - "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", "dev": true }, "node_modules/socket.io-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", - "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", "dev": true, "dependencies": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" }, "engines": { @@ -19385,7 +21677,7 @@ "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -19413,22 +21705,12 @@ } }, "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "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, "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/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, - "engines": { - "node": ">=0.10.0" + "source-map": "^0.5.6" } }, "node_modules/source-map-url": { @@ -19491,15 +21773,15 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", "dev": true }, "node_modules/split": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==", "dev": true, "dependencies": { "through": "2" @@ -19520,19 +21802,46 @@ "node": ">=0.10.0" } }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/split2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", - "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", "dev": true, + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/split2/node_modules/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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, "engines": { - "node": ">= 10.x" + "node": ">= 6" } }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "node_modules/sshpk": { @@ -19563,7 +21872,7 @@ "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", "dev": true, "engines": { "node": "*" @@ -19593,7 +21902,7 @@ "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "dev": true, "dependencies": { "define-property": "^0.2.5", @@ -19606,7 +21915,7 @@ "node_modules/static-extend/node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "dependencies": { "is-descriptor": "^0.1.0" @@ -19618,7 +21927,7 @@ "node_modules/static-extend/node_modules/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=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -19630,7 +21939,7 @@ "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -19648,7 +21957,7 @@ "node_modules/static-extend/node_modules/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=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -19660,7 +21969,7 @@ "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -19684,11 +21993,11 @@ } }, "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/stream-buffers": { @@ -19703,7 +22012,7 @@ "node_modules/stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==", "dev": true, "dependencies": { "duplexer": "~0.1.1" @@ -19722,19 +22031,51 @@ "dev": true }, "node_modules/streamroller": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.4.tgz", - "integrity": "sha512-GI9NzeD+D88UFuIlJkKNDH/IsuR+qIN7Qh8EsmhoRZr9bQoehTraRgwtLUkZbpcAw+hLPfHOypmppz8YyGK68w==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz", + "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==", "dev": true, "dependencies": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "fs-extra": "^10.0.1" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" }, "engines": { "node": ">=8.0" } }, + "node_modules/streamroller/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/streamroller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/streamroller/node_modules/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, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -19744,10 +22085,16 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/string_decoder/node_modules/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==", + "dev": true + }, "node_modules/string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", "dev": true }, "node_modules/string-width": { @@ -19764,33 +22111,29 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/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 - }, "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -19825,7 +22168,7 @@ "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "engines": { "node": ">=4" @@ -19834,7 +22177,7 @@ "node_modules/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=", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", "dev": true, "engines": { "node": ">=0.10.0" @@ -19843,34 +22186,42 @@ "node_modules/strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/strip-json-comments": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", + "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/suffix": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", - "integrity": "sha1-zFgjFkag7xEC95R47zqSSP2chC8=", + "integrity": "sha512-j5uf6MJtMCfC4vBe5LFktSe4bGyNTBk7I2Kdri0jeLrcv5B9pWfxVa5JQpoxgtR8vaVB7bVxsWgnfQbX5wkhAA==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -19887,7 +22238,7 @@ "node_modules/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=", + "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", "dev": true, "dependencies": { "es6-iterator": "^2.0.1", @@ -19911,9 +22262,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -19986,7 +22337,7 @@ "node_modules/temp-fs": { "version": "0.9.9", "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz", - "integrity": "sha1-gHFzBDeHByDpQxUy/igUNk+IA9c=", + "integrity": "sha512-WfecDCR1xC9b0nsrzSaxPf3ZuWeWLUWblW4vlDQAa1biQaKHiImHnJfeQocQe/hXKMcolRzgkcVX/7kK4zoWbw==", "dev": true, "dependencies": { "rimraf": "~2.5.2" @@ -19998,7 +22349,7 @@ "node_modules/temp-fs/node_modules/rimraf": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", - "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", + "integrity": "sha512-Lw7SHMjssciQb/rRz7JyPIy9+bbUshEucPoLRvWqy09vC5zQixl8Uet+Zl+SROBB/JMWHJRdCk1qdxNWHNMvlQ==", "dev": true, "dependencies": { "glob": "^7.0.5" @@ -20030,9 +22381,9 @@ } }, "node_modules/terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.2", @@ -20048,16 +22399,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" + "terser": "^5.14.1" }, "engines": { "node": ">= 10.13.0" @@ -20097,15 +22448,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -20124,7 +22466,19 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/terser-webpack-plugin/node_modules/source-map": { + "node_modules/terser/node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/terser/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", @@ -20133,24 +22487,16 @@ "node": ">=0.10.0" } }, - "node_modules/terser/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "node_modules/terser/node_modules/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 - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -20168,7 +22514,7 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "node_modules/textextensions": { @@ -20186,7 +22532,7 @@ "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, "node_modules/through2": { @@ -20235,7 +22581,7 @@ "node_modules/time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -20280,21 +22626,21 @@ } }, "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "dependencies": { - "rimraf": "^3.0.0" + "os-tmpdir": "~1.0.2" }, "engines": { - "node": ">=8.17.0" + "node": ">=0.6.0" } }, "node_modules/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=", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", "dev": true, "dependencies": { "is-absolute": "^1.0.0", @@ -20307,7 +22653,7 @@ "node_modules/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=", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "engines": { "node": ">=4" } @@ -20315,7 +22661,7 @@ "node_modules/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=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, "dependencies": { "kind-of": "^3.0.2" @@ -20333,7 +22679,7 @@ "node_modules/to-object-path/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "dependencies": { "is-buffer": "^1.1.5" @@ -20369,19 +22715,23 @@ "node": ">=8.0" } }, - "node_modules/to-regex-range/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, "engines": { - "node": ">=0.12.0" + "node": ">=0.10.0" } }, "node_modules/to-through": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", "dev": true, "dependencies": { "through2": "^2.0.3" @@ -20433,13 +22783,13 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, "node_modules/traverse": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", "dev": true, "engines": { "node": "*" @@ -20458,7 +22808,7 @@ "node_modules/trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "integrity": "sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -20475,14 +22825,14 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz", - "integrity": "sha512-nWuffZppoaYK0vQ1SQmkSsQzJoHA4s6uzdb2waRpD806x9yfq153AdVsWz4je2qZcW+pENrMQXbGQ3sMCkXuhw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, @@ -20507,7 +22857,7 @@ "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -20519,7 +22869,7 @@ "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, "node_modules/type": { @@ -20576,7 +22926,7 @@ "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, "node_modules/typescript": { @@ -20615,9 +22965,9 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "version": "0.7.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", + "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", "dev": true, "funding": [ { @@ -20634,9 +22984,9 @@ } }, "node_modules/uglify-js": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz", - "integrity": "sha512-peeoTk3hSwYdoc9nrdiEJk+gx1ALCtTjdYuKSXMTDqq7n1W7dHPqWDdSi+BPL0ni2YMeHD7hKUSdbj3TZauY2A==", + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, "optional": true, "bin": { @@ -20647,14 +22997,14 @@ } }, "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" }, "funding": { @@ -20674,7 +23024,7 @@ "node_modules/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=", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -20704,7 +23054,7 @@ "node_modules/undertaker-registry": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", "dev": true, "engines": { "node": ">= 0.10" @@ -20713,7 +23063,7 @@ "node_modules/undertaker/node_modules/fast-levenshtein": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", "dev": true }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -20745,9 +23095,9 @@ } }, "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "engines": { "node": ">=4" } @@ -20786,10 +23136,19 @@ "node": ">=0.10.0" } }, + "node_modules/union-value/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/union-value/node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -20905,7 +23264,7 @@ "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "engines": { "node": ">= 0.8" } @@ -20913,7 +23272,7 @@ "node_modules/unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, "dependencies": { "has-value": "^0.3.1", @@ -20926,7 +23285,7 @@ "node_modules/unset-value/node_modules/has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "dev": true, "dependencies": { "get-value": "^2.0.3", @@ -20940,7 +23299,7 @@ "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dev": true, "dependencies": { "isarray": "1.0.0" @@ -20952,7 +23311,7 @@ "node_modules/unset-value/node_modules/has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -20961,7 +23320,7 @@ "node_modules/unset-value/node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, "node_modules/unzipper": { @@ -20981,6 +23340,15 @@ "setimmediate": "~1.0.4" } }, + "node_modules/unzipper/node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -20992,9 +23360,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz", - "integrity": "sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "funding": [ { "type": "opencollective", @@ -21028,14 +23396,14 @@ "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, "node_modules/url": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", "dev": true, "dependencies": { "punycode": "1.3.2", @@ -21061,7 +23429,7 @@ "node_modules/url/node_modules/punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", "dev": true }, "node_modules/use": { @@ -21074,29 +23442,28 @@ } }, "node_modules/util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "dev": true, "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", "which-typed-array": "^1.1.2" } }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "engines": { "node": ">= 0.4.0" } @@ -21160,7 +23527,7 @@ "node_modules/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=", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", "dev": true, "engines": { "node": ">= 0.10" @@ -21169,7 +23536,7 @@ "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "engines": { "node": ">= 0.8" } @@ -21177,7 +23544,7 @@ "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "engines": [ "node >=0.6.0" @@ -21191,13 +23558,13 @@ "node_modules/verror/node_modules/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=", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true }, "node_modules/vfile": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.4.tgz", - "integrity": "sha512-KI+7cnst03KbEyN1+JE504zF5bJBZa+J+CrevLeyIMq0aPU681I2rQ5p4PlnQ6exFtWiUrg26QUdFMnAKR6PIw==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", "dev": true, "dependencies": { "@types/unist": "^2.0.0", @@ -21254,6 +23621,12 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/vfile-reporter/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, "node_modules/vfile-reporter/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -21325,13 +23698,13 @@ } }, "node_modules/video.js": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.20.2.tgz", - "integrity": "sha512-hdvAHKAyaL6bCDkeu0pPtFYKi1EDaOUovm7FN1xqBDolUxgH8FKy1WIgTS+Ouuaw7R54SCTcSeXjZEizhy9ouQ==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.20.3.tgz", + "integrity": "sha512-JMspxaK74LdfWcv69XWhX4rILywz/eInOVPdKefpQiZJSMD5O8xXYueqACP2Q5yqKstycgmmEKlJzZ+kVmDciw==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", - "@videojs/http-streaming": "2.14.2", + "@videojs/http-streaming": "2.14.3", "@videojs/vhs-utils": "^3.0.4", "@videojs/xhr": "2.6.0", "aes-decrypter": "3.1.3", @@ -21342,7 +23715,7 @@ "mux.js": "6.0.1", "safe-json-parse": "4.0.0", "videojs-font": "3.2.0", - "videojs-vtt.js": "^0.15.3" + "videojs-vtt.js": "^0.15.4" } }, "node_modules/video.js/node_modules/safe-json-parse": { @@ -21474,7 +23847,7 @@ "node_modules/vinyl-sourcemap": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", "dev": true, "dependencies": { "append-buffer": "^1.0.2", @@ -21492,7 +23865,7 @@ "node_modules/vinyl-sourcemap/node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -21504,7 +23877,7 @@ "node_modules/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=", + "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==", "dev": true, "dependencies": { "source-map": "^0.5.1" @@ -21522,16 +23895,16 @@ "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/vue-template-compiler": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.10.tgz", - "integrity": "sha512-QO+8R9YRq1Gudm8ZMdo/lImZLJVUIAM8c07Vp84ojdDAf8HmPJc7XB556PcXV218k2AkKznsRz6xB5uOjAC4EQ==", + "version": "2.7.13", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.13.tgz", + "integrity": "sha512-jYM6TClwDS9YqP48gYrtAtaOhRKkbYmbzE+Q51gX5YDr777n7tNI/IZk4QV4l/PjQPNh/FVa/E92sh/RqKMrog==", "dev": true, "optional": true, "dependencies": { @@ -21549,9 +23922,9 @@ } }, "node_modules/watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", @@ -21564,54 +23937,148 @@ "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, "dependencies": { "defaults": "^1.0.3" } }, "node_modules/webdriver": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.16.16.tgz", - "integrity": "sha512-x8UoG9k/P8KDrfSh1pOyNevt9tns3zexoMxp9cKnyA/7HYSErhZYTLGlgxscAXLtQG41cMH/Ba/oBmOx7Hgd8w==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.5.3.tgz", + "integrity": "sha512-cDTn/hYj5x8BYwXxVb/WUwqGxrhCMP2rC8ttIWCfzmiVtmOnJGulC7CyxU3+p9Q5R/gIKTzdJOss16dhb+5CoA==", "dev": true, "dependencies": { - "@types/node": "^17.0.4", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "got": "^11.0.2", - "ky": "^0.29.0", "lodash.merge": "^4.6.1" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/webdriver/node_modules/@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriver/node_modules/@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "dependencies": { + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriver/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/webdriver/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/webdriver/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/webdriver/node_modules/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 + }, + "node_modules/webdriver/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/webdriver/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/webdriverio": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.16.16.tgz", - "integrity": "sha512-caPaEWyuD3Qoa7YkW4xCCQA4v9Pa9wmhFGPvNZh3ERtjMCNi8L/XXOdkekWNZmFh3tY0kFguBj7+fAwSY7HAGw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.25.4.tgz", + "integrity": "sha512-agkgwn2SIk5cAJ03uue1GnGZcUZUDN3W4fUMY9/VfO8bVJrPEgWg31bPguEWPu+YhEB/aBJD8ECxJ3OEKdy4qQ==", "dev": true, "dependencies": { "@types/aria-query": "^5.0.0", - "@types/node": "^17.0.4", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/repl": "7.16.14", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@types/node": "^18.0.0", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/repl": "7.25.4", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", "archiver": "^5.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", - "devtools": "7.16.16", - "devtools-protocol": "^0.0.973690", + "devtools": "7.25.4", + "devtools-protocol": "^0.0.1061995", "fs-extra": "^10.0.0", - "get-port": "^5.1.1", "grapheme-splitter": "^1.0.2", "lodash.clonedeep": "^4.5.0", "lodash.isobject": "^3.0.2", @@ -21623,12 +24090,120 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^8.0.0", - "webdriver": "7.16.16" + "webdriver": "7.25.4" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/webdriverio/node_modules/@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "node_modules/webdriverio/node_modules/@wdio/config": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.25.4.tgz", + "integrity": "sha512-vb0emDtD9FbFh/yqW6oNdo2iuhQp8XKj6GX9fyy9v4wZgg3B0HPMVJxhIfcoHz7LMBWlHSo9YdvhFI5EQHRLBA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "deepmerge": "^4.0.0", + "glob": "^8.0.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio/node_modules/@wdio/logger": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.19.0.tgz", + "integrity": "sha512-xR7SN/kGei1QJD1aagzxs3KMuzNxdT/7LYYx+lt6BII49+fqL/SO+5X0FDCZD0Ds93AuQvvz9eGyzrBI2FFXmQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio/node_modules/@wdio/protocols": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.22.0.tgz", + "integrity": "sha512-8EXRR+Ymdwousm/VGtW3H1hwxZ/1g1H99A1lF0U4GuJ5cFWHCd0IVE5H31Z52i8ZruouW8jueMkGZPSo2IIUSQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio/node_modules/@wdio/repl": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.25.4.tgz", + "integrity": "sha512-kYhj9gLsUk4HmlXLqkVre+gwbfvw9CcnrHjqIjrmMS4mR9D8zvBb5CItb3ZExfPf9jpFzIFREbCAYoE9x/kMwg==", + "dev": true, + "dependencies": { + "@wdio/utils": "7.25.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio/node_modules/@wdio/types": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.25.4.tgz", + "integrity": "sha512-muvNmq48QZCvocctnbe0URq2FjJjUPIG4iLoeMmyF0AQgdbjaUkMkw3BHYNHVTbSOU9WMsr2z8alhj/I2H6NRQ==", + "dev": true, + "dependencies": { + "@types/node": "^18.0.0", + "got": "^11.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "^4.6.2" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/webdriverio/node_modules/@wdio/utils": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.25.4.tgz", + "integrity": "sha512-8iwQDk+foUqSzKZKfhLxjlCKOkfRJPNHaezQoevNgnrTq/t0ek+ldZCATezb9B8jprAuP4mgS9xi22akc6RkzA==", + "dev": true, + "dependencies": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "p-iteration": "^1.1.8" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/webdriverio/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/webdriverio/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -21638,6 +24213,80 @@ "balanced-match": "^1.0.0" } }, + "node_modules/webdriverio/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/webdriverio/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/webdriverio/node_modules/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 + }, + "node_modules/webdriverio/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webdriverio/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/webdriverio/node_modules/ky": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.30.0.tgz", + "integrity": "sha512-X/u76z4JtDVq10u1JA5UQfatPxgPaVDMYTrgHyiTpGN2z4TMEJkIHsoSBBSg9SWZEIXTKsi9kHgiQ9o3Y/4yog==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } + }, "node_modules/webdriverio/node_modules/minimatch": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", @@ -21650,16 +24299,48 @@ "node": ">=10" } }, + "node_modules/webdriverio/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webdriverio/node_modules/webdriver": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.25.4.tgz", + "integrity": "sha512-6nVDwenh0bxbtUkHASz9B8T9mB531Fn1PcQjUGj2t5dolLPn6zuK1D7XYVX40hpn6r3SlYzcZnEBs4X0az5Txg==", + "dev": true, + "dependencies": { + "@types/node": "^18.0.0", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "got": "^11.0.2", + "ky": "0.30.0", + "lodash.merge": "^4.6.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, "node_modules/webpack": { - "version": "5.70.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", - "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -21667,24 +24348,24 @@ "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.2", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "bin": { @@ -21704,9 +24385,9 @@ } }, "node_modules/webpack-bundle-analyzer": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", - "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz", + "integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==", "dev": true, "dependencies": { "acorn": "^8.0.4", @@ -21727,9 +24408,9 @@ } }, "node_modules/webpack-bundle-analyzer/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -21738,15 +24419,6 @@ "node": ">=0.4.0" } }, - "node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/webpack-bundle-analyzer/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -21805,6 +24477,15 @@ "node": ">= 10" } }, + "node_modules/webpack-bundle-analyzer/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/webpack-bundle-analyzer/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -21818,9 +24499,9 @@ } }, "node_modules/webpack-bundle-analyzer/node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, "engines": { "node": ">=8.3.0" @@ -21916,10 +24597,92 @@ "webpack": "^5.21.2" } }, + "node_modules/webpack-stream/node_modules/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, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-stream/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-stream/node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-stream/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-stream/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-stream/node_modules/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, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/webpack-stream/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/webpack/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -21953,15 +24716,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -22006,7 +24760,7 @@ "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "dependencies": { "tr46": "~0.0.3", @@ -22059,18 +24813,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, "node_modules/which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", + "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" + "is-typed-array": "^1.1.9" }, "engines": { "node": ">= 0.4" @@ -22079,6 +24839,58 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/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, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/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": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -22091,13 +24903,13 @@ "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, "node_modules/workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", "dev": true }, "node_modules/wrap-ansi": { @@ -22153,7 +24965,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "node_modules/write": { @@ -22228,13 +25040,13 @@ "node_modules/yargs": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", - "integrity": "sha1-BU3oth8i7v23IHBZ6u+da4P7kxo=", + "integrity": "sha512-7OGt4xXoWJQh5ulgZ78rKaqY7dNWbjfK+UKxGcIlaM2j7C4fqGchyv8CPvEWdRPrHp6Ula/YU8yGRpYGOHrI+g==", "dev": true }, "node_modules/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "engines": { "node": ">=12" @@ -22267,18 +25079,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/yargs-unparser/node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -22291,7 +25091,7 @@ "node_modules/yarn-install": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yarn-install/-/yarn-install-1.0.0.tgz", - "integrity": "sha1-V/RQULgu/VcYKzlzxUqgXLXSUjA=", + "integrity": "sha512-VO1u181msinhPcGvQTVMnHVOae8zjX/NSksR17e6eXHRveDvHCF5mGjh9hkN8mzyfnCqcBe42LdTs7bScuTaeg==", "dev": true, "dependencies": { "cac": "^3.0.3", @@ -22309,7 +25109,7 @@ "node_modules/yarn-install/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -22318,7 +25118,7 @@ "node_modules/yarn-install/node_modules/ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -22327,7 +25127,7 @@ "node_modules/yarn-install/node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "dependencies": { "ansi-styles": "^2.2.1", @@ -22343,7 +25143,7 @@ "node_modules/yarn-install/node_modules/cross-spawn": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", "dev": true, "dependencies": { "lru-cache": "^4.0.1", @@ -22363,7 +25163,7 @@ "node_modules/yarn-install/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -22375,7 +25175,7 @@ "node_modules/yarn-install/node_modules/supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "engines": { "node": ">=0.8.0" @@ -22396,13 +25196,13 @@ "node_modules/yarn-install/node_modules/yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", "dev": true }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "dependencies": { "buffer-crc32": "~0.2.3", @@ -22460,20 +25260,19 @@ } }, "plugins/eslint": { - "name": "eslint-plugin-prebid", "version": "1.0.0", - "integrity": "sha512-DH8lk8H4D+XCWtPm7C27IzzD4lkBHv49YTqOHeS/1mYCp4rn1j3NNNA1gl2q+CNYaAPSZDaS5DwRL/ErDP6O4Q==", "dev": true, "license": "Apache-2.0" } }, "dependencies": { "@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "requires": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" } }, "@babel/code-frame": { @@ -22485,25 +25284,25 @@ } }, "@babel/compat-data": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", - "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==" + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==" }, "@babel/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", - "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.0", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -22512,86 +25311,96 @@ } }, "@babel/eslint-parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", - "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", "dev": true, "requires": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", "semver": "^6.3.0" } }, "@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.1.tgz", + "integrity": "sha512-u1dMdBUmA7Z0rBB97xh8pIhviK7oItYOkjbsCxTWMknyvbQRBwX7/gn4JXurRdirWMFh+ZtYARqkA6ydogVZpg==", "requires": { - "@babel/types": "^7.19.0", + "@babel/types": "^7.20.0", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } } }, "@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" } }, "@babel/helper-compilation-targets": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", - "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", "requires": { - "@babel/compat-data": "^7.19.0", + "@babel/compat-data": "^7.20.0", "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", + "browserslist": "^4.21.3", "semver": "^6.3.0" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", - "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" } }, "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -22604,11 +25413,11 @@ "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" }, "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" } }, "@babel/helper-function-name": { @@ -22629,11 +25438,11 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.9" } }, "@babel/helper-module-imports": { @@ -22645,69 +25454,70 @@ } }, "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", "requires": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" } }, "@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" } }, "@babel/helper-plugin-utils": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", - "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==" + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" }, "@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" } }, "@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" } }, "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.19.4" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.20.0" } }, "@babel/helper-split-export-declaration": { @@ -22719,14 +25529,14 @@ } }, "@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" }, "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -22734,24 +25544,24 @@ "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" }, "@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", "requires": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" } }, "@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", "requires": { "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" } }, "@babel/highlight": { @@ -22765,169 +25575,170 @@ } }, "@babel/parser": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", - "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==" + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.1.tgz", + "integrity": "sha512-hp0AYxaZJhxULfM1zyp7Wgr+pSUKBcP3M+PHnSzWGdXOzg/kHWIgiUWARvubhUKGOEw3xqY4x+lyZ9ytBVcELw==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz", + "integrity": "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", - "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", - "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", "requires": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" + "@babel/plugin-transform-parameters": "^7.18.8" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-syntax-async-generators": { @@ -22970,6 +25781,14 @@ "@babel/helper-plugin-utils": "^7.8.3" } }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.19.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", @@ -23043,331 +25862,332 @@ } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.0.tgz", + "integrity": "sha512-sXOohbpHZSk7GjxK9b3dKB7CfqUD5DwOH+DggKzOQ7TXYP+RCSbRykfjQmn/zq+rBjycVRtLf9pYhAaEJA786w==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.0.tgz", + "integrity": "sha512-1dIhvZfkDVx/zn2S1aFwlruspTt4189j7fEkH0Y0VyuDM6bQt7bD6kLcz3l4IlLG+e5OReaBz9ROAbttRtUHqA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "requires": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", "requires": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" } }, "@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.1.tgz", + "integrity": "sha512-nDvKLrAvl+kf6BOy1UJ3MGwzzfTMgppxwiD2Jb4LO3xjYyZq30oQzDNJbCQpMdG9+j2IXHoiMrw5Cm/L6ZoxXQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", "requires": { - "regenerator-transform": "^0.14.2" + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.9.tgz", - "integrity": "sha512-wS8uJwBt7/b/mzE13ktsJdmS4JP/j7PQSaADtnb4I2wL0zK51MQ0pmF8/Jy0wUIS96fr+fXT6S/ifiPXnvrlSg==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", "requires": { "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.9", - "babel-plugin-polyfill-corejs2": "^0.3.1", - "babel-plugin-polyfill-corejs3": "^0.5.2", - "babel-plugin-polyfill-regenerator": "^0.3.1", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", "semver": "^6.3.0" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz", + "integrity": "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==", "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.19.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.19.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -23377,44 +26197,44 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.19.4", + "@babel/plugin-transform-classes": "^7.19.0", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.19.4", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", + "@babel/types": "^7.19.4", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", "semver": "^6.3.0" } }, @@ -23431,18 +26251,21 @@ } }, "@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", + "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", "requires": { - "regenerator-runtime": "^0.13.4" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - } + "regenerator-runtime": "^0.13.10" + } + }, + "@babel/runtime-corejs3": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.20.1.tgz", + "integrity": "sha512-CGulbEDcg/ND1Im7fUNRZdGXmX2MTWVVZacQi/6DiKE5HNwZ3aVTm5PV4lO8HHz0B2h8WQyvKKjbX5XgTtydsg==", + "dev": true, + "requires": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.10" } }, "@babel/template": { @@ -23456,29 +26279,29 @@ } }, "@babel/traverse": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", - "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", + "@babel/generator": "^7.20.1", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.0", - "@babel/types": "^7.19.0", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.0.tgz", + "integrity": "sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==", "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } }, @@ -23518,9 +26341,9 @@ } }, "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -23596,7 +26419,7 @@ "@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=", + "integrity": "sha512-o/EatdaGt8+x2qpb0vFLC/2Gug/xYPRXb6a+ET1wGYKozKN3krDWC/zZFZAtrzxJHuDL12mwdfEFKcKMNvc55A==", "dev": true, "requires": { "normalize-path": "^2.0.1", @@ -23606,7 +26429,7 @@ "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" @@ -23676,57 +26499,6 @@ "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" - }, - "dependencies": { - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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 - } } }, "@istanbuljs/schema": { @@ -23736,15 +26508,15 @@ "dev": true }, "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", + "@types/yargs": "^15.0.0", "chalk": "^4.0.0" }, "dependencies": { @@ -23782,6 +26554,12 @@ "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.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -23794,19 +26572,18 @@ } }, "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" }, "@jridgewell/set-array": { "version": "1.1.2", @@ -23821,20 +26598,42 @@ "requires": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } } }, "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "requires": { + "eslint-scope": "5.1.1" } }, "@polka/url": { @@ -23879,15 +26678,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==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, - "@socket.io/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==", + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", "dev": true }, "@szmarczak/http-timer": { @@ -23900,9 +26699,9 @@ } }, "@types/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-P+dkdFu0n08PDIvw+9nT9ByQnd+Udc8DaWPb9HKfaPwCvWvQpC5XaMRx2xLWECm9x1VKNps6vEAlirjA6+uNrQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", "dev": true }, "@types/cacheable-request": { @@ -23917,12 +26716,6 @@ "@types/responselike": "*" } }, - "@types/component-emitter": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", - "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==", - "dev": true - }, "@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -23957,15 +26750,15 @@ "dev": true }, "@types/ejs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.0.tgz", - "integrity": "sha512-DCg+Ka+uDQ31lJ/UtEXVlaeV3d6t81gifaVWKJy4MYVVgvJttyX/viREy+If7fz+tK/gVxTGMtyrFPnm4gjrVA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.1.tgz", + "integrity": "sha512-RQul5wEfY7BjWm0sYY86cmUN/pcXWGyVxWX93DFFJvcrxax5zKlieLwA3T77xJGwNcZW0YW6CYG70p1m8xPFmA==", "dev": true }, "@types/eslint": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", - "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "version": "8.4.9", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.9.tgz", + "integrity": "sha512-jFCSo4wJzlHQLCpceUhUnXdrPuCNOjGFMQ8Eg6JXxlz3QaCKOb7eGi2cephQdM4XTYsNej69P9JDJ1zqNIbncQ==", "dev": true, "requires": { "@types/estree": "*", @@ -23973,9 +26766,9 @@ } }, "@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", "dev": true, "requires": { "@types/eslint": "*", @@ -24037,13 +26830,13 @@ "dev": true }, "@types/inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-BNoMetRf3gmkpAlV5we+kxyZTle7YibdOntIZbU5pyIfMdcwy784KfeZDAcuyMznkh5OLa17RVXZOGA5LTlkgQ==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-HhxyLejTHMfohAuhRun4csWigAMjXTmRyiJTU1Y/I1xmggikFMkOUoMQRlFm+zQcPEGHSs3io/0FAmNZf8EymQ==", "dev": true, "requires": { "@types/through": "*", - "rxjs": "^7.2.0" + "rxjs": "^6.4.0" } }, "@types/istanbul-lib-coverage": { @@ -24071,54 +26864,54 @@ } }, "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "@types/keyv": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", - "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-4.2.0.tgz", + "integrity": "sha512-xoBtGl5R9jeKUhc8ZqeYaRDx04qqJ10yhhXYGmJ4Jr8qKpvMsDQQrNUvF/wUJ4klOtmJeJM+p2Xo3zp9uaC3tw==", "dev": true, "requires": { - "@types/node": "*" + "keyv": "*" } }, "@types/lodash": { - "version": "4.14.179", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz", - "integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==", + "version": "4.14.187", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.187.tgz", + "integrity": "sha512-MrO/xLXCaUgZy3y96C/iOsaIqZSeupyTImKClHunL5GrmaiII2VwvWmLBu2hwa0Kp0sV19CsyjtrTc/Fx8rg/A==", "dev": true }, "@types/lodash.flattendeep": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.6.tgz", - "integrity": "sha512-uLm2MaRVlqJSGsMK0RZpP5T3KqReq+9WbYDHCUhBhp98v56hMG/Yht52bsoTSui9xz2mUvQ9NfG3LrNGDL92Ng==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.7.tgz", + "integrity": "sha512-1h6GW/AeZw/Wej6uxrqgmdTDZX1yFS39lRsXYkg+3kWvOWWrlGCI6H7lXxlUHOzxDT4QeYGmgPpQ3BX9XevzOg==", "dev": true, "requires": { "@types/lodash": "*" } }, "@types/lodash.pickby": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.6.tgz", - "integrity": "sha512-NFa13XxlMd9eFi0UFZFWIztpMpXhozbijrx3Yb1viYZphT7jyopIFVoIRF4eYMjruWNEG1rnyrRmg/8ej9T8Iw==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.7.tgz", + "integrity": "sha512-4ebXRusuLflfscbD0PUX4eVknDHD9Yf+uMtBIvA/hrnTqeAzbuHuDjvnYriLjUrI9YrhCPVKUf4wkRSXJQ6gig==", "dev": true, "requires": { "@types/lodash": "*" } }, "@types/lodash.union": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.6.tgz", - "integrity": "sha512-Wu0ZEVNcyCz8eAn6TlUbYWZoGbH9E+iOHxAZbwUoCEXdUiy6qpcz5o44mMXViM4vlPLLCPlkAubEP1gokoSZaw==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.7.tgz", + "integrity": "sha512-6HXM6tsnHJzKgJE0gA/LhTGf/7AbjUk759WZ1MziVm+OBNAATHhdgj+a3KVE8g76GCLAnN4ZEQQG1EGgtBIABA==", "dev": true, "requires": { "@types/lodash": "*" @@ -24133,16 +26926,10 @@ "@types/unist": "*" } }, - "@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", - "dev": true - }, "@types/mocha": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", - "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", + "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==", "dev": true }, "@types/ms": { @@ -24152,9 +26939,9 @@ "dev": true }, "@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", "dev": true }, "@types/normalize-package-data": { @@ -24170,18 +26957,18 @@ "dev": true }, "@types/puppeteer": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.5.tgz", - "integrity": "sha512-lxCjpDEY+DZ66+W3x5Af4oHnEmUXt0HuaRzkBGE2UZiZEp/V1d3StpLPlmNVu/ea091bdNmVPl44lu8Wy/0ZCA==", + "version": "5.4.7", + "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.7.tgz", + "integrity": "sha512-JdGWZZYL0vKapXF4oQTC5hLVNfOgdPrqeZ1BiQnGk5cB7HeE91EWUiTdVSdQPobRN8rIcdffjiOgCYJ/S8QrnQ==", "dev": true, "requires": { "@types/node": "*" } }, "@types/recursive-readdir": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.0.tgz", - "integrity": "sha512-HGk753KRu2N4mWduovY4BLjYq4jTOL29gV2OfGdGxHcPSWGFkC5RRIdk+VTs5XmYd7MVAD+JwKrcb5+5Y7FOCg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.1.tgz", + "integrity": "sha512-Xd+Ptc4/F2ueInqy5yK2FI5FxtwwbX2+VZpcg+9oYsFJVen8qQKGapCr+Bi5wQtHU1cTXT8s+07lo/nKPgu8Gg==", "dev": true, "requires": { "@types/node": "*" @@ -24261,9 +27048,9 @@ "dev": true }, "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -24276,9 +27063,9 @@ "dev": true }, "@types/yauzl": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", - "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, "optional": true, "requires": { @@ -24292,9 +27079,9 @@ "dev": true }, "@videojs/http-streaming": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.2.tgz", - "integrity": "sha512-K1raSfO/pq5r8iUas3OSYni0kXOj91n8ealIpV02khghzGv9LQ6O3YUqYd/eAhJ1HIrmZWOnrYpK/P+mhUExXQ==", + "version": "2.14.3", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.3.tgz", + "integrity": "sha512-2tFwxCaNbcEZzQugWf8EERwNMyNtspfHnvxRGRABQs09W/5SqmkWFuGWfUAm4wQKlXGfdPyAJ1338ASl459xAA==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", @@ -24330,14 +27117,14 @@ } }, "@vue/compiler-core": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.38.tgz", - "integrity": "sha512-/FsvnSu7Z+lkd/8KXMa4yYNUiqQrI22135gfsQYVGuh5tqEgOB0XqrUdb/KnCLa5+TmQLPwvyUnKMyCpu+SX3Q==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.41.tgz", + "integrity": "sha512-oA4mH6SA78DT+96/nsi4p9DX97PHcNROxs51lYk7gb9Z4BPKQ3Mh+BLn6CQZBw857Iuhu28BfMSRHAlPvD4vlw==", "dev": true, "optional": true, "requires": { "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.38", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "source-map": "^0.6.1" }, @@ -24352,29 +27139,29 @@ } }, "@vue/compiler-dom": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.38.tgz", - "integrity": "sha512-zqX4FgUbw56kzHlgYuEEJR8mefFiiyR3u96498+zWPsLeh1WKvgIReoNE+U7gG8bCUdvsrJ0JRmev0Ky6n2O0g==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.41.tgz", + "integrity": "sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw==", "dev": true, "optional": true, "requires": { - "@vue/compiler-core": "3.2.38", - "@vue/shared": "3.2.38" + "@vue/compiler-core": "3.2.41", + "@vue/shared": "3.2.41" } }, "@vue/compiler-sfc": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.38.tgz", - "integrity": "sha512-KZjrW32KloMYtTcHAFuw3CqsyWc5X6seb8KbkANSWt3Cz9p2qA8c1GJpSkksFP9ABb6an0FLCFl46ZFXx3kKpg==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.41.tgz", + "integrity": "sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w==", "dev": true, "optional": true, "requires": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.38", - "@vue/compiler-dom": "3.2.38", - "@vue/compiler-ssr": "3.2.38", - "@vue/reactivity-transform": "3.2.38", - "@vue/shared": "3.2.38", + "@vue/compiler-core": "3.2.41", + "@vue/compiler-dom": "3.2.41", + "@vue/compiler-ssr": "3.2.41", + "@vue/reactivity-transform": "3.2.41", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "magic-string": "^0.25.7", "postcss": "^8.1.10", @@ -24391,34 +27178,34 @@ } }, "@vue/compiler-ssr": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.38.tgz", - "integrity": "sha512-bm9jOeyv1H3UskNm4S6IfueKjUNFmi2kRweFIGnqaGkkRePjwEcfCVqyS3roe7HvF4ugsEkhf4+kIvDhip6XzQ==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.41.tgz", + "integrity": "sha512-Y5wPiNIiaMz/sps8+DmhaKfDm1xgj6GrH99z4gq2LQenfVQcYXmHIOBcs5qPwl7jaW3SUQWjkAPKMfQemEQZwQ==", "dev": true, "optional": true, "requires": { - "@vue/compiler-dom": "3.2.38", - "@vue/shared": "3.2.38" + "@vue/compiler-dom": "3.2.41", + "@vue/shared": "3.2.41" } }, "@vue/reactivity-transform": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.38.tgz", - "integrity": "sha512-3SD3Jmi1yXrDwiNJqQ6fs1x61WsDLqVk4NyKVz78mkaIRh6d3IqtRnptgRfXn+Fzf+m6B1KxBYWq1APj6h4qeA==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.41.tgz", + "integrity": "sha512-mK5+BNMsL4hHi+IR3Ft/ho6Za+L3FA5j8WvreJ7XzHrqkPq8jtF/SMo7tuc9gHjLDwKZX1nP1JQOKo9IEAn54A==", "dev": true, "optional": true, "requires": { "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.38", - "@vue/shared": "3.2.38", + "@vue/compiler-core": "3.2.41", + "@vue/shared": "3.2.41", "estree-walker": "^2.0.2", "magic-string": "^0.25.7" } }, "@vue/shared": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.38.tgz", - "integrity": "sha512-dTyhTIRmGXBjxJE+skC8tTWCGLCVc4wQgRRLt8+O9p5ewBAjoBwtCAkLPrtToSr1xltoe3st21Pv953aOZ7alg==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.41.tgz", + "integrity": "sha512-W9mfWLHmJhkfAmV+7gDjcHeAWALQtgGT3JErxULl0oz6R6+3ug91I7IErs93eCFhPCZPHBs4QJS7YWEV7A3sxw==", "dev": true, "optional": true }, @@ -24434,43 +27221,219 @@ "browserstack-local": "^1.4.5", "got": "^11.0.2", "webdriverio": "7.16.16" + }, + "dependencies": { + "@wdio/config": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.16.16.tgz", + "integrity": "sha512-K/ObPuo6Da2liz++OKOIfbdpFwI7UWiFcBylfJkCYbweuXCoW1aUqlKI6rmKPwCH9Uqr/RHWu6p8eo0zWe6xVA==", + "dev": true, + "requires": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.14", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + } + }, + "@wdio/protocols": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.16.7.tgz", + "integrity": "sha512-Wv40pNQcLiPzQ3o98Mv4A8T1EBQ6k4khglz/e2r16CTm+F3DDYh8eLMAsU5cgnmuwwDKX1EyOiFwieykBn5MCg==", + "dev": true + }, + "@wdio/repl": { + "version": "7.16.14", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.16.14.tgz", + "integrity": "sha512-Ezih0Y+lsGkKv3H3U56hdWgZiQGA3VaAYguSLd9+g1xbQq+zMKqSmfqECD9bAy+OgCCiVTRstES6lHZxJVPhAg==", + "dev": true, + "requires": { + "@wdio/utils": "7.16.14" + } + }, + "@wdio/utils": { + "version": "7.16.14", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.16.14.tgz", + "integrity": "sha512-wwin8nVpIlhmXJkq6GJw9aDDzgLOJKgXTcEua0T2sdXjoW78u5Ly/GZrFXTjMGhacFvoZfitTrjyfyy4CxMVvw==", + "dev": true, + "requires": { + "@wdio/logger": "7.16.0", + "@wdio/types": "7.16.14", + "p-iteration": "^1.1.8" + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "devtools": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", + "integrity": "sha512-M0kzkuSgfEhpqIis3gdtWsNjn/HQ+vRAmEzDnbYx/7FfjFxhSv1d+rOOT20pvd60soItMYpsOova1igACEGkGQ==", + "dev": true, + "requires": { + "@types/node": "^17.0.4", + "@types/ua-parser-js": "^0.7.33", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "chrome-launcher": "^0.15.0", + "edge-paths": "^2.1.0", + "puppeteer-core": "^13.1.3", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.1", + "uuid": "^8.0.0" + } + }, + "devtools-protocol": { + "version": "0.0.973690", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.973690.tgz", + "integrity": "sha512-myh3hSFp0YWa2GED11PmbLhV4dv9RdO7YUz27XJrbQLnP5bMbZL6dfOOILTHO57yH0kX5GfuOZBsg/4NamfPvQ==", + "dev": true + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "ua-parser-js": { + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", + "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "webdriver": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.16.16.tgz", + "integrity": "sha512-x8UoG9k/P8KDrfSh1pOyNevt9tns3zexoMxp9cKnyA/7HYSErhZYTLGlgxscAXLtQG41cMH/Ba/oBmOx7Hgd8w==", + "dev": true, + "requires": { + "@types/node": "^17.0.4", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "got": "^11.0.2", + "ky": "^0.29.0", + "lodash.merge": "^4.6.1" + } + }, + "webdriverio": { + "version": "7.16.16", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.16.16.tgz", + "integrity": "sha512-caPaEWyuD3Qoa7YkW4xCCQA4v9Pa9wmhFGPvNZh3ERtjMCNi8L/XXOdkekWNZmFh3tY0kFguBj7+fAwSY7HAGw==", + "dev": true, + "requires": { + "@types/aria-query": "^5.0.0", + "@types/node": "^17.0.4", + "@wdio/config": "7.16.16", + "@wdio/logger": "7.16.0", + "@wdio/protocols": "7.16.7", + "@wdio/repl": "7.16.14", + "@wdio/types": "7.16.14", + "@wdio/utils": "7.16.14", + "archiver": "^5.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.16.16", + "devtools-protocol": "^0.0.973690", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "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", + "minimatch": "^5.0.0", + "puppeteer-core": "^13.1.3", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.16.16" + } + } } }, "@wdio/cli": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.16.16.tgz", - "integrity": "sha512-Wz/e5zm1UNHB9RAIsJIM7ioDzVllUwTvhVWOrI7HR/53GmO/cIvAVjpnlglizJNgK8WlbnM/cKNVIXxqxrnFmw==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.5.7.tgz", + "integrity": "sha512-nOQJLskrY+UECDd3NxE7oBzb6cDA7e7x02YWQugOlOgnZ4a+PJmkFoSsO8C2uNCpdFngy5rJKGUo5vbtAHEF9Q==", "dev": true, "requires": { "@types/ejs": "^3.0.5", "@types/fs-extra": "^9.0.4", - "@types/inquirer": "^8.1.2", + "@types/inquirer": "^7.3.1", "@types/lodash.flattendeep": "^4.4.6", "@types/lodash.pickby": "^4.6.6", "@types/lodash.union": "^4.6.6", - "@types/node": "^17.0.4", "@types/recursive-readdir": "^2.2.0", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "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": "^10.0.0", - "inquirer": "8.1.5", + "inquirer": "^8.0.0", "lodash.flattendeep": "^4.4.0", "lodash.pickby": "^4.6.0", "lodash.union": "^4.6.0", "mkdirp": "^1.0.4", "recursive-readdir": "^2.2.2", - "webdriverio": "7.16.16", + "webdriverio": "7.5.7", "yargs": "^17.0.0", "yarn-install": "^1.0.0" }, "dependencies": { + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -24480,6 +27443,16 @@ "color-convert": "^2.0.1" } }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -24490,6 +27463,31 @@ "supports-color": "^7.1.0" } }, + "chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "requires": { + "@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": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -24505,6 +27503,65 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "requires": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + } + }, + "devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "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 + }, + "puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + } + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -24514,13 +27571,62 @@ "has-flag": "^4.0.0" } }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", + "dev": true, + "requires": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "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", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + }, "yargs": { - "version": "17.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", - "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -24532,17 +27638,26 @@ } }, "@wdio/concise-reporter": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/concise-reporter/-/concise-reporter-7.16.14.tgz", - "integrity": "sha512-CR+9+skJ3mXPIdRo0AnIJTJHOArrWdKlXTnyZ/DD6M9VrNk5aiTWQyphT/IeHV5+fxjHlMNIf/KgIhj1ewschQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/concise-reporter/-/concise-reporter-7.5.7.tgz", + "integrity": "sha512-964i7eQ4sboSla2bdR8714Er82QBgS6u39GmDFX8Izy9Ge38xaE75HuF5S7mnOWGzSojCWgqtwy5k7Rfg6GE3g==", "dev": true, "requires": { - "@wdio/reporter": "7.16.14", - "@wdio/types": "7.16.14", + "@wdio/reporter": "7.5.7", + "@wdio/types": "7.5.3", "chalk": "^4.0.0", "pretty-ms": "^7.0.0" }, "dependencies": { + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -24577,6 +27692,12 @@ "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.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -24589,31 +27710,175 @@ } }, "@wdio/config": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.16.16.tgz", - "integrity": "sha512-K/ObPuo6Da2liz++OKOIfbdpFwI7UWiFcBylfJkCYbweuXCoW1aUqlKI6rmKPwCH9Uqr/RHWu6p8eo0zWe6xVA==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.5.3.tgz", + "integrity": "sha512-udvVizYoilOxuWj/BmoN6y7ZCd4wPdYNlSfWznrbCezAdaLZ4/pNDOO0WRWx2C4+q1wdkXZV/VuQPUGfL0lEHQ==", "dev": true, "requires": { - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", "deepmerge": "^4.0.0", "glob": "^7.1.2" + }, + "dependencies": { + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@wdio/local-runner": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.16.16.tgz", - "integrity": "sha512-AJaOyM842PWgMffrrXyHJjouVseLHoiL5U1sw2VVproi3ORWHbltl1AMnreU/lrGu9L0CVKHYT1pxu5UbSOCxQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.5.7.tgz", + "integrity": "sha512-aYc0XUV+/e3cg8Fp+CWlC4FbwSSG3mKAv1iuy/+Hwzg2kJE+aa+Rf2p2BQYc7HPRtKNW0bM8o+aCImZLAiPM+A==", "dev": true, "requires": { "@types/stream-buffers": "^3.0.3", - "@wdio/logger": "7.16.0", - "@wdio/repl": "7.16.14", - "@wdio/runner": "7.16.16", - "@wdio/types": "7.16.14", + "@wdio/logger": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/runner": "7.5.7", + "@wdio/types": "7.5.3", "async-exit-hook": "^2.0.1", - "split2": "^4.0.0", + "split2": "^3.2.2", "stream-buffers": "^3.0.2" + }, + "dependencies": { + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@wdio/logger": { @@ -24662,6 +27927,12 @@ "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.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -24674,19 +27945,46 @@ } }, "@wdio/mocha-framework": { - "version": "7.16.15", - "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.16.15.tgz", - "integrity": "sha512-XRya85/RYPZk4MZ7Cvl3oudTdrOo+RyO8b5Ff+dH8hD3GBCACaWgW9AjbsyhvbSTdUlF0gNLPdqOCsxV5XyM3w==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.5.3.tgz", + "integrity": "sha512-96QCVWsiyZxEgOZP3oTq2B2T7zne5dCdehLa2n4q/BLjk96Rj0jifidJZfd/1+vdNPKX0gWWAzpy98Znn8MVMw==", "dev": true, "requires": { - "@types/mocha": "^9.0.0", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", - "expect-webdriverio": "^3.0.0", - "mocha": "^9.0.0" + "@types/mocha": "^8.0.0", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "expect-webdriverio": "^2.0.0", + "mocha": "^8.0.1" }, "dependencies": { + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -24710,17 +28008,33 @@ "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "color-convert": { @@ -24738,6 +28052,21 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -24754,10 +28083,30 @@ "path-exists": "^4.0.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" + } + }, + "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 + }, "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", "dev": true, "requires": { "argparse": "^2.0.1" @@ -24773,13 +28122,12 @@ } }, "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "chalk": "^4.0.0" } }, "minimatch": { @@ -24792,47 +28140,59 @@ } }, "mocha": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", - "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", "dev": true, "requires": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.3", + "chokidar": "3.5.1", + "debug": "4.3.1", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.2.0", + "glob": "7.1.6", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", "minimatch": "3.0.4", "ms": "2.1.3", - "nanoid": "3.2.0", - "serialize-javascript": "6.0.0", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", "which": "2.0.2", - "workerpool": "6.2.0", + "wide-align": "1.1.3", + "workerpool": "6.1.0", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", "dev": true }, "p-limit": { @@ -24853,11 +28213,23 @@ "p-limit": "^3.0.2" } }, - "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 + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } }, "strip-json-comments": { "version": "3.1.1", @@ -24865,6 +28237,21 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -24889,72 +28276,288 @@ } }, "@wdio/protocols": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.16.7.tgz", - "integrity": "sha512-Wv40pNQcLiPzQ3o98Mv4A8T1EBQ6k4khglz/e2r16CTm+F3DDYh8eLMAsU5cgnmuwwDKX1EyOiFwieykBn5MCg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.5.3.tgz", + "integrity": "sha512-lpNaKwxYhDSL6neDtQQYXvzMAw+u4PXx65ryeMEX82mkARgzSZps5Kyrg9ub7X4T17K1NPfnY6UhZEWg6cKJCg==", "dev": true }, "@wdio/repl": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.16.14.tgz", - "integrity": "sha512-Ezih0Y+lsGkKv3H3U56hdWgZiQGA3VaAYguSLd9+g1xbQq+zMKqSmfqECD9bAy+OgCCiVTRstES6lHZxJVPhAg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.5.3.tgz", + "integrity": "sha512-jfNJwNoc2nWdnLsFoGHmOJR9zaWfDTBMWM3W1eR5kXIjevD6gAfWsB5ZoA4IdybujCXxdnhlsm4o2jIzp/6f7A==", "dev": true, "requires": { - "@wdio/utils": "7.16.14" + "@wdio/utils": "7.5.3" } }, "@wdio/reporter": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.16.14.tgz", - "integrity": "sha512-e/I2oGfqjx9+zI4NT/garqxm7Afnos1EcrGSNu75WmP3PNJt4i+9DKkROu4PM6XWcpUB4v2UF7Mv/NrL3TU9aA==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.5.7.tgz", + "integrity": "sha512-9PXqZtCXDtU6UYLNDPu9MZQ8BiABGnRlJTrlbYB3gBfZDibMkJMvwXzPderipBv2+ifDZXmGe3Njf1ao2TkbFA==", "dev": true, "requires": { - "@types/diff": "^5.0.0", - "@types/node": "^17.0.4", - "@types/object-inspect": "^1.8.0", - "@types/supports-color": "^8.1.0", - "@types/tmp": "^0.2.0", - "@wdio/types": "7.16.14", - "diff": "^5.0.0", - "fs-extra": "^10.0.0", - "object-inspect": "^1.10.3", - "supports-color": "8.1.1" + "@wdio/types": "7.5.3", + "fs-extra": "^10.0.0" + }, + "dependencies": { + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + } } }, "@wdio/runner": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.16.16.tgz", - "integrity": "sha512-Tt2ja6GukGPq1m98WP26yOWUGwzK1y7gPTLy6rKlamz3mOBC7koL0T9+iqcFREquUe4CMy2jWp1lqvPlwMbu7g==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.5.7.tgz", + "integrity": "sha512-RzVXd+xnwK/thkx1/xo9K5iscQ0Ofobgsx5dNVtwLDVMn9V7jCW/WX4dSCPAPaVSqnUCmkcQp3P5AoSBPpCZnQ==", "dev": true, "requires": { - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "deepmerge": "^4.0.0", "gaze": "^1.1.2", - "webdriver": "7.16.16", - "webdriverio": "7.16.16" + "webdriver": "7.5.3", + "webdriverio": "7.5.7" + }, + "dependencies": { + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "requires": { + "@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" + } + }, + "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 + }, + "devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "requires": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + } + }, + "devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "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 + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", + "dev": true, + "requires": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "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", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + } } }, "@wdio/spec-reporter": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.19.1.tgz", - "integrity": "sha512-qnZkn3VcyBPtcorUtpyCFE8v5ubyWmR7mFETXNzyriHyvjvk+NeFCWaFcIehpXYXiAmNpAwyfnZoIY6tkKQixQ==", + "version": "7.19.7", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.19.7.tgz", + "integrity": "sha512-BDBZU2EK/GuC9VxtfqPtoW43FmvKxYDsvcDVDi3F7o+9fkcuGSJiWbw1AX251ZzzVQ7YP9ImTitSpdpUKXkilQ==", "dev": true, "requires": { "@types/easy-table": "^0.0.33", - "@wdio/reporter": "7.19.1", - "@wdio/types": "7.19.1", + "@wdio/reporter": "7.19.7", + "@wdio/types": "7.19.5", "chalk": "^4.0.0", "easy-table": "^1.1.1", "pretty-ms": "^7.0.0" }, "dependencies": { "@wdio/reporter": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.19.1.tgz", - "integrity": "sha512-sWmBBV4dPCZkGk9Qq0m35T/vHGen0N10nH4osQcVP3IZJqpo2eLIH4w+X6EUbjZ2GdgOA2bLMMzb1bl9JqnGPg==", + "version": "7.19.7", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.19.7.tgz", + "integrity": "sha512-Dum19gpfru66FnIq78/4HTuW87B7ceLDp6PJXwQM5kXyN7Gb7zhMgp6FZTM0FCYLyi6U/zXZSvpNUYl77caS6g==", "dev": true, "requires": { "@types/diff": "^5.0.0", @@ -24962,17 +28565,46 @@ "@types/object-inspect": "^1.8.0", "@types/supports-color": "^8.1.0", "@types/tmp": "^0.2.0", - "@wdio/types": "7.19.1", + "@wdio/types": "7.19.5", "diff": "^5.0.0", "fs-extra": "^10.0.0", "object-inspect": "^1.10.3", "supports-color": "8.1.1" + } + }, + "@wdio/types": { + "version": "7.19.5", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.19.5.tgz", + "integrity": "sha512-S1lC0pmtEO7NVH/2nM1c7NHbkgxLZH3VVG/z6ym3Bbxdtcqi2LMsEvvawMAU/fmhyiIkMsGZCO8vxG9cRw4z4A==", + "dev": true, + "requires": { + "@types/node": "^17.0.4", + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "dependencies": { "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -24980,13 +28612,303 @@ } } }, + "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": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@wdio/sync": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-7.5.7.tgz", + "integrity": "sha512-Zu/AYLjwqbFSbaOU1US7ownv3ov8JrtoGHq51JfJ4masefJDXNkHix2cZ0qEgl3IvkkWQ0ewL0G8GTXb3KOemA==", + "dev": true, + "requires": { + "@types/fibers": "^3.1.0", + "@types/puppeteer": "^5.4.0", + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3", + "fibers": "^5.0.0", + "webdriverio": "7.5.7" + }, + "dependencies": { + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", + "dev": true, + "requires": { + "@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" + } + }, + "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 + }, + "devtools": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.5.7.tgz", + "integrity": "sha512-+kqmvFbceElhYpN35yjm1T4Rz3VbH0QaqrNWKRpeyFp657Y5W0bm1s5FyMUeIv0aTNkAgWcETtqL+EG9X9uvjQ==", + "dev": true, + "requires": { + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "chrome-launcher": "^0.13.1", + "edge-paths": "^2.1.0", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + } + }, + "devtools-protocol": { + "version": "0.0.878340", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.878340.tgz", + "integrity": "sha512-W0q8Y02r1RNwfZtI4Jjh1/MZxRHyrIgy9FvElbJzQelZjmNH197H4mBQs7DZjlUUDA9s6Zz2jl+zUYFgLgEnzw==", + "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 + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "puppeteer-core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-9.1.1.tgz", + "integrity": "sha512-zbedbitVIGhmgz0nt7eIdLsnaoVZSlNJfBivqm2w67T8LR2bU1dvnruDZ8nQO0zn++Iet7zHbAOdnuS5+H2E7A==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.869402", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.869402", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", + "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==", + "dev": true + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "webdriverio": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.5.7.tgz", + "integrity": "sha512-TLluVPLo6Snn/dxEITvMz7ZuklN4qZOBddDuLb9LO3rhsfKDMNbnhcBk0SLdFsWny0aCuhWNpJ6co93702XC0A==", + "dev": true, + "requires": { + "@types/aria-query": "^4.2.1", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/repl": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", + "archiver": "^5.0.0", + "aria-query": "^4.2.2", + "atob": "^2.1.2", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools": "7.5.7", + "devtools-protocol": "^0.0.878340", + "fs-extra": "^10.0.0", + "get-port": "^5.1.1", + "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", + "minimatch": "^3.0.4", + "puppeteer-core": "^9.1.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^8.0.0", + "webdriver": "7.5.3" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + } + } + }, + "@wdio/types": { + "version": "7.16.14", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.16.14.tgz", + "integrity": "sha512-AyNI9iBSos9xWBmiFAF3sBs6AJXO/55VppU/eeF4HRdbZMtMarnvMuahM+jlUrA3vJSmDW+ufelG0MT//6vrnw==", + "dev": true, + "requires": { + "@types/node": "^17.0.4", + "got": "^11.8.1" + } + }, + "@wdio/utils": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.5.3.tgz", + "integrity": "sha512-nlLDKr8v8abLOHCKroBwQkGPdCIxjID2MllgWX23xqkYZylM9RdwPBdL8osQt9m3rq2TxiPAT4OlbzNt2WtN6Q==", + "dev": true, + "requires": { + "@wdio/logger": "7.5.3", + "@wdio/types": "7.5.3" + }, + "dependencies": { + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, "@wdio/types": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.19.1.tgz", - "integrity": "sha512-mOodKlmvYxpj8P5BhjggEGpXuiRSlsyn2ClG8QqJ3lfXgOtOVEzFNfv/Ai7TkHr+lHDQNXLjllCjSqoCHhwlqg==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", "dev": true, "requires": { - "@types/node": "^17.0.4", "got": "^11.8.1" } }, @@ -25024,6 +28946,12 @@ "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.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -25035,41 +28963,6 @@ } } }, - "@wdio/sync": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-7.16.16.tgz", - "integrity": "sha512-MbVFAteaAOxHLKkMiMzOnh1hzINAK2U41GDIfy1yaPumcw1pNuJIhWrBYxprNMlqt8srk++wqQWgj5XpFjCL6g==", - "dev": true, - "requires": { - "@types/fibers": "^3.1.0", - "@types/puppeteer": "^5.4.0", - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "fibers": "^5.0.0", - "webdriverio": "7.16.16" - } - }, - "@wdio/types": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.16.14.tgz", - "integrity": "sha512-AyNI9iBSos9xWBmiFAF3sBs6AJXO/55VppU/eeF4HRdbZMtMarnvMuahM+jlUrA3vJSmDW+ufelG0MT//6vrnw==", - "dev": true, - "requires": { - "@types/node": "^17.0.4", - "got": "^11.8.1" - } - }, - "@wdio/utils": { - "version": "7.16.14", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.16.14.tgz", - "integrity": "sha512-wwin8nVpIlhmXJkq6GJw9aDDzgLOJKgXTcEua0T2sdXjoW78u5Ly/GZrFXTjMGhacFvoZfitTrjyfyy4CxMVvw==", - "dev": true, - "requires": { - "@wdio/logger": "7.16.0", - "@wdio/types": "7.16.14", - "p-iteration": "^1.1.8" - } - }, "@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -25217,9 +29110,9 @@ } }, "@xmldom/xmldom": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.6.tgz", - "integrity": "sha512-HHXP9hskkFQHy8QxxUXkS7946FFIhYVfGqsk0WLwllmexN9x/+R4UBLvurHEuyXRfVEObVR8APuQehykLviwSQ==", + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.8.tgz", + "integrity": "sha512-PrJx38EfpitFhwmILRl37jAdBlsww6AZ6rRVK4QS7T7RHLhX7mSs647sTmgr9GIxe3qjXdesmomEgbgaokrVFg==", "dev": true }, "@xtuc/ieee754": { @@ -25237,7 +29130,7 @@ "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", "dev": true }, "accepts": { @@ -25262,6 +29155,12 @@ "dev": true, "requires": {} }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "aes-decrypter": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz", @@ -25275,10 +29174,13 @@ } }, "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 + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } }, "ajv": { "version": "6.12.3", @@ -25292,17 +29194,24 @@ "uri-js": "^4.2.2" } }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", "dev": true, "optional": true }, "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==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true }, "ansi-cyan": { @@ -25326,7 +29235,7 @@ "ansi-gray": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", "dev": true, "requires": { "ansi-wrap": "0.1.0" @@ -25358,7 +29267,7 @@ "ansi-wrap": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", "dev": true }, "anymatch": { @@ -25374,20 +29283,20 @@ "append-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", "dev": true, "requires": { "buffer-equal": "^1.0.0" } }, "archiver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz", - "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", "dev": true, "requires": { "archiver-utils": "^2.1.0", - "async": "^3.2.0", + "async": "^3.2.3", "buffer-crc32": "^0.2.1", "readable-stream": "^3.6.0", "readdir-glob": "^1.0.0", @@ -25396,9 +29305,9 @@ }, "dependencies": { "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", "dev": true }, "readable-stream": { @@ -25435,7 +29344,7 @@ "archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, "argparse": { @@ -25448,21 +29357,36 @@ } }, "aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", - "dev": true + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "requires": { + "deep-equal": "^2.0.5" + } }, "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 + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "dependencies": { + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", + "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=", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", "dev": true, "requires": { "make-iterator": "^1.0.0" @@ -25477,50 +29401,50 @@ "arr-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", "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=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", "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=", + "integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==", "dev": true }, "array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", "dev": true }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "array-from": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==", "dev": true }, "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", "get-intrinsic": "^1.1.1", "is-string": "^1.0.7" } @@ -25528,7 +29452,7 @@ "array-initial": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", "dev": true, "requires": { "array-slice": "^1.0.0", @@ -25580,24 +29504,25 @@ "array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "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=", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true }, "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" } }, "asn1": { @@ -25624,7 +29549,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true }, "assertion-error": { @@ -25636,7 +29561,7 @@ "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true }, "astral-regex": { @@ -25648,7 +29573,7 @@ "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", "dev": true }, "async-done": { @@ -25678,7 +29603,7 @@ "async-settle": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", "dev": true, "requires": { "async-done": "^1.2.2" @@ -25687,7 +29612,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "atob": { @@ -25705,7 +29630,7 @@ "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=", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true }, "aws4": { @@ -25717,7 +29642,7 @@ "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=", + "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -25728,19 +29653,19 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -25753,13 +29678,13 @@ "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", "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=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -25768,7 +29693,7 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true } } @@ -25812,19 +29737,13 @@ "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==", "dev": true }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -25845,19 +29764,10 @@ "trim-right": "^1.0.1" }, "dependencies": { - "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" - } - }, "jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "integrity": "sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA==", "dev": true } } @@ -25865,7 +29775,7 @@ "babel-helpers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "integrity": "sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ==", "dev": true, "requires": { "babel-runtime": "^6.22.0", @@ -25873,56 +29783,26 @@ } }, "babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", "dev": true, "requires": { "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", + "loader-utils": "^2.0.0", "make-dir": "^3.1.0", "schema-utils": "^2.6.5" - }, - "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" - } - }, - "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" - } - } } }, "babel-messages": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==", "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==", - "requires": { - "object.assign": "^4.1.0" - } - }, "babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -25934,54 +29814,39 @@ "@istanbuljs/schema": "^0.1.2", "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" - }, - "dependencies": { - "istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - } } }, "babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", "semver": "^6.1.1" } }, "babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.3.3" } }, "babel-register": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "integrity": "sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A==", "dev": true, "requires": { "babel-core": "^6.26.0", @@ -26007,22 +29872,13 @@ "requires": { "minimist": "^1.2.6" } - }, - "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" - } } } }, "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=", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", "dev": true, "requires": { "core-js": "^2.4.0", @@ -26034,13 +29890,19 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true } } }, "babel-template": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==", "dev": true, "requires": { "babel-runtime": "^6.26.0", @@ -26053,7 +29915,7 @@ "babel-traverse": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==", "dev": true, "requires": { "babel-code-frame": "^6.26.0", @@ -26085,7 +29947,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -26093,7 +29955,7 @@ "babel-types": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", "dev": true, "requires": { "babel-runtime": "^6.26.0", @@ -26105,7 +29967,7 @@ "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=", + "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", "dev": true } } @@ -26119,7 +29981,7 @@ "bach": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", "dev": true, "requires": { "arr-filter": "^1.1.1", @@ -26163,7 +30025,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -26190,18 +30052,26 @@ "dev": true, "requires": { "safe-buffer": "5.1.2" + }, + "dependencies": { + "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==", + "dev": true + } } }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "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=", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, "requires": { "tweetnacl": "^0.14.3" @@ -26210,7 +30080,7 @@ "beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", + "integrity": "sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA==", "dev": true }, "big-integer": { @@ -26228,7 +30098,7 @@ "binary": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", "dev": true, "requires": { "buffers": "~0.1.1", @@ -26284,13 +30154,13 @@ "bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", "dev": true }, "body": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", "dev": true, "requires": { "continuable-cache": "^0.3.1", @@ -26302,13 +30172,13 @@ "bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", + "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", "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=", + "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", "dev": true, "requires": { "bytes": "1", @@ -26318,26 +30188,28 @@ "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true } } }, "body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "requires": { "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "dependencies": { "debug": { @@ -26351,7 +30223,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -26381,14 +30253,14 @@ "dev": true }, "browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "requires": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" + "update-browserslist-db": "^1.0.9" } }, "browserstack": { @@ -26431,21 +30303,22 @@ } }, "browserstack-local": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.4.9.tgz", - "integrity": "sha512-V+q8HQwRQFr9nd32xR66ZZ3VDWa3Kct4IMMudhKgcuD7cWrvvFARZOibx71II+Rf7P5nMQpWWxl9z/3p927nbg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.5.1.tgz", + "integrity": "sha512-T/wxyWDzvBHbDvl7fZKpFU7mYze6nrUkBhNy+d+8bXBqgQX10HTYvajIGO0wb49oGSLCPM0CMZTV/s7e6LF0sA==", "dev": true, "requires": { - "https-proxy-agent": "^4.0.0", + "agent-base": "^6.0.2", + "https-proxy-agent": "^5.0.1", "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==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.5.tgz", + "integrity": "sha512-oociT3nl+FhQnyJbAb1RM4oQ5pN7aKeXEURkTkiEVm/Rji2r0agl3Wbw5V23VFn9lCU5/fGyDejRZPtGYsEcFw==", "dev": true, "requires": { "https-proxy-agent": "^2.2.1", @@ -26495,13 +30368,13 @@ "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, "buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", "dev": true }, "buffer-from": { @@ -26519,7 +30392,7 @@ "buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", "dev": true }, "bytes": { @@ -26530,7 +30403,7 @@ "cac": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/cac/-/cac-3.0.4.tgz", - "integrity": "sha1-bSTO7Dcu/lybeYgIvH9JtHJCpO8=", + "integrity": "sha512-hq4rxE3NT5PlaEiVV39Z45d6MoFcQZG5dsgJqtAUeOz3408LEQAElToDkf9i5IYSCOmK0If/81dLg7nKxqPR0w==", "dev": true, "requires": { "camelcase-keys": "^3.0.0", @@ -26545,35 +30418,19 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "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 - }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "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" - } - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -26586,23 +30443,35 @@ "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "requires": { "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" } }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "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" + } + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, "requires": { "pinkie-promise": "^2.0.0" @@ -26611,7 +30480,7 @@ "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "requires": { "load-json-file": "^1.0.0", @@ -26622,17 +30491,23 @@ "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=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" } }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "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=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -26641,7 +30516,7 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true } } @@ -26716,6 +30591,24 @@ "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": "sha512-U4E6A6aFyYnNW+tDt5/yIUKQURKXe3WMFPfX4FxrQFcwZ/R08AUk1xWcUtlr7oq6CV07Ji+aa69V2g7BSpblnQ==", + "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": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true + } + } + }, "can-autoplay": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/can-autoplay/-/can-autoplay-3.0.2.tgz", @@ -26723,14 +30616,14 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001390", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001390.tgz", - "integrity": "sha512-sS4CaUM+/+vqQUlCvCJ2WtDlV81aWtHhqeEVkLokVJJa3ViN4zDxAGfq9R8i1m90uGHxo99cy10Od+lvn3hf0g==" + "version": "1.0.30001429", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz", + "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==" }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "ccount": { @@ -26757,7 +30650,7 @@ "chainsaw": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", "dev": true, "requires": { "traverse": ">=0.3.0 <0.4" @@ -26771,21 +30664,6 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "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" - } - } } }, "character-entities": { @@ -26815,7 +30693,7 @@ "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", "dev": true }, "chokidar": { @@ -26841,9 +30719,9 @@ "dev": true }, "chrome-launcher": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.0.tgz", - "integrity": "sha512-ZQqX5kb9H0+jy1OqLnWampfocrtSZaGl7Ny3F9GRha85o4odbL8x55paUzh51UC7cEmZ5obp3H2Mm70uC2PpRA==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.1.tgz", + "integrity": "sha512-UugC8u59/w2AyX5sHLZUHoxBAiSiunUhZa3zZwMH6zPVis0C3dDKiRWyUGIo14tTbZHGVviWxv3PQWZ7taZ4fg==", "dev": true, "requires": { "@types/node": "*", @@ -26878,10 +30756,16 @@ "static-extend": "^0.1.1" }, "dependencies": { + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -26890,7 +30774,7 @@ "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=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -26899,7 +30783,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -26916,7 +30800,7 @@ "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=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -26925,7 +30809,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -26956,9 +30840,9 @@ } }, "cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", "dev": true }, "cli-width": { @@ -26968,32 +30852,32 @@ "dev": true }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", "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=", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", "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=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "dev": true, "requires": { "mimic-response": "^1.0.0" @@ -27002,7 +30886,7 @@ "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=", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", "dev": true }, "cloneable-readable": { @@ -27019,13 +30903,13 @@ "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=", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", "dev": true }, "collection-map": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", "dev": true, "requires": { "arr-map": "^2.0.2", @@ -27036,7 +30920,7 @@ "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dev": true, "requires": { "map-visit": "^1.0.0", @@ -27054,7 +30938,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "color-support": { "version": "1.1.3", @@ -27083,10 +30967,16 @@ "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==", "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=", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, "component-emitter": { @@ -27123,7 +31013,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "concat-stream": { @@ -27176,10 +31066,40 @@ "ms": "2.0.0" } }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "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" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true } } @@ -27196,13 +31116,6 @@ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "requires": { "safe-buffer": "5.2.1" - }, - "dependencies": { - "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==" - } } }, "content-type": { @@ -27213,31 +31126,28 @@ "continuable-cache": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", - "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", + "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", "dev": true }, "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "requires": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true }, "copy-props": { @@ -27251,30 +31161,22 @@ } }, "core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==" + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz", + "integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==" }, "core-js-compat": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", - "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", "requires": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - } + "browserslist": "^4.21.4" } }, "core-js-pure": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", - "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==" + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz", + "integrity": "sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==" }, "core-util-is": { "version": "1.0.3", @@ -27306,14 +31208,10 @@ } }, "crc-32": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.1.tgz", - "integrity": "sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w==", - "dev": true, - "requires": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.3.1" - } + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true }, "crc32-stream": { "version": "4.0.2", @@ -27396,13 +31294,13 @@ "css-value": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", - "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=", + "integrity": "sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==", "dev": true }, "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true }, "d": { @@ -27418,22 +31316,22 @@ "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "date-format": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.4.tgz", - "integrity": "sha512-/jyf4rhB17ge328HJuJjAcmRtCsGd+NDeAtahRBTaK6vSPR6MO5HlrAit3Nn7dVjaa6sowW0WXt8yQtLyZQFRg==", + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true }, "dateformat": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", + "integrity": "sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==", "dev": true }, "de-indent": { @@ -27444,9 +31342,9 @@ "optional": true }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } @@ -27474,9 +31372,9 @@ } }, "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true }, "decode-named-character-reference": { @@ -27491,7 +31389,7 @@ "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=", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", "dev": true }, "decompress-response": { @@ -27567,13 +31465,13 @@ "default-resolution": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", "dev": true }, "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, "requires": { "clone": "^1.0.2" @@ -27582,7 +31480,7 @@ "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true } } @@ -27594,11 +31492,13 @@ "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==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, "requires": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, "define-property": { @@ -27614,13 +31514,13 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true }, "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, "dequal": { "version": "2.0.3", @@ -27629,85 +31529,232 @@ "dev": true }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, "detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==", + "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=", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "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=", + "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", "dev": true }, "devtools": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.16.16.tgz", - "integrity": "sha512-M0kzkuSgfEhpqIis3gdtWsNjn/HQ+vRAmEzDnbYx/7FfjFxhSv1d+rOOT20pvd60soItMYpsOova1igACEGkGQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-7.25.4.tgz", + "integrity": "sha512-R6/S/dCqxoX4Y6PxIGM9JFAuSRZzUeV5r+CoE/frhmno6mTe7dEEgwkJlfit3LkKRoul8n4DsL2A3QtWOvq5IA==", "dev": true, "requires": { - "@types/node": "^17.0.4", + "@types/node": "^18.0.0", "@types/ua-parser-js": "^0.7.33", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", "chrome-launcher": "^0.15.0", "edge-paths": "^2.1.0", "puppeteer-core": "^13.1.3", "query-selector-shadow-dom": "^1.0.0", "ua-parser-js": "^1.0.1", - "uuid": "^8.0.0" + "uuid": "^9.0.0" }, "dependencies": { + "@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "@wdio/config": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.25.4.tgz", + "integrity": "sha512-vb0emDtD9FbFh/yqW6oNdo2iuhQp8XKj6GX9fyy9v4wZgg3B0HPMVJxhIfcoHz7LMBWlHSo9YdvhFI5EQHRLBA==", + "dev": true, + "requires": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "deepmerge": "^4.0.0", + "glob": "^8.0.3" + } + }, + "@wdio/logger": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.19.0.tgz", + "integrity": "sha512-xR7SN/kGei1QJD1aagzxs3KMuzNxdT/7LYYx+lt6BII49+fqL/SO+5X0FDCZD0Ds93AuQvvz9eGyzrBI2FFXmQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/protocols": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.22.0.tgz", + "integrity": "sha512-8EXRR+Ymdwousm/VGtW3H1hwxZ/1g1H99A1lF0U4GuJ5cFWHCd0IVE5H31Z52i8ZruouW8jueMkGZPSo2IIUSQ==", + "dev": true + }, + "@wdio/types": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.25.4.tgz", + "integrity": "sha512-muvNmq48QZCvocctnbe0URq2FjJjUPIG4iLoeMmyF0AQgdbjaUkMkw3BHYNHVTbSOU9WMsr2z8alhj/I2H6NRQ==", + "dev": true, + "requires": { + "@types/node": "^18.0.0", + "got": "^11.8.1" + } + }, + "@wdio/utils": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.25.4.tgz", + "integrity": "sha512-8iwQDk+foUqSzKZKfhLxjlCKOkfRJPNHaezQoevNgnrTq/t0ek+ldZCATezb9B8jprAuP4mgS9xi22akc6RkzA==", + "dev": true, + "requires": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "p-iteration": "^1.1.8" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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 + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.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 + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, "ua-parser-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", - "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==", + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", + "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", "dev": true }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "dev": true } } }, "devtools-protocol": { - "version": "0.0.973690", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.973690.tgz", - "integrity": "sha512-myh3hSFp0YWa2GED11PmbLhV4dv9RdO7YUz27XJrbQLnP5bMbZL6dfOOILTHO57yH0kX5GfuOZBsg/4NamfPvQ==", + "version": "0.0.1061995", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1061995.tgz", + "integrity": "sha512-pKZZWTjWa/IF4ENCg6GN8bu/AxSZgdhjSa26uc23wz38Blt2Tnm9icOPcSG3Cht55rMq35in1w3rWVPcZ60ArA==", "dev": true }, "di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true }, "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", "dev": true }, "diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true }, "dlv": { @@ -27796,15 +31843,9 @@ } }, "chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true - }, - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz", + "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==", "dev": true }, "glob": { @@ -27820,12 +31861,6 @@ "once": "^1.3.0" } }, - "ini": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", - "dev": true - }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -27844,19 +31879,13 @@ "brace-expansion": "^2.0.1" } }, - "strip-json-comments": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", - "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", - "dev": true - }, "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -27870,7 +31899,7 @@ "dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "requires": { "custom-event": "~1.0.0", @@ -27897,12 +31926,38 @@ "dev": true }, "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", "dev": true, "requires": { - "readable-stream": "^2.0.2" + "readable-stream": "~1.1.9" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "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": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + } } }, "duplexify": { @@ -27970,7 +32025,7 @@ "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "requires": { "jsbn": "~0.1.0", @@ -27990,7 +32045,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "ejs": { "version": "3.1.8", @@ -28002,14 +32057,14 @@ } }, "electron-to-chromium": { - "version": "1.4.243", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.243.tgz", - "integrity": "sha512-BgLD2gBX43OSXwlT01oYRRD5NIB4n3okTRxkzEAC6G0SZG4TTlyrWMjbOo0fajCwqwpRtMHXQNMjtRN6qpNtfw==" + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" }, "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "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": { @@ -28021,7 +32076,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "end-of-stream": { "version": "1.4.4", @@ -28033,9 +32088,9 @@ } }, "engine.io": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", - "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", "dev": true, "requires": { "@types/cookie": "^0.4.1", @@ -28048,21 +32103,26 @@ "debug": "~4.3.1", "engine.io-parser": "~5.0.3", "ws": "~8.2.3" + }, + "dependencies": { + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + } } }, "engine.io-parser": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", - "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", - "dev": true, - "requires": { - "@socket.io/base64-arraybuffer": "~1.0.2" - } + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "dev": true }, "enhanced-resolve": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", - "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -28081,7 +32141,7 @@ "ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", "dev": true }, "errno": { @@ -28112,31 +32172,35 @@ } }, "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" } }, "es-get-iterator": { @@ -28161,6 +32225,15 @@ "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -28184,15 +32257,15 @@ } }, "es5-shim": { - "version": "4.6.5", - "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.5.tgz", - "integrity": "sha512-vfQ4UAai8szn0sAubCy97xnZ4sJVDD1gt/Grn736hg8D7540wemIb1YPrYZSTqlM2H69EQX1or4HU/tSwRTI3w==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.7.tgz", + "integrity": "sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==", "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=", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", "dev": true, "requires": { "d": "1", @@ -28203,7 +32276,7 @@ "es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", "dev": true }, "es6-promise": { @@ -28215,7 +32288,7 @@ "es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "dev": true, "requires": { "es6-promise": "^4.0.3" @@ -28251,17 +32324,17 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "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=" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "escodegen": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", "dev": true, "requires": { "esprima": "^2.7.1", @@ -28274,13 +32347,13 @@ "estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", "dev": true }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dev": true, "requires": { "prelude-ls": "~1.1.2", @@ -28304,13 +32377,13 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "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=", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", "dev": true, "optional": true, "requires": { @@ -28320,7 +32393,7 @@ "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "dev": true, "requires": { "prelude-ls": "~1.1.2" @@ -28385,18 +32458,6 @@ "@babel/highlight": "^7.10.4" } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "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-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -28438,18 +32499,24 @@ "dev": true }, "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, + "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 + }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -28481,7 +32548,7 @@ "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=", + "integrity": "sha512-UkFojTV1o0GOe1edOEiuI5ccYLJSuNngtqSeClNzhsmG8KPJ+7mRxgtp2oYhqZAK/brlXMoCd+VgXViE0AfyKw==", "dev": true, "requires": {} }, @@ -28507,13 +32574,12 @@ } }, "eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "debug": "^3.2.7" }, "dependencies": { "debug": { @@ -28538,9 +32604,9 @@ } }, "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "requires": { "array-includes": "^3.1.4", @@ -28548,14 +32614,14 @@ "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "dependencies": { "debug": { @@ -28579,7 +32645,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -28678,7 +32744,7 @@ "esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", "dev": true }, "esquery": { @@ -28736,12 +32802,12 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", "dev": true, "requires": { "d": "1", @@ -28751,7 +32817,7 @@ "event-stream": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==", "dev": true, "requires": { "duplexer": "~0.1.1", @@ -28766,7 +32832,7 @@ "map-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==", "dev": true } } @@ -28814,7 +32880,7 @@ "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true }, "semver": { @@ -28826,7 +32892,7 @@ "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "requires": { "shebang-regex": "^1.0.0" @@ -28835,7 +32901,7 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true }, "which": { @@ -28849,16 +32915,10 @@ } } }, - "exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "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=", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "dev": true, "requires": { "debug": "^2.3.3", @@ -28882,7 +32942,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -28891,7 +32951,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -28900,7 +32960,7 @@ "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=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -28909,7 +32969,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -28926,7 +32986,7 @@ "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=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -28935,7 +32995,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -28957,13 +33017,13 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -28971,66 +33031,95 @@ "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" } }, "expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", "dev": true, "requires": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "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 + } } }, "expect-webdriverio": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-3.1.4.tgz", - "integrity": "sha512-65FTS3bmxcIp0cq6fLb/72TrCQXBCpwPLC7SwMWdpPlLq461mXcK1BPKJJjnIC587aXSKD+3E4hvnlCtwDmXfg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-2.0.2.tgz", + "integrity": "sha512-dst0tqP1aZ2p7TPmbatqoIQ+7hRTw+IeKNi830XxKhu2DNNe5vQ85i9ttf9rpXgbnUf91HxKcocn4G7A5bQxDA==", "dev": true, "requires": { - "expect": "^27.0.2", - "jest-matcher-utils": "^27.0.2" + "expect": "^26.6.2", + "jest-matcher-utils": "^26.6.2" } }, "express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.2", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.2", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.9.7", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.18.0", + "serve-static": "1.15.0", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -29047,28 +33136,23 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "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==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, "ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", "dev": true, "requires": { - "type": "^2.5.0" + "type": "^2.7.2" }, "dependencies": { "type": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", - "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", "dev": true } } @@ -29080,13 +33164,20 @@ "dev": true }, "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "kind-of": "^1.1.0" + }, + "dependencies": { + "kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", + "dev": true + } } }, "external-editor": { @@ -29098,17 +33189,6 @@ "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" - }, - "dependencies": { - "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" - } - } } }, "extglob": { @@ -29130,7 +33210,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -29139,7 +33219,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -29148,7 +33228,7 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true } } @@ -29179,7 +33259,7 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true }, "faker": { @@ -29215,13 +33295,13 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "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=", + "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", "dev": true, "requires": { "websocket-driver": ">=0.5.1" @@ -29230,16 +33310,16 @@ "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "requires": { "pend": "~1.2.0" } }, "fibers": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.1.tgz", - "integrity": "sha512-VMC7Frt87Oo0AOJ6EcPFbi+tZmkQ4tD85aatwyWL6I9cYMJmm2e+pXUJsfGZ36U7MffXtjou2XIiWJMtHriErw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.3.tgz", + "integrity": "sha512-/qYTSoZydQkM21qZpGLDLuCq8c+B8KhuCQ1kLPvnRNhxhVbvrpmH9l2+Lblf5neDuEsY4bfT7LeO553TXQDvJw==", "dev": true, "requires": { "detect-libc": "^1.0.3" @@ -29309,16 +33389,16 @@ } }, "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "dependencies": { @@ -29333,7 +33413,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -29349,12 +33429,13 @@ } }, "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "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": "^2.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, "findup-sync": { @@ -29367,6 +33448,151 @@ "is-glob": "^4.0.0", "micromatch": "^3.0.4", "resolve-dir": "^1.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "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": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "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": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true + } + } + }, + "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": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "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": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "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" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } } }, "fined": { @@ -29416,9 +33642,9 @@ } }, "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "flush-write-stream": { @@ -29432,48 +33658,51 @@ } }, "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "dev": true }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "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=", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", "dev": true, "requires": { "for-in": "^1.0.1" } }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, "foreachasync": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", - "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=", + "integrity": "sha512-J+ler7Ta54FwwNcx6wQRDhTIbNeyDcARMkOcguEqnEdtm0jKvN3Li3PDAb2Du3ubJYEWfYL83XMROXdsXAXycw==", "dev": true }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true }, "fork-stream": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", - "integrity": "sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=", + "integrity": "sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==", "dev": true }, "form-data": { @@ -29495,7 +33724,7 @@ "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "dev": true, "requires": { "map-cache": "^0.2.2" @@ -29504,12 +33733,12 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", "dev": true }, "fs-constants": { @@ -29519,9 +33748,9 @@ "dev": true }, "fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "requires": { "graceful-fs": "^4.2.0", @@ -29532,7 +33761,7 @@ "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=", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -29554,7 +33783,7 @@ "fs.extra": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz", - "integrity": "sha1-3QI/kwE77iRTHxszUUw3sg/ZM0k=", + "integrity": "sha512-Ig401VXtyrWrz23k9KxAx9OrnL8AHSLNhQ8YJH2wSYuH0ZUfxwBeY6zXkd/oOyVRFTlpEu/0n5gHeuZt7aqbkw==", "dev": true, "requires": { "fs-extra": "~0.6.1", @@ -29565,7 +33794,7 @@ "fs-extra": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz", - "integrity": "sha1-9G8MdbeEH40gCzNIzU1pHVoJnRU=", + "integrity": "sha512-5rU898vl/Z948L+kkJedbmo/iltzmiF5bn/eEk0j/SgrPpI+Ydau9xlJPicV7Av2CHYBGz5LAlwTnBU80j1zPQ==", "dev": true, "requires": { "jsonfile": "~1.0.1", @@ -29577,19 +33806,19 @@ "jsonfile": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz", - "integrity": "sha1-6l7+QLg2kLmGZ2FKc5L8YOhCwN0=", + "integrity": "sha512-KbsDJNRfRPF5v49tMNf9sqyyGqGLBcz1v5kZT01kG5ns5mQSltwxCKVmUzVKtEinkUnTDtSrp6ngWpV7Xw0ZlA==", "dev": true }, "mkdirp": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", "dev": true }, "rimraf": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", "dev": true } } @@ -29597,7 +33826,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "fsevents": { @@ -29619,12 +33848,12 @@ }, "dependencies": { "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } }, "rimraf": { @@ -29651,10 +33880,28 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, "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=", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, "gaze": { @@ -29680,17 +33927,17 @@ "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=", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", "dev": true }, "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" } }, "get-package-type": { @@ -29727,13 +33974,13 @@ "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", "dev": true }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "requires": { "assert-plus": "^1.0.0" @@ -29765,15 +34012,15 @@ "dev": true }, "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } @@ -29818,7 +34065,7 @@ "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "requires": { "is-extglob": "^2.1.0" @@ -29860,7 +34107,7 @@ "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" @@ -29868,6 +34115,12 @@ } } }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true + }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -29915,7 +34168,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -29924,7 +34177,7 @@ "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -29957,7 +34210,7 @@ "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "requires": { "is-extglob": "^2.1.0" @@ -29968,18 +34221,99 @@ "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=", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", "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-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "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" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "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" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "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" + } + }, + "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 + } + } + }, "readdirp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", @@ -29994,7 +34328,7 @@ "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=", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, "requires": { "is-number": "^3.0.0", @@ -30027,7 +34361,7 @@ "global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", "dev": true, "requires": { "expand-tilde": "^2.0.2", @@ -30037,6 +34371,12 @@ "which": "^1.2.14" }, "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -30060,13 +34400,13 @@ "dev": true }, "globule": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz", - "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", "dev": true, "requires": { "glob": "~7.1.1", - "lodash": "~4.17.10", + "lodash": "^4.17.21", "minimatch": "~3.0.2" }, "dependencies": { @@ -30124,9 +34464,9 @@ } }, "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "grapheme-splitter": { @@ -30166,56 +34506,6 @@ "vinyl": "^2.1.0" }, "dependencies": { - "arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", - "dev": true, - "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": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", - "dev": true - }, - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", - "dev": true - }, - "extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", - "dev": true, - "requires": { - "kind-of": "^1.1.0" - } - }, - "kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", - "dev": true - }, - "plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", - "dev": true, - "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" - } - }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -30275,19 +34565,19 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", "dev": true }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", "dev": true, "requires": { "string-width": "^1.0.1", @@ -30295,10 +34585,16 @@ "wrap-ansi": "^2.0.0" } }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true + }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "requires": { "path-exists": "^2.0.0", @@ -30311,19 +34607,37 @@ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "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=", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "dev": true, "requires": { "number-is-nan": "^1.0.0" } }, + "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" + } + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, "requires": { "pinkie-promise": "^2.0.0" @@ -30332,7 +34646,7 @@ "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "requires": { "load-json-file": "^1.0.0", @@ -30343,23 +34657,23 @@ "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=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "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=", + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -30370,22 +34684,16 @@ "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "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=", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", "dev": true, "requires": { "string-width": "^1.0.1", @@ -30434,7 +34742,7 @@ "gulp-concat": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", - "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", + "integrity": "sha512-a2scActrQrDBpBbR3WUZGyGS1JEPLg5PZJdIa7/Bi3GuKAmPYDK6SFhy/NZq5R8KsKKFvtfR0fakbUCcKGCCjg==", "dev": true, "requires": { "concat-with-sourcemaps": "^1.0.0", @@ -30486,10 +34794,22 @@ "ms": "2.0.0" } }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "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=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "requires": { "depd": "~1.1.2", @@ -30501,7 +34821,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "mime": { @@ -30513,9 +34833,18 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, "send": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", @@ -30562,12 +34891,33 @@ "plugin-error": "^1.0.1" }, "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": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -30661,18 +35011,6 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "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" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -30710,6 +35048,16 @@ "eslint-visitor-keys": "^1.1.0" } }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", @@ -30745,6 +35093,12 @@ "type-fest": "^0.8.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 + }, "inquirer": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", @@ -30832,6 +35186,18 @@ "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true }, + "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" + } + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -30853,15 +35219,6 @@ "glob": "^7.1.3" } }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -30989,7 +35346,7 @@ "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=", + "integrity": "sha512-F+53crhLb78CTlG7ZZJFWzP0+/4q0vt2/pULXFkTMs6AGBo0Eh5cx+eWsqqHv8hrNIUsuTab3Se8rOOzP/6+EQ==", "dev": true, "requires": { "through2": "^0.6.3" @@ -30998,13 +35355,13 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "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=", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -31016,13 +35373,13 @@ "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true }, "through2": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", "dev": true, "requires": { "readable-stream": ">=1.0.33-1 <1.1.0-0", @@ -31054,9 +35411,9 @@ }, "dependencies": { "@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", + "version": "14.18.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", + "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", "dev": true } } @@ -31075,6 +35432,15 @@ "tslib": "^1.10.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-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -31084,6 +35450,18 @@ "color-convert": "^2.0.1" } }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, "chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -31109,6 +35487,34 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.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 + }, + "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" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -31183,6 +35589,51 @@ "terser": "^5.9.0", "through2": "^4.0.2", "vinyl-sourcemaps-apply": "^0.2.1" + }, + "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" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "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" + } + } } }, "gulp-util": { @@ -31214,19 +35665,19 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -31239,24 +35690,15 @@ "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "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=", + "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", "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.template": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", @@ -31277,7 +35719,7 @@ "lodash.templatesettings": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "integrity": "sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ==", "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0", @@ -31287,13 +35729,13 @@ "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=", + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", "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=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -31302,7 +35744,7 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true }, "through2": { @@ -31318,7 +35760,7 @@ "vinyl": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "integrity": "sha512-P5zdf3WB9uzr7IFoVQ2wZTmUwHL8cMZWJGzLBNCHNZ3NB6HTMsYABtt7z8tAGIINLXyAob9B9a1yzVGMFOYKEA==", "dev": true, "requires": { "clone": "^1.0.0", @@ -31331,7 +35773,7 @@ "gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", "dev": true, "requires": { "glogg": "^1.0.0" @@ -31370,7 +35812,7 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true }, "har-validator": { @@ -31381,20 +35823,6 @@ "requires": { "ajv": "^6.12.3", "har-schema": "^2.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - } } }, "has": { @@ -31408,7 +35836,7 @@ "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -31417,32 +35845,40 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true } } }, "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "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 + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "has-gulplog": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==", "dev": true, "requires": { "sparkles": "^1.0.0" } }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -31460,7 +35896,7 @@ "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "dev": true, "requires": { "get-value": "^2.0.6", @@ -31471,7 +35907,7 @@ "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=", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "dev": true, "requires": { "is-number": "^3.0.0", @@ -31484,10 +35920,30 @@ "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": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "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": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "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=", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -31553,7 +36009,7 @@ "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=", + "integrity": "sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg==", "dev": true, "requires": { "os-homedir": "^1.0.0", @@ -31570,10 +36026,13 @@ } }, "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "html-escaper": { "version": "2.0.2", @@ -31594,21 +36053,21 @@ "dev": true }, "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "requires": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "http-parser-js": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", - "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "http-proxy": { @@ -31625,7 +36084,7 @@ "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -31644,12 +36103,12 @@ } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "requires": { - "agent-base": "5", + "agent-base": "6", "debug": "4" } }, @@ -31694,7 +36153,13 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ==", "dev": true }, "individual": { @@ -31706,7 +36171,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "requires": { "once": "^1.3.0", @@ -31719,15 +36184,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", "dev": true }, "inquirer": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.5.tgz", - "integrity": "sha512-G6/9xUqmt/r+UvufSyrPpt84NYwhKZ9jLsgMbQzlx804XErNupor8WQdBnBRrXmBfTPpuwf1sV+ss2ovjgdXIg==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", "dev": true, "requires": { "ansi-escapes": "^4.2.1", @@ -31740,10 +36205,11 @@ "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^7.2.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" }, "dependencies": { "ansi-styles": { @@ -31780,6 +36246,21 @@ "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 + }, + "rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -31788,6 +36269,12 @@ "requires": { "has-flag": "^4.0.0" } + }, + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true } } }, @@ -31820,7 +36307,7 @@ "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=", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", "dev": true }, "ipaddr.js": { @@ -31868,7 +36355,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "is-bigint": { @@ -31906,15 +36393,15 @@ "dev": true }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "requires": { "has": "^1.0.3" } @@ -31993,7 +36480,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, "is-finite": { @@ -32057,7 +36544,7 @@ "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=", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", "dev": true }, "is-negative-zero": { @@ -32067,35 +36554,15 @@ "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": { - "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" - } - } - } + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "requires": { "has-tostringtag": "^1.0.0" @@ -32141,7 +36608,7 @@ "is-running": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz", - "integrity": "sha1-MKc/9cw4VOT8JUkICen1q/jeCeA=", + "integrity": "sha512-mjJd3PujZMl7j+D395WTIO5tU5RIDBfVSRtRR4VOJou3H66E38UjbjvDGh3slJzPuolsb+yQFqwHNNdyp5jg3w==", "dev": true }, "is-set": { @@ -32151,10 +36618,13 @@ "dev": true }, "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } }, "is-ssh": { "version": "1.4.0", @@ -32168,7 +36638,7 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true }, "is-string": { @@ -32190,22 +36660,22 @@ } }, "is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", + "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", "dev": true, "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0" } }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "is-unc-path": { @@ -32226,13 +36696,13 @@ "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", "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=", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", "dev": true }, "is-weakmap": { @@ -32282,33 +36752,33 @@ "dev": true }, "isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "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=", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "istanbul": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", - "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "integrity": "sha512-nMtdn4hvK0HjUlzr1DrKSUY8ychprt8dzHOgY2KXsIhHu5PuQQEOTM27gV9Xblyon7aUH/TSFIjRHEODF/FRPg==", "dev": true, "requires": { "abbrev": "1.0.x", @@ -32330,7 +36800,7 @@ "glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", "dev": true, "requires": { "inflight": "^1.0.4", @@ -32343,28 +36813,28 @@ "has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", "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==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } }, "resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", "dev": true }, "supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", "dev": true, "requires": { "has-flag": "^1.0.0" @@ -32387,6 +36857,19 @@ "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true }, + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, "istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", @@ -32398,6 +36881,12 @@ "supports-color": "^7.1.0" }, "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32429,9 +36918,9 @@ } }, "istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -32500,6 +36989,12 @@ "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.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32512,15 +37007,15 @@ } }, "jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "dependencies": { "ansi-styles": { @@ -32557,6 +37052,12 @@ "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.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32569,21 +37070,21 @@ } }, "jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", "dev": true }, "jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "dependencies": { "ansi-styles": { @@ -32620,6 +37121,12 @@ "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.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32632,20 +37139,20 @@ } }, "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "stack-utils": "^2.0.2" }, "dependencies": { "ansi-styles": { @@ -32682,15 +37189,17 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } + "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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true }, "supports-color": { "version": "7.2.0", @@ -32703,6 +37212,12 @@ } } }, + "jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "dev": true + }, "jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -32712,6 +37227,23 @@ "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "js-tokens": { @@ -32740,7 +37272,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "jsesc": { @@ -32754,12 +37286,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "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-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -32781,13 +37307,13 @@ "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=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "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=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, "json5": { @@ -32820,7 +37346,7 @@ "just-clone": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", - "integrity": "sha1-v7P672WqEqMWBYcSlFwyb9jwFDQ=" + "integrity": "sha512-p93GINPwrve0w3HUzpXmpTl7MyzzWz1B5ag44KEtq/hP1mtK8lA2b9Q0VQaPlnY87352osJcE6uBmN0e8kuFMw==" }, "just-debounce": { "version": "1.1.0", @@ -32835,9 +37361,9 @@ "dev": true }, "karma": { - "version": "6.3.17", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.17.tgz", - "integrity": "sha512-2TfjHwrRExC8yHoWlPBULyaLwAFmXmxQrcuFImt/JsAsSZu1uOWTZ1ZsWjqQtWpHLiatJOHL5jFjXSJIgCd01g==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz", + "integrity": "sha512-Cj57NKOskK7wtFWSlMvZf459iX+kpYIPXmkNUzP2WAFcA7nhr/ALn5R7sw3w+1udFDcpMx/tuB8d5amgm3ijaA==", "dev": true, "requires": { "@colors/colors": "1.5.0", @@ -32859,20 +37385,31 @@ "qjobs": "^1.2.0", "range-parser": "^1.2.1", "rimraf": "^3.0.2", - "socket.io": "^4.2.0", + "socket.io": "^4.4.1", "source-map": "^0.6.1", "tmp": "^0.2.1", "ua-parser-js": "^0.7.30", "yargs": "^16.1.1" }, "dependencies": { + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } }, "source-map": { @@ -32881,6 +37418,15 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -32925,14 +37471,14 @@ "karma-chai": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", - "integrity": "sha1-vuWtQEAFF4Ea40u5RfdikJEIt5o=", + "integrity": "sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg==", "dev": true, "requires": {} }, "karma-chrome-launcher": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", - "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", "dev": true, "requires": { "which": "^1.2.1" @@ -32961,21 +37507,6 @@ "istanbul-lib-source-maps": "^4.0.1", "istanbul-reports": "^3.0.5", "minimatch": "^3.0.4" - }, - "dependencies": { - "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - } } }, "karma-coverage-istanbul-reporter": { @@ -33054,7 +37585,7 @@ "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=", + "integrity": "sha512-8xU6F2/R6u6HAZ/nlyhhx3WEhj4C6hJorG7FR2REX81pgj2LSo9ADJXxCGIeXg6Qr2BGpxp4hcZcEOYGAwiumg==", "dev": true, "requires": { "es5-shim": "^4.0.5" @@ -33073,7 +37604,7 @@ "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=", + "integrity": "sha512-ts71ke8pHvw6qdRtq0+7VY3ANLoZuUNNkA8abRaWV13QRPNm7TtSOqyszjHUtuwOWKcsSz4tbUtrNICrQC+SXQ==", "dev": true, "requires": { "lodash": "^4.6.1" @@ -33091,7 +37622,7 @@ "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=", + "integrity": "sha512-Hr6nhkIp0GIJJrvzY8JFeHpQZNseuIakGac4bpw8K1+5F0tLb6l7uvXRa8mt2Z+NVwYgCct4QAfp2R2QP6o00w==", "dev": true, "requires": { "chalk": "^2.1.0", @@ -33108,7 +37639,7 @@ "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "dev": true, "requires": { "ansi-regex": "^3.0.0" @@ -33119,28 +37650,28 @@ "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=", + "integrity": "sha512-rdty4FlVIowmUhPuG08TeXKHvaRxeDSzPxGIkWguCF3A32kE0uvXZ6dXW08PuaNjai8Ip3f5Pn9Pm2HlChaxCw==", "dev": true, "requires": {} }, "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=", + "integrity": "sha512-qmypLWd6F2qrDJfAETvXDfxHvKDk+nyIjpH9xIeI3/hENr0U3nuqkxaftq73PfXZ4aOuOChA6SnLW4m4AxfRjQ==", "dev": true, "requires": {} }, "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=", + "integrity": "sha512-5NRc8KmTBjNPE3dNfpJP90BArnBohYV4//MsLFfUA1e6N+G1/A5WuWctaFBtMQ6MWRybs/oguSej0JwDr8gInA==", "dev": true, "requires": {} }, "karma-sinon": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/karma-sinon/-/karma-sinon-1.0.5.tgz", - "integrity": "sha1-TjRD8oMP3s/2JNN0cWPxIX2qKpo=", + "integrity": "sha512-wrkyAxJmJbn75Dqy17L/8aILJWFm7znd1CE8gkyxTBFnjMSOe2XTJ3P30T8SkxWZHmoHX0SCaUJTDBEoXs25Og==", "dev": true, "requires": {} }, @@ -33156,7 +37687,7 @@ "karma-spec-reporter": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.32.tgz", - "integrity": "sha1-LpxyB+pyZ3EmAln4K+y1QyCeRAo=", + "integrity": "sha512-ZXsYERZJMTNRR2F3QN11OWF5kgnT/K2dzhM+oY3CDyMrDI3TjIWqYGG7c15rR9wjmy9lvdC+CCshqn3YZqnNrA==", "dev": true, "requires": { "colors": "^1.1.2" @@ -33180,9 +37711,9 @@ "dev": true }, "keyv": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.1.1.tgz", - "integrity": "sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz", + "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==", "dev": true, "requires": { "json-buffer": "3.0.1" @@ -33219,7 +37750,7 @@ "last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", "dev": true, "requires": { "default-resolution": "^2.0.0", @@ -33238,7 +37769,7 @@ "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", "dev": true, "requires": { "invert-kv": "^1.0.0" @@ -33247,13 +37778,13 @@ "lcov-parse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", - "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", + "integrity": "sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==", "dev": true }, "lead": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", "dev": true, "requires": { "flush-write-stream": "^1.0.2" @@ -33318,7 +37849,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -33332,7 +37863,7 @@ "listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", "dev": true }, "live-connect-js": { @@ -33389,19 +37920,29 @@ } }, "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true }, + "loader-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", + "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "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": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" } }, "lodash": { @@ -33413,126 +37954,135 @@ "lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", "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=", + "integrity": "sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA==", "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=", + "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==", "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=", + "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", "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=", + "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", "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=", + "integrity": "sha512-Sjlavm5y+FUVIF3vF3B75GyXrzsfYV8Dlv3L4mEpuB9leg8N6yf/7rU06iLPx9fY0Mv3khVp9p7Dx0mGV6V5OQ==", "dev": true }, "lodash._reevaluate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", + "integrity": "sha512-OrPwdDc65iJiBeUe5n/LIjd7Viy99bKwDdk7Z5ljfZg0uFRFlfQaCy9tZ4YMAag9WAZmlVpe1iZrkIMMSMHD3w==", "dev": true }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", "dev": true }, "lodash._root": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==", "dev": true }, "lodash.clone": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", + "integrity": "sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg==", "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=", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", "dev": true }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true }, "lodash.difference": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", "dev": true }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==", + "dev": true, + "requires": { + "lodash._root": "^3.0.0" + } + }, "lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "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=", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "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=", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "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=", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", "dev": true }, "lodash.isarray": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", "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=", + "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==", "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=", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, "lodash.keys": { @@ -33555,19 +38105,19 @@ "lodash.pickby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=", + "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==", "dev": true }, "lodash.restparam": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", "dev": true }, "lodash.some": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==", "dev": true }, "lodash.template": { @@ -33592,19 +38142,19 @@ "lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true }, "lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", "dev": true }, "lodash.zip": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", - "integrity": "sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", "dev": true }, "log-driver": { @@ -33623,16 +38173,16 @@ } }, "log4js": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.4.2.tgz", - "integrity": "sha512-k80cggS2sZQLBwllpT1p06GtfvzMmSdUCkW96f0Hj83rKGJDAu2vZjt9B9ag2vx8Zz1IXzxoLgqvRJCdMKybGg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", + "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", "dev": true, "requires": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "flatted": "^3.2.5", + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", "rfdc": "^1.3.0", - "streamroller": "^3.0.4" + "streamroller": "^3.1.3" } }, "loglevel": { @@ -33695,7 +38245,7 @@ "lru-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", "dev": true, "requires": { "es5-ext": "~0.10.2" @@ -33751,7 +38301,7 @@ "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true }, "map-obj": { @@ -33763,13 +38313,13 @@ "map-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", "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=", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, "requires": { "object-visit": "^1.0.0" @@ -33782,15 +38332,15 @@ "dev": true }, "marky": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.4.tgz", - "integrity": "sha512-zd2/GiSn6U3/jeFVZ0J9CA1LzQ8RfIVvXkb/U0swFHF/zT+dVohTAWjmo2DcIuofmIIIROlwTbd+shSeXmxr0w==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", "dev": true }, "matchdep": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", "dev": true, "requires": { "findup-sync": "^2.0.0", @@ -33799,10 +38349,90 @@ "stack-trace": "0.0.10" }, "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "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": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "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": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true + } + } + }, "findup-sync": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", "dev": true, "requires": { "detect-file": "^1.0.0", @@ -33811,14 +38441,77 @@ "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=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "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": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "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": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "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" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } } } }, @@ -33929,11 +38622,12 @@ } }, "mdast-util-gfm-table": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.4.tgz", - "integrity": "sha512-aEuoPwZyP4iIMkf2cLWXxx3EQ6Bmh2yKy9MVCg4i6Sd3cX80dcLEfXO/V4ul3pGH9czBK4kp+FAl+ZHmSUt9/w==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.6.tgz", + "integrity": "sha512-uHR+fqFq3IvB3Rd4+kzXW8dmpxUhvgCQZep6KdjsLK4O6meK5dYZEayLtIxNus1XO3gfjfcIFe8a7L0HZRGgag==", "dev": true, "requires": { + "@types/mdast": "^3.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^1.0.0", "mdast-util-to-markdown": "^1.3.0" @@ -33952,24 +38646,22 @@ "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=", + "integrity": "sha512-CcJ0mHa36QYumDKiZ2OIR+ClhfOM7zIzN+Wfy8tRZ1hpH9DKLCS+Mh4DyK5bCxzE9uxMWcbIpeNFWsg1zrj/2g==", "dev": true, "requires": { "mdast-util-to-string": "^1.0.0" } }, "mdast-util-to-hast": { - "version": "12.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.1.tgz", - "integrity": "sha512-dyindR2P7qOqXO1hQirZeGtVbiX7xlNQbw7gGaAwN4A1dh4+X8xU/JyYmRoyB8Fu1uPXzp7mlL5QwW7k+knvgA==", + "version": "12.2.4", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.4.tgz", + "integrity": "sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==", "dev": true, "requires": { "@types/hast": "^2.0.0", "@types/mdast": "^3.0.0", - "@types/mdurl": "^1.0.0", "mdast-util-definitions": "^5.0.0", - "mdurl": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-sanitize-uri": "^1.1.0", "trim-lines": "^3.0.0", "unist-builder": "^3.0.0", "unist-util-generated": "^2.0.0", @@ -34051,16 +38743,10 @@ } } }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "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=" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "memoizee": { "version": "0.4.15", @@ -34091,7 +38777,7 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "merge-stream": { "version": "2.0.0", @@ -34102,12 +38788,12 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "micromark": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz", - "integrity": "sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", "dev": true, "requires": { "@types/debug": "^4.0.0", @@ -34397,9 +39083,9 @@ } }, "micromark-util-sanitize-uri": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz", - "integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", "dev": true, "requires": { "micromark-util-character": "^1.0.0", @@ -34432,100 +39118,13 @@ "dev": true }, "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "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" - }, - "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-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "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 - }, - "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" - } - } + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mime": { @@ -34535,16 +39134,16 @@ "dev": true }, "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "requires": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" } }, "mimic-fn": { @@ -34578,9 +39177,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, "mixin-deep": { @@ -34634,6 +39233,12 @@ "yargs-unparser": "2.0.0" }, "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==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -34649,15 +39254,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -34679,6 +39275,17 @@ } } }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -34694,22 +39301,11 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "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 - } - } + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true }, "escape-string-regexp": { "version": "4.0.0", @@ -34727,6 +39323,37 @@ "path-exists": "^4.0.0" } }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "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" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "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 + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -34762,6 +39389,17 @@ "dev": true, "requires": { "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + } } }, "ms": { @@ -34770,12 +39408,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -34794,23 +39426,20 @@ "p-limit": "^3.0.2" } }, - "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 - }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } }, "yargs": { "version": "16.2.0", @@ -34857,17 +39486,20 @@ "ms": "2.0.0" } }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } } } }, @@ -34890,9 +39522,9 @@ "dev": true }, "mrmime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", - "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", "dev": true }, "ms": { @@ -34903,45 +39535,10 @@ "multipipe": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "integrity": "sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q==", "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 - } } }, "mute-stdout": { @@ -34974,11 +39571,10 @@ "optional": true }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "optional": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true }, "nanomatch": { "version": "1.2.13", @@ -34999,6 +39595,22 @@ "to-regex": "^3.0.1" }, "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -35010,13 +39622,13 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "ncp": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", - "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", + "integrity": "sha512-PfGU8jYWdRl4FqJfCy0IzbkGyFHntfWygZg46nFk/dJD/XRrk2cj0SsKSX9n5u5gE0E0YfEpKWrEkfjnlZSTXA==", "dev": true }, "negotiator": { @@ -35068,7 +39680,7 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "lolex": { @@ -35108,29 +39720,32 @@ "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", "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==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, @@ -35158,7 +39773,7 @@ "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=", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", "dev": true, "requires": { "path-key": "^2.0.0" @@ -35167,7 +39782,7 @@ "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true } } @@ -35175,7 +39790,7 @@ "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=", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", "dev": true }, "oauth-sign": { @@ -35187,13 +39802,13 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, "requires": { "copy-descriptor": "^0.1.0", @@ -35204,7 +39819,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -35213,7 +39828,7 @@ "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=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -35228,7 +39843,7 @@ "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=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -35256,7 +39871,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -35265,10 +39880,9 @@ } }, "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" }, "object-is": { "version": "1.1.5", @@ -35283,32 +39897,34 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, "requires": { "isobject": "^3.0.0" } }, "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" } }, "object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", "dev": true, "requires": { "array-each": "^1.0.1", @@ -35320,7 +39936,7 @@ "object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", "dev": true, "requires": { "for-own": "^1.0.0", @@ -35330,7 +39946,7 @@ "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, "requires": { "isobject": "^3.0.1" @@ -35339,7 +39955,7 @@ "object.reduce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", "dev": true, "requires": { "for-own": "^1.0.0", @@ -35358,9 +39974,9 @@ } }, "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "requires": { "ee-first": "1.1.1" } @@ -35374,7 +39990,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "requires": { "wrappy": "1" @@ -35407,7 +40023,7 @@ "is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", "dev": true } } @@ -35477,6 +40093,12 @@ "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 + }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -35501,7 +40123,7 @@ "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=", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", "dev": true, "requires": { "readable-stream": "^2.0.1" @@ -35510,13 +40132,13 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", "dev": true }, "os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", "dev": true, "requires": { "lcid": "^1.0.0" @@ -35525,7 +40147,7 @@ "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=", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true }, "p-cancelable": { @@ -35537,7 +40159,7 @@ "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "dev": true }, "p-iteration": { @@ -35547,27 +40169,27 @@ "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==", + "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": "^1.0.0" + "p-try": "^2.0.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "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": "^1.1.0" + "p-limit": "^2.2.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=", + "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 }, "parent-module": { @@ -35582,7 +40204,7 @@ "parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, "requires": { "is-absolute": "^1.0.0", @@ -35617,7 +40239,7 @@ "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true }, "parse-path": { @@ -35649,25 +40271,25 @@ "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "dev": true }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", "dev": true }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, "path-key": { @@ -35684,7 +40306,7 @@ "path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, "requires": { "path-root-regex": "^0.1.0" @@ -35693,13 +40315,13 @@ "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=", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "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=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "path-type": { "version": "1.1.0", @@ -35729,7 +40351,7 @@ "pause-stream": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", "dev": true, "requires": { "through": "~2.3" @@ -35738,13 +40360,13 @@ "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, "picocolors": { @@ -35767,13 +40389,13 @@ "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "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=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "requires": { "pinkie": "^2.0.0" @@ -35795,98 +40417,46 @@ "dev": true, "requires": { "find-up": "^4.0.0" - }, - "dependencies": { - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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 - } } }, "plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", "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" - } - } + "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" } }, "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=", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true }, "postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "version": "8.4.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", + "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", "dev": true, "optional": true, "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" + }, + "dependencies": { + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "optional": true + } } }, "prelude-ls": { @@ -35896,20 +40466,39 @@ "dev": true }, "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", "react-is": "^17.0.1" }, "dependencies": { "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "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 } } @@ -35917,7 +40506,7 @@ "pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", "dev": true }, "pretty-ms": { @@ -35929,12 +40518,6 @@ "parse-ms": "^2.1.0" } }, - "printj": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.3.1.tgz", - "integrity": "sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg==", - "dev": true - }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -35989,7 +40572,7 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true }, "ps-tree": { @@ -36004,13 +40587,13 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", "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==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "pump": { @@ -36065,16 +40648,16 @@ "dev": true }, "puppeteer-core": { - "version": "13.5.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.5.1.tgz", - "integrity": "sha512-dobVqWjV34ilyfQHR3BBnCYaekBYTi5MgegEYBRYd3s3uFy8jUpZEEWbaFjG9ETm+LGzR5Lmr0aF6LLuHtiuCg==", + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.7.0.tgz", + "integrity": "sha512-rXja4vcnAzFAP1OVLq/5dWNfwBGuzcOARJ6qGV7oAZhnLmVRU8G5MsdeQEAOy332ZhkIOnn9jp15R89LKHyp2Q==", "dev": true, "requires": { "cross-fetch": "3.1.5", - "debug": "4.3.3", - "devtools-protocol": "0.0.969999", + "debug": "4.3.4", + "devtools-protocol": "0.0.981744", "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.0", + "https-proxy-agent": "5.0.1", "pkg-dir": "4.2.0", "progress": "2.0.3", "proxy-from-env": "1.1.0", @@ -36084,31 +40667,12 @@ "ws": "8.5.0" }, "dependencies": { - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, "devtools-protocol": { - "version": "0.0.969999", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.969999.tgz", - "integrity": "sha512-6GfzuDWU0OFAuOvBokXpXPLxjOJ5DZ157Ue3sGQQM3LgAamb8m0R0ruSfN0DDu+XG5XJgT50i6zZ/0o8RglreQ==", + "version": "0.0.981744", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", + "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==", "dev": true }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, "ws": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", @@ -36121,7 +40685,7 @@ "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", "dev": true }, "qjobs": { @@ -36131,9 +40695,12 @@ "dev": true }, "qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } }, "query-selector-shadow-dom": { "version": "1.0.0", @@ -36144,7 +40711,7 @@ "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", "dev": true }, "querystringify": { @@ -36174,12 +40741,12 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "requires": { "bytes": "3.1.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } @@ -36202,36 +40769,6 @@ "type-fest": "^2.0.0" }, "dependencies": { - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - } - }, - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, "type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -36326,18 +40863,44 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "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==", "dev": true } } }, "readdir-glob": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", - "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.2.tgz", + "integrity": "sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==", "dev": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "^5.1.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "readdirp": { @@ -36352,30 +40915,19 @@ "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, "requires": { "resolve": "^1.1.6" } }, "recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", "dev": true, "requires": { - "minimatch": "3.0.4" - }, - "dependencies": { - "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" - } - } + "minimatch": "^3.0.5" } }, "regenerate": { @@ -36384,23 +40936,22 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", "requires": { "regenerate": "^1.4.2" } }, "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", + "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" }, "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "requires": { "@babel/runtime": "^7.8.4" } @@ -36413,16 +40964,29 @@ "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + } } }, "regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" } }, "regexpp": { @@ -36432,27 +40996,27 @@ "dev": true }, "regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", "requires": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" } }, "regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" }, "regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "requires": { "jsesc": "~0.5.0" }, @@ -36460,7 +41024,7 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" } } }, @@ -36566,7 +41130,7 @@ "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=", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", "dev": true, "requires": { "remove-bom-buffer": "^3.0.0", @@ -36589,7 +41153,7 @@ "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=", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", "dev": true }, "repeat-element": { @@ -36601,13 +41165,13 @@ "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==", "dev": true, "requires": { "is-finite": "^1.0.0" @@ -36616,13 +41180,13 @@ "replace-ext": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==", "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=", + "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1", @@ -36680,7 +41244,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, "require-from-string": { @@ -36689,10 +41253,16 @@ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, "resolve": { @@ -36714,7 +41284,7 @@ "resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, "requires": { "expand-tilde": "^2.0.0", @@ -36730,7 +41300,7 @@ "resolve-options": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", "dev": true, "requires": { "value-or-function": "^3.0.0" @@ -36739,13 +41309,13 @@ "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", "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==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", "dev": true, "requires": { "lowercase-keys": "^2.0.0" @@ -36763,7 +41333,7 @@ "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=", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", "dev": true } } @@ -36821,20 +41391,12 @@ } }, "rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, "requires": { - "tslib": "^2.1.0" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } + "tslib": "^1.9.0" } }, "sade": { @@ -36847,25 +41409,36 @@ } }, "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==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "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=", + "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", "dev": true }, "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, "requires": { "ret": "~0.1.10" } }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -36899,13 +41472,6 @@ "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} } } }, @@ -36917,30 +41483,30 @@ "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=", + "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", "dev": true, "requires": { "sver-compat": "^1.5.0" } }, "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "dependencies": { "debug": { @@ -36954,7 +41520,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -36999,7 +41565,7 @@ "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, "requires": { "accepts": "~1.3.4", @@ -37020,10 +41586,16 @@ "ms": "2.0.0" } }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "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=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "requires": { "depd": "~1.1.2", @@ -37035,13 +41607,13 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "setprototypeof": { @@ -37049,24 +41621,30 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true } } }, "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.18.0" } }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, "set-value": { @@ -37084,7 +41662,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -37093,7 +41671,7 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true }, "is-plain-object": { @@ -37110,7 +41688,7 @@ "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "dev": true }, "setprototypeof": { @@ -37137,7 +41715,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -37170,21 +41747,6 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "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 - }, - "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" - } } } }, @@ -37200,9 +41762,9 @@ } }, "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", "dev": true }, "slice-ansi": { @@ -37270,7 +41832,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -37279,7 +41841,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "requires": { "is-extendable": "^0.1.0" @@ -37288,7 +41850,7 @@ "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=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -37297,7 +41859,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -37314,7 +41876,7 @@ "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=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -37323,7 +41885,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -37345,13 +41907,13 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "source-map-resolve": { @@ -37383,7 +41945,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "requires": { "is-descriptor": "^1.0.0" @@ -37409,7 +41971,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -37418,33 +41980,32 @@ } }, "socket.io": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", - "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", "dev": true, "requires": { "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.2", - "engine.io": "~6.1.0", - "socket.io-adapter": "~2.3.3", - "socket.io-parser": "~4.0.4" + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" } }, "socket.io-adapter": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", - "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", "dev": true }, "socket.io-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", - "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", "dev": true, "requires": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" } }, @@ -37457,7 +42018,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true }, "source-map-js": { @@ -37478,21 +42039,12 @@ } }, "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "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": { - "buffer-from": "^1.0.0", - "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 - } + "source-map": "^0.5.6" } }, "source-map-url": { @@ -37547,15 +42099,15 @@ } }, "spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", "dev": true }, "split": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==", "dev": true, "requires": { "through": "2" @@ -37568,18 +42120,46 @@ "dev": true, "requires": { "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + } } }, "split2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", - "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", - "dev": true + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "requires": { + "readable-stream": "^3.0.0" + }, + "dependencies": { + "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" + } + } + } }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "sshpk": { @@ -37602,7 +42182,7 @@ "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", "dev": true }, "stack-utils": { @@ -37625,7 +42205,7 @@ "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "dev": true, "requires": { "define-property": "^0.2.5", @@ -37635,7 +42215,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "requires": { "is-descriptor": "^0.1.0" @@ -37644,7 +42224,7 @@ "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=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -37653,7 +42233,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -37670,7 +42250,7 @@ "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=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -37679,7 +42259,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -37701,9 +42281,9 @@ } }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, "stream-buffers": { "version": "3.0.2", @@ -37714,7 +42294,7 @@ "stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==", "dev": true, "requires": { "duplexer": "~0.1.1" @@ -37733,14 +42313,42 @@ "dev": true }, "streamroller": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.4.tgz", - "integrity": "sha512-GI9NzeD+D88UFuIlJkKNDH/IsuR+qIN7Qh8EsmhoRZr9bQoehTraRgwtLUkZbpcAw+hLPfHOypmppz8YyGK68w==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz", + "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==", "dev": true, "requires": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "fs-extra": "^10.0.1" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "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": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "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 + } } }, "string_decoder": { @@ -37750,12 +42358,20 @@ "dev": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "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==", + "dev": true + } } }, "string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", "dev": true }, "string-width": { @@ -37767,34 +42383,28 @@ "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" - }, - "dependencies": { - "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 - } } }, "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "stringify-entities": { @@ -37819,34 +42429,39 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true }, "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=", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", "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=", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true + }, + "strip-json-comments": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", + "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", "dev": true }, "suffix": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", - "integrity": "sha1-zFgjFkag7xEC95R47zqSSP2chC8=", + "integrity": "sha512-j5uf6MJtMCfC4vBe5LFktSe4bGyNTBk7I2Kdri0jeLrcv5B9pWfxVa5JQpoxgtR8vaVB7bVxsWgnfQbX5wkhAA==", "dev": true }, "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" } }, "supports-preserve-symlinks-flag": { @@ -37857,7 +42472,7 @@ "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=", + "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", "dev": true, "requires": { "es6-iterator": "^2.0.1", @@ -37878,9 +42493,9 @@ }, "dependencies": { "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -37944,7 +42559,7 @@ "temp-fs": { "version": "0.9.9", "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz", - "integrity": "sha1-gHFzBDeHByDpQxUy/igUNk+IA9c=", + "integrity": "sha512-WfecDCR1xC9b0nsrzSaxPf3ZuWeWLUWblW4vlDQAa1biQaKHiImHnJfeQocQe/hXKMcolRzgkcVX/7kK4zoWbw==", "dev": true, "requires": { "rimraf": "~2.5.2" @@ -37953,7 +42568,7 @@ "rimraf": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", - "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", + "integrity": "sha512-Lw7SHMjssciQb/rRz7JyPIy9+bbUshEucPoLRvWqy09vC5zQixl8Uet+Zl+SROBB/JMWHJRdCk1qdxNWHNMvlQ==", "dev": true, "requires": { "glob": "^7.0.5" @@ -37986,9 +42601,9 @@ } }, "terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", "dev": true, "requires": { "@jridgewell/source-map": "^0.3.2", @@ -37998,30 +42613,40 @@ }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "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==", + "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.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } } } }, "terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.14", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" + "terser": "^5.14.1" }, "dependencies": { "ajv": { @@ -38036,13 +42661,6 @@ "uri-js": "^4.2.2" } }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, "schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -38053,12 +42671,6 @@ "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } - }, - "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 } } }, @@ -38076,7 +42688,7 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "textextensions": { @@ -38088,7 +42700,7 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, "through2": { @@ -38138,7 +42750,7 @@ "time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", "dev": true }, "timers-ext": { @@ -38182,18 +42794,18 @@ } }, "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "rimraf": "^3.0.0" + "os-tmpdir": "~1.0.2" } }, "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=", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", "dev": true, "requires": { "is-absolute": "^1.0.0", @@ -38203,12 +42815,12 @@ "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=" + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, "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=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -38223,7 +42835,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "requires": { "is-buffer": "^1.1.5" @@ -38241,6 +42853,18 @@ "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + } } }, "to-regex-range": { @@ -38250,20 +42874,12 @@ "dev": true, "requires": { "is-number": "^7.0.0" - }, - "dependencies": { - "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 - } } }, "to-through": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", "dev": true, "requires": { "through2": "^2.0.3" @@ -38305,13 +42921,13 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, "traverse": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", "dev": true }, "trim-lines": { @@ -38323,7 +42939,7 @@ "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "integrity": "sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==", "dev": true }, "trough": { @@ -38333,14 +42949,14 @@ "dev": true }, "tsconfig-paths": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz", - "integrity": "sha512-nWuffZppoaYK0vQ1SQmkSsQzJoHA4s6uzdb2waRpD806x9yfq153AdVsWz4je2qZcW+pENrMQXbGQ3sMCkXuhw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, "requires": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" }, "dependencies": { @@ -38364,7 +42980,7 @@ "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "requires": { "safe-buffer": "^5.0.1" @@ -38373,7 +42989,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, "type": { @@ -38415,7 +43031,7 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, "typescript": { @@ -38447,27 +43063,27 @@ } }, "ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "version": "0.7.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", + "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", "dev": true }, "uglify-js": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz", - "integrity": "sha512-peeoTk3hSwYdoc9nrdiEJk+gx1ALCtTjdYuKSXMTDqq7n1W7dHPqWDdSi+BPL0ni2YMeHD7hKUSdbj3TZauY2A==", + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, "optional": true }, "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" } }, @@ -38484,7 +43100,7 @@ "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=", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", "dev": true }, "undertaker": { @@ -38508,7 +43124,7 @@ "fast-levenshtein": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", "dev": true } } @@ -38516,7 +43132,7 @@ "undertaker-registry": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", "dev": true }, "unicode-canonical-property-names-ecmascript": { @@ -38539,9 +43155,9 @@ "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" }, "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" }, "unified": { "version": "10.1.2", @@ -38570,10 +43186,16 @@ "set-value": "^2.0.1" }, "dependencies": { + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "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=", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true } } @@ -38657,12 +43279,12 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, "requires": { "has-value": "^0.3.1", @@ -38672,7 +43294,7 @@ "has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "dev": true, "requires": { "get-value": "^2.0.3", @@ -38683,7 +43305,7 @@ "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dev": true, "requires": { "isarray": "1.0.0" @@ -38694,13 +43316,13 @@ "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true } } @@ -38720,6 +43342,17 @@ "listenercount": "~1.0.1", "readable-stream": "~2.3.6", "setimmediate": "~1.0.4" + }, + "dependencies": { + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + } } }, "upath": { @@ -38729,9 +43362,9 @@ "dev": true }, "update-browserslist-db": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz", - "integrity": "sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -38749,13 +43382,13 @@ "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", "dev": true }, "url": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", "dev": true, "requires": { "punycode": "1.3.2", @@ -38765,7 +43398,7 @@ "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", "dev": true } } @@ -38793,29 +43426,28 @@ "dev": true }, "util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "dev": true, "requires": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", "which-typed-array": "^1.1.2" } }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "uuid": { "version": "3.4.0", @@ -38863,18 +43495,18 @@ "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=", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", "dev": true }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -38885,15 +43517,15 @@ "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=", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true } } }, "vfile": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.4.tgz", - "integrity": "sha512-KI+7cnst03KbEyN1+JE504zF5bJBZa+J+CrevLeyIMq0aPU681I2rQ5p4PlnQ6exFtWiUrg26QUdFMnAKR6PIw==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", "dev": true, "requires": { "@types/unist": "^2.0.0", @@ -38932,6 +43564,12 @@ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, "string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -38979,13 +43617,13 @@ } }, "video.js": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.20.2.tgz", - "integrity": "sha512-hdvAHKAyaL6bCDkeu0pPtFYKi1EDaOUovm7FN1xqBDolUxgH8FKy1WIgTS+Ouuaw7R54SCTcSeXjZEizhy9ouQ==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.20.3.tgz", + "integrity": "sha512-JMspxaK74LdfWcv69XWhX4rILywz/eInOVPdKefpQiZJSMD5O8xXYueqACP2Q5yqKstycgmmEKlJzZ+kVmDciw==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", - "@videojs/http-streaming": "2.14.2", + "@videojs/http-streaming": "2.14.3", "@videojs/vhs-utils": "^3.0.4", "@videojs/xhr": "2.6.0", "aes-decrypter": "3.1.3", @@ -38996,7 +43634,7 @@ "mux.js": "6.0.1", "safe-json-parse": "4.0.0", "videojs-font": "3.2.0", - "videojs-vtt.js": "^0.15.3" + "videojs-vtt.js": "^0.15.4" }, "dependencies": { "safe-json-parse": { @@ -39121,7 +43759,7 @@ "vinyl-sourcemap": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", "dev": true, "requires": { "append-buffer": "^1.0.2", @@ -39136,7 +43774,7 @@ "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" @@ -39147,7 +43785,7 @@ "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=", + "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==", "dev": true, "requires": { "source-map": "^0.5.1" @@ -39156,13 +43794,13 @@ "void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true }, "vue-template-compiler": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.10.tgz", - "integrity": "sha512-QO+8R9YRq1Gudm8ZMdo/lImZLJVUIAM8c07Vp84ojdDAf8HmPJc7XB556PcXV218k2AkKznsRz6xB5uOjAC4EQ==", + "version": "2.7.13", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.13.tgz", + "integrity": "sha512-jYM6TClwDS9YqP48gYrtAtaOhRKkbYmbzE+Q51gX5YDr777n7tNI/IZk4QV4l/PjQPNh/FVa/E92sh/RqKMrog==", "dev": true, "optional": true, "requires": { @@ -39180,9 +43818,9 @@ } }, "watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -39192,51 +43830,120 @@ "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, "requires": { "defaults": "^1.0.3" } }, "webdriver": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.16.16.tgz", - "integrity": "sha512-x8UoG9k/P8KDrfSh1pOyNevt9tns3zexoMxp9cKnyA/7HYSErhZYTLGlgxscAXLtQG41cMH/Ba/oBmOx7Hgd8w==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.5.3.tgz", + "integrity": "sha512-cDTn/hYj5x8BYwXxVb/WUwqGxrhCMP2rC8ttIWCfzmiVtmOnJGulC7CyxU3+p9Q5R/gIKTzdJOss16dhb+5CoA==", "dev": true, "requires": { - "@types/node": "^17.0.4", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@wdio/config": "7.5.3", + "@wdio/logger": "7.5.3", + "@wdio/protocols": "7.5.3", + "@wdio/types": "7.5.3", + "@wdio/utils": "7.5.3", "got": "^11.0.2", - "ky": "^0.29.0", "lodash.merge": "^4.6.1" + }, + "dependencies": { + "@wdio/logger": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.5.3.tgz", + "integrity": "sha512-r9EADpm0ncS1bDQSWi/nhF9C59/WNLbdAAFlo782E9ItFCpDhNit3aQP9vETv1vFxJRjUIM8Fw/HW8zwPadkbw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/types": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.5.3.tgz", + "integrity": "sha512-jmumhKBhNDABnpmrshYLEcdE9WoP5tmynsDNbDABlb/W8FFiLySQOejukhYIL9CLys4zXerV3/edks0SCzHOiQ==", + "dev": true, + "requires": { + "got": "^11.8.1" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "webdriverio": { - "version": "7.16.16", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.16.16.tgz", - "integrity": "sha512-caPaEWyuD3Qoa7YkW4xCCQA4v9Pa9wmhFGPvNZh3ERtjMCNi8L/XXOdkekWNZmFh3tY0kFguBj7+fAwSY7HAGw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-7.25.4.tgz", + "integrity": "sha512-agkgwn2SIk5cAJ03uue1GnGZcUZUDN3W4fUMY9/VfO8bVJrPEgWg31bPguEWPu+YhEB/aBJD8ECxJ3OEKdy4qQ==", "dev": true, "requires": { "@types/aria-query": "^5.0.0", - "@types/node": "^17.0.4", - "@wdio/config": "7.16.16", - "@wdio/logger": "7.16.0", - "@wdio/protocols": "7.16.7", - "@wdio/repl": "7.16.14", - "@wdio/types": "7.16.14", - "@wdio/utils": "7.16.14", + "@types/node": "^18.0.0", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/repl": "7.25.4", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", "archiver": "^5.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", - "devtools": "7.16.16", - "devtools-protocol": "^0.0.973690", + "devtools": "7.25.4", + "devtools-protocol": "^0.0.1061995", "fs-extra": "^10.0.0", - "get-port": "^5.1.1", "grapheme-splitter": "^1.0.2", "lodash.clonedeep": "^4.5.0", "lodash.isobject": "^3.0.2", @@ -39248,9 +43955,85 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^8.0.0", - "webdriver": "7.16.16" + "webdriver": "7.25.4" }, "dependencies": { + "@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "@wdio/config": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.25.4.tgz", + "integrity": "sha512-vb0emDtD9FbFh/yqW6oNdo2iuhQp8XKj6GX9fyy9v4wZgg3B0HPMVJxhIfcoHz7LMBWlHSo9YdvhFI5EQHRLBA==", + "dev": true, + "requires": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "deepmerge": "^4.0.0", + "glob": "^8.0.3" + } + }, + "@wdio/logger": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.19.0.tgz", + "integrity": "sha512-xR7SN/kGei1QJD1aagzxs3KMuzNxdT/7LYYx+lt6BII49+fqL/SO+5X0FDCZD0Ds93AuQvvz9eGyzrBI2FFXmQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "@wdio/protocols": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.22.0.tgz", + "integrity": "sha512-8EXRR+Ymdwousm/VGtW3H1hwxZ/1g1H99A1lF0U4GuJ5cFWHCd0IVE5H31Z52i8ZruouW8jueMkGZPSo2IIUSQ==", + "dev": true + }, + "@wdio/repl": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.25.4.tgz", + "integrity": "sha512-kYhj9gLsUk4HmlXLqkVre+gwbfvw9CcnrHjqIjrmMS4mR9D8zvBb5CItb3ZExfPf9jpFzIFREbCAYoE9x/kMwg==", + "dev": true, + "requires": { + "@wdio/utils": "7.25.4" + } + }, + "@wdio/types": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.25.4.tgz", + "integrity": "sha512-muvNmq48QZCvocctnbe0URq2FjJjUPIG4iLoeMmyF0AQgdbjaUkMkw3BHYNHVTbSOU9WMsr2z8alhj/I2H6NRQ==", + "dev": true, + "requires": { + "@types/node": "^18.0.0", + "got": "^11.8.1" + } + }, + "@wdio/utils": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-7.25.4.tgz", + "integrity": "sha512-8iwQDk+foUqSzKZKfhLxjlCKOkfRJPNHaezQoevNgnrTq/t0ek+ldZCATezb9B8jprAuP4mgS9xi22akc6RkzA==", + "dev": true, + "requires": { + "@wdio/logger": "7.19.0", + "@wdio/types": "7.25.4", + "p-iteration": "^1.1.8" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -39260,6 +44043,56 @@ "balanced-match": "^1.0.0" } }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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 + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.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 + }, + "ky": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.30.0.tgz", + "integrity": "sha512-X/u76z4JtDVq10u1JA5UQfatPxgPaVDMYTrgHyiTpGN2z4TMEJkIHsoSBBSg9SWZEIXTKsi9kHgiQ9o3Y/4yog==", + "dev": true + }, "minimatch": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", @@ -39268,19 +44101,45 @@ "requires": { "brace-expansion": "^2.0.1" } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "webdriver": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.25.4.tgz", + "integrity": "sha512-6nVDwenh0bxbtUkHASz9B8T9mB531Fn1PcQjUGj2t5dolLPn6zuK1D7XYVX40hpn6r3SlYzcZnEBs4X0az5Txg==", + "dev": true, + "requires": { + "@types/node": "^18.0.0", + "@wdio/config": "7.25.4", + "@wdio/logger": "7.19.0", + "@wdio/protocols": "7.22.0", + "@wdio/types": "7.25.4", + "@wdio/utils": "7.25.4", + "got": "^11.0.2", + "ky": "0.30.0", + "lodash.merge": "^4.6.1" + } } } }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, "webpack": { - "version": "5.70.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", - "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -39288,31 +44147,31 @@ "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.2", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true }, "acorn-import-assertions": { @@ -39334,13 +44193,6 @@ "uri-js": "^4.2.2" } }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, "schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -39355,9 +44207,9 @@ } }, "webpack-bundle-analyzer": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", - "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz", + "integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==", "dev": true, "requires": { "acorn": "^8.0.4", @@ -39372,15 +44224,9 @@ }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true }, "ansi-styles": { @@ -39423,6 +44269,12 @@ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "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.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -39433,9 +44285,9 @@ } }, "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, "requires": {} } @@ -39498,6 +44350,66 @@ "supports-color": "^8.1.1", "through": "^2.3.8", "vinyl": "^2.2.1" + }, + "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" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.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 + }, + "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" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "websocket-driver": { @@ -39520,7 +44432,7 @@ "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "requires": { "tr46": "~0.0.3", @@ -39561,18 +44473,66 @@ "is-weakset": "^2.0.1" } }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, "which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", + "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", "dev": true, "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" + "is-typed-array": "^1.1.9" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "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": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "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": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, "word-wrap": { @@ -39584,13 +44544,13 @@ "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, "workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", "dev": true }, "wrap-ansi": { @@ -39633,7 +44593,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "write": { @@ -39684,13 +44644,13 @@ "yargs": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", - "integrity": "sha1-BU3oth8i7v23IHBZ6u+da4P7kxo=", + "integrity": "sha512-7OGt4xXoWJQh5ulgZ78rKaqY7dNWbjfK+UKxGcIlaM2j7C4fqGchyv8CPvEWdRPrHp6Ula/YU8yGRpYGOHrI+g==", "dev": true }, "yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, "yargs-unparser": { @@ -39711,12 +44671,6 @@ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -39728,7 +44682,7 @@ "yarn-install": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yarn-install/-/yarn-install-1.0.0.tgz", - "integrity": "sha1-V/RQULgu/VcYKzlzxUqgXLXSUjA=", + "integrity": "sha512-VO1u181msinhPcGvQTVMnHVOae8zjX/NSksR17e6eXHRveDvHCF5mGjh9hkN8mzyfnCqcBe42LdTs7bScuTaeg==", "dev": true, "requires": { "cac": "^3.0.3", @@ -39739,19 +44693,19 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -39764,7 +44718,7 @@ "cross-spawn": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", "dev": true, "requires": { "lru-cache": "^4.0.1", @@ -39784,7 +44738,7 @@ "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -39793,7 +44747,7 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true }, "which": { @@ -39808,7 +44762,7 @@ "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", "dev": true } } @@ -39816,7 +44770,7 @@ "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "requires": { "buffer-crc32": "~0.2.3", diff --git a/package.json b/package.json index 60586841a53..21b0f56d38f 100644 --- a/package.json +++ b/package.json @@ -35,13 +35,13 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.16.5", - "@wdio/browserstack-service": "^7.16.0", - "@wdio/cli": "^7.5.2", - "@wdio/concise-reporter": "^7.5.2", - "@wdio/local-runner": "^7.5.2", - "@wdio/mocha-framework": "^7.5.2", - "@wdio/spec-reporter": "^7.19.0", - "@wdio/sync": "^7.5.2", + "@wdio/browserstack-service": "~7.16.0", + "@wdio/cli": "~7.5.2", + "@wdio/concise-reporter": "~7.5.2", + "@wdio/local-runner": "~7.5.2", + "@wdio/mocha-framework": "~7.5.2", + "@wdio/spec-reporter": "~7.19.0", + "@wdio/sync": "~7.5.2", "ajv": "6.12.3", "assert": "^2.0.0", "babel-loader": "^8.0.5", From bf85447707945290055a5734665666e5e5099979 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 3 Nov 2022 12:39:08 -0700 Subject: [PATCH 088/367] Prebid core: fix exception in `requestBids` introduced by #9106 (#9194) * Revert "Prebid core: return a promise from `requestBids` (#9106)" This reverts commit 64aff9b1af9bb1b2761e1012f628299f16c0eb46. * Revert "Revert "Prebid core: return a promise from `requestBids` (#9106)"" This reverts commit bf5ee3015059fd80a415ec67e7c5f690076a2ae1. * Prebid core: fix exception in `requestBids` introduced by #9106 * Add comments --- src/prebid.js | 162 ++++++++++++++++---------------- test/spec/unit/pbjs_api_spec.js | 18 +++- 2 files changed, 100 insertions(+), 80 deletions(-) diff --git a/src/prebid.js b/src/prebid.js index 94391343cd3..06429b13a72 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -49,6 +49,7 @@ import {default as adapterManager, gdprDataHandler, getS2SBidderSet, uspDataHand import CONSTANTS from './constants.json'; import * as events from './events.js'; import {newMetrics, useMetrics} from './utils/perfMetrics.js'; +import {defer} from './utils/promise.js'; const $$PREBID_GLOBAL$$ = getGlobal(); const { triggerUserSyncs } = userSync; @@ -622,7 +623,7 @@ $$PREBID_GLOBAL$$.removeAdUnit = function (adUnitCode) { * @alias module:pbjs.requestBids */ $$PREBID_GLOBAL$$.requestBids = (function() { - const delegate = hook('sync', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2, metrics } = {}) { + const delegate = hook('async', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2, metrics, defer } = {}) { events.emit(REQUEST_BIDS); const cbTimeout = timeout || config.getConfig('bidderTimeout'); logInfo('Invoking $$PREBID_GLOBAL$$.requestBids', arguments); @@ -630,23 +631,28 @@ $$PREBID_GLOBAL$$.requestBids = (function() { global: mergeDeep({}, config.getAnyConfig('ortb2') || {}, ortb2 || {}), bidder: Object.fromEntries(Object.entries(config.getBidderConfig()).map(([bidder, cfg]) => [bidder, cfg.ortb2]).filter(([_, ortb2]) => ortb2 != null)) } - return startAuction({bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2Fragments, metrics}); + return startAuction({bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2Fragments, metrics, defer}); }, 'requestBids'); return wrapHook(delegate, function requestBids(req = {}) { - // if the request does not specify adUnits, clone the global adUnit array - before - // any hook has a chance to run. + // unlike the main body of `delegate`, this runs before any other hook has a chance to; + // it's also not restricted in its return value in the way `async` hooks are. + + // if the request does not specify adUnits, clone the global adUnit array; // otherwise, if the caller goes on to use addAdUnits/removeAdUnits, any asynchronous logic // in any hook might see their effects. - req.metrics = newMetrics(); - req.metrics.checkpoint('requestBids'); let adUnits = req.adUnits || $$PREBID_GLOBAL$$.adUnits; req.adUnits = (isArray(adUnits) ? adUnits.slice() : [adUnits]); - return delegate.call(this, req); + + req.metrics = newMetrics(); + req.metrics.checkpoint('requestBids'); + req.defer = defer({promiseFactory: (r) => new Promise(r)}) + delegate.call(this, req); + return req.defer.promise; }); })(); -export const startAuction = hook('sync', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, ttlBuffer, adUnitCodes, labels, auctionId, ortb2Fragments, metrics } = {}) { +export const startAuction = hook('async', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, ttlBuffer, adUnitCodes, labels, auctionId, ortb2Fragments, metrics, defer } = {}) { const s2sBidders = getS2SBidderSet(config.getConfig('s2sConfig') || []); adUnits = useMetrics(metrics).measureTime('requestBids.validate', () => checkAdUnitSetup(adUnits)); @@ -658,85 +664,83 @@ export const startAuction = hook('sync', function ({ bidsBackHandler, timeout: c adUnitCodes = adUnits && adUnits.map(unit => unit.code); } - return new Promise((resolve) => { - function auctionDone(bids, timedOut, auctionId) { - if (typeof bidsBackHandler === 'function') { - try { - bidsBackHandler(bids, timedOut, auctionId); - } catch (e) { - logError('Error executing bidsBackHandler', null, e); - } + function auctionDone(bids, timedOut, auctionId) { + if (typeof bidsBackHandler === 'function') { + try { + bidsBackHandler(bids, timedOut, auctionId); + } catch (e) { + logError('Error executing bidsBackHandler', null, e); } - resolve({bids, timedOut, auctionId}); } + defer.resolve({bids, timedOut, auctionId}) + } + + /* + * for a given adunit which supports a set of mediaTypes + * and a given bidder which supports a set of mediaTypes + * a bidder is eligible to participate on the adunit + * if it supports at least one of the mediaTypes on the adunit + */ + adUnits.forEach(adUnit => { + // get the adunit's mediaTypes, defaulting to banner if mediaTypes isn't present + const adUnitMediaTypes = Object.keys(adUnit.mediaTypes || { 'banner': 'banner' }); - /* - * for a given adunit which supports a set of mediaTypes - * and a given bidder which supports a set of mediaTypes - * a bidder is eligible to participate on the adunit - * if it supports at least one of the mediaTypes on the adunit - */ - adUnits.forEach(adUnit => { - // get the adunit's mediaTypes, defaulting to banner if mediaTypes isn't present - const adUnitMediaTypes = Object.keys(adUnit.mediaTypes || { 'banner': 'banner' }); - - // get the bidder's mediaTypes - const allBidders = adUnit.bids.map(bid => bid.bidder); - const bidderRegistry = adapterManager.bidderRegistry; - - const bidders = allBidders.filter(bidder => !s2sBidders.has(bidder)); - - const tid = adUnit.ortb2Imp?.ext?.tid || generateUUID(); - adUnit.transactionId = tid; - if (ttlBuffer != null && !adUnit.hasOwnProperty('ttlBuffer')) { - adUnit.ttlBuffer = ttlBuffer; + // get the bidder's mediaTypes + const allBidders = adUnit.bids.map(bid => bid.bidder); + const bidderRegistry = adapterManager.bidderRegistry; + + const bidders = allBidders.filter(bidder => !s2sBidders.has(bidder)); + + const tid = adUnit.ortb2Imp?.ext?.tid || generateUUID(); + adUnit.transactionId = tid; + if (ttlBuffer != null && !adUnit.hasOwnProperty('ttlBuffer')) { + adUnit.ttlBuffer = ttlBuffer; + } + // Populate ortb2Imp.ext.tid with transactionId. Specifying a transaction ID per item in the ortb impression array, lets multiple transaction IDs be transmitted in a single bid request. + deepSetValue(adUnit, 'ortb2Imp.ext.tid', tid); + + bidders.forEach(bidder => { + const adapter = bidderRegistry[bidder]; + const spec = adapter && adapter.getSpec && adapter.getSpec(); + // banner is default if not specified in spec + const bidderMediaTypes = (spec && spec.supportedMediaTypes) || ['banner']; + + // check if the bidder's mediaTypes are not in the adUnit's mediaTypes + const bidderEligible = adUnitMediaTypes.some(type => includes(bidderMediaTypes, type)); + if (!bidderEligible) { + // drop the bidder from the ad unit if it's not compatible + logWarn(unsupportedBidderMessage(adUnit, bidder)); + adUnit.bids = adUnit.bids.filter(bid => bid.bidder !== bidder); + } else { + adunitCounter.incrementBidderRequestsCounter(adUnit.code, bidder); } - // Populate ortb2Imp.ext.tid with transactionId. Specifying a transaction ID per item in the ortb impression array, lets multiple transaction IDs be transmitted in a single bid request. - deepSetValue(adUnit, 'ortb2Imp.ext.tid', tid); - - bidders.forEach(bidder => { - const adapter = bidderRegistry[bidder]; - const spec = adapter && adapter.getSpec && adapter.getSpec(); - // banner is default if not specified in spec - const bidderMediaTypes = (spec && spec.supportedMediaTypes) || ['banner']; - - // check if the bidder's mediaTypes are not in the adUnit's mediaTypes - const bidderEligible = adUnitMediaTypes.some(type => includes(bidderMediaTypes, type)); - if (!bidderEligible) { - // drop the bidder from the ad unit if it's not compatible - logWarn(unsupportedBidderMessage(adUnit, bidder)); - adUnit.bids = adUnit.bids.filter(bid => bid.bidder !== bidder); - } else { - adunitCounter.incrementBidderRequestsCounter(adUnit.code, bidder); - } - }); - adunitCounter.incrementRequestsCounter(adUnit.code); }); + adunitCounter.incrementRequestsCounter(adUnit.code); + }); - if (!adUnits || adUnits.length === 0) { - logMessage('No adUnits configured. No bids requested.'); - auctionDone(); - } else { - const auction = auctionManager.createAuction({ - adUnits, - adUnitCodes, - callback: auctionDone, - cbTimeout, - labels, - auctionId, - ortb2Fragments, - metrics, - }); - - let adUnitsLen = adUnits.length; - if (adUnitsLen > 15) { - logInfo(`Current auction ${auction.getAuctionId()} contains ${adUnitsLen} adUnits.`, adUnits); - } + if (!adUnits || adUnits.length === 0) { + logMessage('No adUnits configured. No bids requested.'); + auctionDone(); + } else { + const auction = auctionManager.createAuction({ + adUnits, + adUnitCodes, + callback: auctionDone, + cbTimeout, + labels, + auctionId, + ortb2Fragments, + metrics, + }); - adUnitCodes.forEach(code => targeting.setLatestAuctionForAdUnit(code, auction.getAuctionId())); - auction.callBids(); + let adUnitsLen = adUnits.length; + if (adUnitsLen > 15) { + logInfo(`Current auction ${auction.getAuctionId()} contains ${adUnitsLen} adUnits.`, adUnits); } - }); + + adUnitCodes.forEach(code => targeting.setLatestAuctionForAdUnit(code, auction.getAuctionId())); + auction.callBids(); + } }, 'startAuction'); export function executeCallbacks(fn, reqBidsConfigObj) { diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index b8b82f7ca96..8e3314bd954 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -1615,6 +1615,19 @@ describe('Unit: Prebid Module', function () { }); describe('returns a promise that resolves', () => { + function delayHook(next, ...args) { + setTimeout(() => next(...args)) + } + + beforeEach(() => { + // make sure the return value works correctly when hooks give up priority + $$PREBID_GLOBAL$$.requestBids.before(delayHook) + }); + + afterEach(() => { + $$PREBID_GLOBAL$$.requestBids.getHooks({hook: delayHook}).remove(); + }); + Object.entries({ 'immediately, without bidsBackHandler': (req) => $$PREBID_GLOBAL$$.requestBids(req), 'after bidsBackHandler': (() => { @@ -1665,7 +1678,10 @@ describe('Unit: Prebid Module', function () { sinon.assert.match(bids[bid.adUnitCode].bids[0], bid) done(); }); - completeAuction([bid]); + // `completeAuction` won't work until we're out of `delayHook` + // and the mocked auction has been set up; + // setTimeout here takes us after the setTimeout in `delayHook` + setTimeout(() => completeAuction([bid])); }) }) }) From 0c5450b745454d04de96881f48fb0150a9cedc63 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 3 Nov 2022 19:55:36 +0000 Subject: [PATCH 089/367] Prebid 7.24.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7567271b07f..89f17ef1a63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.24.0-pre", + "version": "7.24.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 21b0f56d38f..75fffaa4cf1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.24.0-pre", + "version": "7.24.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From abf4688ce2005f342db86d7fe8e89c2fff05b518 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 3 Nov 2022 19:55:36 +0000 Subject: [PATCH 090/367] Increment version to 7.25.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 89f17ef1a63..48ef496ee8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.24.0", + "version": "7.25.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 75fffaa4cf1..d98f313f4dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.24.0", + "version": "7.25.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 7487bfd79979b0fc10e5b39fe18f1b3fb9bd6861 Mon Sep 17 00:00:00 2001 From: Jeremy Sadwith Date: Fri, 4 Nov 2022 11:09:47 -0400 Subject: [PATCH 091/367] Kargo Bid Adapter : add support for client hints (#9184) * pageURL pull from topmostLocation * Kargo: Support for client hints (#9) * Starting SUA support * Kargo: Adding support for client hints * Adding tests for sua --- modules/kargoBidAdapter.js | 22 ++++--- test/spec/modules/kargoBidAdapter_spec.js | 80 +++++++++++++++++++++-- 2 files changed, 90 insertions(+), 12 deletions(-) diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index c0faf2490cb..15d706c0410 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -1,4 +1,4 @@ -import { _each, buildUrl, triggerPixel } from '../src/utils.js'; +import { _each, buildUrl, deepAccess, pick, triggerPixel } from '../src/utils.js'; import { config } from '../src/config.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { getStorageManager } from '../src/storageManager.js'; @@ -37,10 +37,9 @@ export const spec = { bidSizes[bid.bidId] = bid.sizes; }); - let tdid; - if (validBidRequests.length > 0 && validBidRequests[0].userId && validBidRequests[0].userId.tdid) { - tdid = validBidRequests[0].userId.tdid; - } + const firstBidRequest = validBidRequests[0]; + + const tdid = deepAccess(firstBidRequest, 'userId.tdid') const transformedParams = Object.assign({}, { sessionId: spec._getSessionId(), @@ -62,10 +61,17 @@ export const spec = { prebidRawBidRequests: validBidRequests }, spec._getAllMetadata(bidderRequest, tdid)); + // User Agent Client Hints / SUA + const uaClientHints = deepAccess(firstBidRequest, 'ortb2.device.sua'); + if (uaClientHints) { + transformedParams.device.sua = pick(uaClientHints, ['browsers', 'platform', 'mobile', 'model']); + } + // Pull Social Canvas segments and embed URL - if (validBidRequests.length > 0 && validBidRequests[0].params.socialCanvas) { - transformedParams.socialCanvasSegments = validBidRequests[0].params.socialCanvas.segments; - transformedParams.socialEmbedURL = validBidRequests[0].params.socialCanvas.embedURL; + const socialCanvas = deepAccess(firstBidRequest, 'params.socialCanvas'); + if (socialCanvas) { + transformedParams.socialCanvasSegments = socialCanvas.segments; + transformedParams.socialEmbedURL = socialCanvas.embedURL; } const encodedParams = encodeURIComponent(JSON.stringify(transformedParams)); diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index 169ee520f33..565b83704fa 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -69,7 +69,33 @@ describe('kargo adapter tests', function () { userId: { tdid: 'fake-tdid' }, - sizes: [[320, 50], [300, 250], [300, 600]] + sizes: [[320, 50], [300, 250], [300, 600]], + ortb2: { + device: { + sua: { + platform: { + brand: 'macOS', + version: [ '12', '6', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + } + ], + mobile: 0, + model: '' + } + } + } }, { params: { @@ -259,6 +285,28 @@ describe('kargo adapter tests', function () { device: { width: screen.width, height: screen.height, + sua: { + platform: { + brand: 'macOS', + version: [ '12', '6', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + } + ], + mobile: 0, + model: '', + }, }, userIDs: { kargoID: '5f108831-302d-11e7-bf6b-4595acd3bf6c', @@ -280,13 +328,39 @@ describe('kargo adapter tests', function () { prebidRawBidRequests: [ { bidId: 1, + ortb2: { + device: { + sua: { + platform: { + brand: 'macOS', + version: [ '12', '6', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + } + ], + mobile: 0, + model: '' + } + } + }, params: { placementId: 'foo' }, userId: { tdid: 'fake-tdid' }, - sizes: [[320, 50], [300, 250], [300, 600]] + sizes: [[320, 50], [300, 250], [300, 600]], }, { bidId: 2, @@ -330,7 +404,6 @@ describe('kargo adapter tests', function () { var payload = { timeout: 200, uspConsent: '1---', - foo: 'bar', refererInfo: { page: 'https://www.prebid.org', }, @@ -349,7 +422,6 @@ describe('kargo adapter tests', function () { expect(request.method).to.equal('GET'); expect(request.currency).to.equal('USD'); expect(request.timeout).to.equal(200); - expect(request.foo).to.equal('bar'); expect(krakenParams).to.deep.equal(expected); // Make sure session ID stays the same across requests simulating multiple auctions on one page load for (let i in sessionIds) { From 475dcd2487f8d87942a0dcfbda408a5e2b1a37d5 Mon Sep 17 00:00:00 2001 From: vfourny <109095331+vfourny-ogury@users.noreply.github.com> Date: Mon, 7 Nov 2022 14:51:17 +0100 Subject: [PATCH 092/367] adding timeline data to logging events (#9208) --- modules/oguryBidAdapter.js | 7 +++-- test/spec/modules/oguryBidAdapter_spec.js | 32 +++++++++++++++++++---- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/modules/oguryBidAdapter.js b/modules/oguryBidAdapter.js index cb082f2d9a9..da62ce5c0a1 100644 --- a/modules/oguryBidAdapter.js +++ b/modules/oguryBidAdapter.js @@ -11,7 +11,7 @@ const DEFAULT_TIMEOUT = 1000; const BID_HOST = 'https://mweb-hb.presage.io/api/header-bidding-request'; const TIMEOUT_MONITORING_HOST = 'https://ms-ads-monitoring-events.presage.io'; const MS_COOKIE_SYNC_DOMAIN = 'https://ms-cookie-sync.presage.io'; -const ADAPTER_VERSION = '1.3.0'; +const ADAPTER_VERSION = '1.4.0'; function getClientWidth() { const documentElementClientWidth = window.top.document.documentElement.clientWidth @@ -114,7 +114,10 @@ function buildRequests(validBidRequests, bidderRequest) { banner: { format: sizes }, - ext: bidRequest.params + ext: { + ...bidRequest.params, + timeSpentOnPage: document.timeline && document.timeline.currentTime ? document.timeline.currentTime : 0 + } }); } }); diff --git a/test/spec/modules/oguryBidAdapter_spec.js b/test/spec/modules/oguryBidAdapter_spec.js index b9e4b44b571..f7cdcc0d11a 100644 --- a/test/spec/modules/oguryBidAdapter_spec.js +++ b/test/spec/modules/oguryBidAdapter_spec.js @@ -244,12 +244,16 @@ describe('OguryBidAdapter', function () { describe('buildRequests', function () { const stubbedWidth = 200 const stubbedHeight = 600 + const stubbedCurrentTime = 1234567890 const stubbedWidthMethod = sinon.stub(window.top.document.documentElement, 'clientWidth').get(function() { return stubbedWidth; }); const stubbedHeightMethod = sinon.stub(window.top.document.documentElement, 'clientHeight').get(function() { return stubbedHeight; }); + const stubbedCurrentTimeMethod = sinon.stub(document.timeline, 'currentTime').get(function() { + return stubbedCurrentTime; + }); const defaultTimeout = 1000; const expectedRequestObject = { @@ -266,7 +270,10 @@ describe('OguryBidAdapter', function () { h: 250 }] }, - ext: bidRequests[0].params + ext: { + ...bidRequests[0].params, + timeSpentOnPage: stubbedCurrentTime + } }, { id: bidRequests[1].bidId, tagid: bidRequests[1].params.adUnitId, @@ -276,7 +283,10 @@ describe('OguryBidAdapter', function () { h: 500 }] }, - ext: bidRequests[1].params + ext: { + ...bidRequests[1].params, + timeSpentOnPage: stubbedCurrentTime + } }], regs: { ext: { @@ -295,7 +305,7 @@ describe('OguryBidAdapter', function () { }, ext: { prebidversion: '$prebid.version$', - adapterversion: '1.3.0' + adapterversion: '1.4.0' }, device: { w: stubbedWidth, @@ -306,6 +316,7 @@ describe('OguryBidAdapter', function () { after(function() { stubbedWidthMethod.restore(); stubbedHeightMethod.restore(); + stubbedCurrentTimeMethod.restore(); }); it('sends bid request to ENDPOINT via POST', function () { @@ -316,6 +327,17 @@ describe('OguryBidAdapter', function () { expect(request.method).to.equal('POST'); }); + it('timeSpentOnpage should be 0 if timeline is undefined', function () { + const stubbedTimelineMethod = sinon.stub(document, 'timeline').get(function() { + return undefined; + }); + const validBidRequests = utils.deepClone(bidRequests) + + const request = spec.buildRequests(validBidRequests, bidderRequest); + expect(request.data.imp[0].ext.timeSpentOnPage).to.equal(0); + stubbedTimelineMethod.restore(); + }); + it('bid request object should be conform', function () { const validBidRequests = utils.deepClone(bidRequests) @@ -675,7 +697,7 @@ describe('OguryBidAdapter', function () { advertiserDomains: openRtbBidResponse.body.seatbid[0].bid[0].adomain }, nurl: openRtbBidResponse.body.seatbid[0].bid[0].nurl, - adapterVersion: '1.3.0', + adapterVersion: '1.4.0', prebidVersion: '$prebid.version$' }, { requestId: openRtbBidResponse.body.seatbid[0].bid[1].impid, @@ -692,7 +714,7 @@ describe('OguryBidAdapter', function () { advertiserDomains: openRtbBidResponse.body.seatbid[0].bid[1].adomain }, nurl: openRtbBidResponse.body.seatbid[0].bid[1].nurl, - adapterVersion: '1.3.0', + adapterVersion: '1.4.0', prebidVersion: '$prebid.version$' }] From 2ec27435d338bd4d4ac41d39d250ad5325137f85 Mon Sep 17 00:00:00 2001 From: Aaron Price <67345931+AaronColbyPrice@users.noreply.github.com> Date: Mon, 7 Nov 2022 06:36:21 -0800 Subject: [PATCH 093/367] eps_update_branding - Update Conversant branding to Epsilon (#9206) --- modules/conversantAnalyticsAdapter.md | 25 ++++++++++++------------- modules/conversantBidAdapter.md | 6 +++--- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/modules/conversantAnalyticsAdapter.md b/modules/conversantAnalyticsAdapter.md index 51db983a8bd..2f026cbcbb9 100644 --- a/modules/conversantAnalyticsAdapter.md +++ b/modules/conversantAnalyticsAdapter.md @@ -1,37 +1,36 @@ # Overview -- Module Name: Conversant Bidder Adapter +- Module Name: Epsilon Analytics Adapter - Module Type: Analytics Adapter -- Maintainer: mediapsr@conversantmedia.com +- Maintainer: mediapsr@epsilon.com ## Description -Analytics adapter for Conversant is used to track performance of Prebid auctions. See the usage below for how to +Analytics adapter for Epsilon (formerly Conversant) is used to track performance of Prebid auctions. See the usage below for how to configure the adapter for your webpage. To enable analytics and gain access to the data publishers will need - to contact their Conversant representative. + to contact their Epsilon representative (publishersupport@epsilon.com). ## Setup -Before any analytics are recorded for your website you will need to have a Conversant representative turn +Before any analytics are recorded for your website you will need to have an Epsilon representative turn on Prebid analytics for your website. -The simplest configuration to add Conversant Prebid analytics to your page is as follows: +The simplest configuration to add Epsilon Prebid analytics to your page is as follows: ``` pbjs.que.push(function() { pbjs.enableAnalytics({ provider: 'conversant', options: { - site_id: '' + site_id: } }) }); ``` -Additionally the following options are supported: +Additionally, the following options are supported: -- **sampleRate**: Expects an integer from 0 to 100. By default only 50% (corresponds to a value of 50) of instances are enabled -for Conversant Prebid Analytics. This field allows the publisher to override that percentage to sample -at a higher or lower rate. '0' would completely disable sampling and '100' would capture every instance. +- **cnvr_sampling**: Sample rate for analytics data. Value should be between 0 and 1 (inclusive), 0 == never sample, +1 == always sample, 0.5 == send analytics 50% of the time. ### Complete Example ``` @@ -39,8 +38,8 @@ at a higher or lower rate. '0' would completely disable sampling and '100' would pbjs.enableAnalytics({ provider: 'conversant', options: { - site_id: '1234', - sampleRate: 90 + site_id: 1234, + cnvr_sampling: 0.9 } }) }); diff --git a/modules/conversantBidAdapter.md b/modules/conversantBidAdapter.md index 07d9abf918b..baf8b756aca 100644 --- a/modules/conversantBidAdapter.md +++ b/modules/conversantBidAdapter.md @@ -1,12 +1,12 @@ # Overview -- Module Name: Conversant Bidder Adapter +- Module Name: Epsilon Bidder Adapter - Module Type: Bidder Adapter -- Maintainer: mediapsr@conversantmedia.com +- Maintainer: mediapsr@epsilon.com # Description -Module that connects to Conversant's demand sources. Supports banners and videos. +Module that connects to Epsilon's (formerly Conversant) demand sources. Supports banners and videos. # Test Parameters ``` From 40d3ae10fac6e71bf5811a1f9d657eb3184098a1 Mon Sep 17 00:00:00 2001 From: Mikhail Ivanchenko Date: Mon, 7 Nov 2022 23:54:10 +0300 Subject: [PATCH 094/367] NextMillennium Bid Adapter: set content-type to text/plain (#9210) * add video support * Changed content-type to text/plain --- modules/nextMillenniumBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nextMillenniumBidAdapter.js b/modules/nextMillenniumBidAdapter.js index 25ad1f43e82..762c571f1e6 100644 --- a/modules/nextMillenniumBidAdapter.js +++ b/modules/nextMillenniumBidAdapter.js @@ -141,7 +141,7 @@ export const spec = { url: isTest ? TEST_ENDPOINT : ENDPOINT, data: JSON.stringify(postBody), options: { - contentType: 'application/json', + contentType: 'text/plain', withCredentials: true }, From e28494b80caddfc348ae91fa53c3e8406cc425da Mon Sep 17 00:00:00 2001 From: Robert Ray Martinez III Date: Tue, 8 Nov 2022 06:21:26 -0800 Subject: [PATCH 095/367] default 1x1 size if no sizes on adUnit (#9211) --- modules/magniteAnalyticsAdapter.js | 2 +- .../modules/magniteAnalyticsAdapter_spec.js | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/modules/magniteAnalyticsAdapter.js b/modules/magniteAnalyticsAdapter.js index 44666178e46..99f384e9eff 100644 --- a/modules/magniteAnalyticsAdapter.js +++ b/modules/magniteAnalyticsAdapter.js @@ -706,7 +706,7 @@ magniteAdapter.track = ({ eventType, args }) => { 'code as adUnitCode', 'transactionId', 'mediaTypes', mediaTypes => Object.keys(mediaTypes), - 'sizes as dimensions', sizes => sizes.map(sizeToDimensions), + 'sizes as dimensions', sizes => (sizes || [[1, 1]]).map(sizeToDimensions), ]); ad.pbAdSlot = deepAccess(adUnit, 'ortb2Imp.ext.data.pbadslot'); ad.pattern = deepAccess(adUnit, 'ortb2Imp.ext.data.aupname'); diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js index 240a5aa51a2..69fd7794ced 100644 --- a/test/spec/modules/magniteAnalyticsAdapter_spec.js +++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js @@ -548,6 +548,26 @@ describe('magnite analytics adapter', function () { ]); }); + it('should pass along 1x1 size if no sizes in adUnit', function () { + const auctionInit = utils.deepClone(MOCK.AUCTION_INIT); + + delete auctionInit.adUnits[0].sizes; + + events.emit(AUCTION_INIT, auctionInit); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + clock.tick(rubiConf.analyticsBatchTimeout + 1000); + + let message = JSON.parse(server.requests[0].requestBody); + expect(message.auctions[0].adUnits[0].dimensions).to.deep.equal([ + { + width: 1, + height: 1 + } + ]); + }); + it('should pass along user ids', function () { let auctionInit = utils.deepClone(MOCK.AUCTION_INIT); auctionInit.bidderRequests[0].bids[0].userId = { From e19b7f146162da624caebd03704237281235d702 Mon Sep 17 00:00:00 2001 From: Nayan Savla Date: Tue, 8 Nov 2022 06:49:58 -0800 Subject: [PATCH 096/367] Yieldmo Bid Adapteer : add iab gvlid and update path (#9189) * Add stage bidder service * add stage url * fix url * fix string method * clean up rebase * Adding transaction id and auction id. * Adding gvlid to Yieldmo Adapter * Resolving linting errors * Update yieldmoBidAdapter_spec.js Co-authored-by: elber@yieldmo.com Co-authored-by: Elber Carneiro <81249884+ym-elber@users.noreply.github.com> --- modules/yieldmoBidAdapter.js | 30 +++++++++++++++------ test/spec/modules/yieldmoBidAdapter_spec.js | 7 +++-- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js index 892936ceea5..64ab8a87eea 100644 --- a/modules/yieldmoBidAdapter.js +++ b/modules/yieldmoBidAdapter.js @@ -20,12 +20,15 @@ import {find, includes} from '../src/polyfill.js'; import {createEidsArray} from './userId/eids.js'; const BIDDER_CODE = 'yieldmo'; +const GVLID = 173; const CURRENCY = 'USD'; const TIME_TO_LIVE = 300; const NET_REVENUE = true; -const BANNER_SERVER_ENDPOINT = 'https://ads.yieldmo.com/exchange/prebid'; -const VIDEO_SERVER_ENDPOINT = 'https://ads.yieldmo.com/exchange/prebidvideo'; const PB_COOKIE_ASSIST_SYNC_ENDPOINT = `https://ads.yieldmo.com/pbcas`; +const BANNER_PATH = '/exchange/prebid'; +const VIDEO_PATH = '/exchange/prebidvideo'; +const STAGE_DOMAIN = 'https://ads-stg.yieldmo.com'; +const PROD_DOMAIN = 'https://ads.yieldmo.com'; const OUTSTREAM_VIDEO_PLAYER_URL = 'https://prebid-outstream.yieldmo.com/bundle.js'; const OPENRTB_VIDEO_BIDPARAMS = ['mimes', 'startdelay', 'placement', 'startdelay', 'skipafter', 'protocols', 'api', 'playbackmethod', 'maxduration', 'minduration', 'pos', 'skip', 'skippable']; @@ -40,7 +43,7 @@ const BANNER_REQUEST_PROPERTIES_TO_REDUCE = ['description', 'title', 'pr', 'page export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO], - + gvlid: GVLID, /** * Determines whether or not the given bid request is valid. * @param {object} bid, bid to validate @@ -59,6 +62,9 @@ export const spec = { * @return ServerRequest Info describing the request to the server. */ buildRequests: function (bidRequests, bidderRequest) { + const stage = isStage(bidderRequest); + const bannerUrl = getAdserverUrl(BANNER_PATH, stage); + const videoUrl = getAdserverUrl(VIDEO_PATH, stage); const bannerBidRequests = bidRequests.filter(request => hasBannerMediaType(request)); const videoBidRequests = bidRequests.filter(request => hasVideoMediaType(request)); let serverRequests = []; @@ -122,8 +128,8 @@ export const spec = { serverRequest.eids = JSON.stringify(eids); }; // check if url exceeded max length - const url = `${BANNER_SERVER_ENDPOINT}?${parseQueryStringParameters(serverRequest)}`; - let extraCharacters = url.length - MAX_BANNER_REQUEST_URL_LENGTH; + const fullUrl = `${bannerUrl}?${parseQueryStringParameters(serverRequest)}`; + let extraCharacters = fullUrl.length - MAX_BANNER_REQUEST_URL_LENGTH; if (extraCharacters > 0) { for (let i = 0; i < BANNER_REQUEST_PROPERTIES_TO_REDUCE.length; i++) { extraCharacters = shortcutProperty(extraCharacters, serverRequest, BANNER_REQUEST_PROPERTIES_TO_REDUCE[i]); @@ -136,7 +142,7 @@ export const spec = { serverRequests.push({ method: 'GET', - url: BANNER_SERVER_ENDPOINT, + url: bannerUrl, data: serverRequest }); } @@ -148,7 +154,7 @@ export const spec = { }; serverRequests.push({ method: 'POST', - url: VIDEO_SERVER_ENDPOINT, + url: videoUrl, data: serverRequest }); } @@ -249,7 +255,6 @@ function addPlacement(request) { if (transactionId) { placementInfo.tid = transactionId; } - if (request.auctionId) { placementInfo.auctionId = request.auctionId; } @@ -676,3 +681,12 @@ function canAccessTopWindow() { return false; } } + +function isStage(bidderRequest) { + return !!bidderRequest.refererInfo?.referer?.includes('pb_force_a'); +} + +function getAdserverUrl(path, stage) { + const domain = stage ? STAGE_DOMAIN : PROD_DOMAIN; + return `${domain}${path}`; +} diff --git a/test/spec/modules/yieldmoBidAdapter_spec.js b/test/spec/modules/yieldmoBidAdapter_spec.js index 32f0ead11f1..8a0ebf863dd 100644 --- a/test/spec/modules/yieldmoBidAdapter_spec.js +++ b/test/spec/modules/yieldmoBidAdapter_spec.js @@ -34,6 +34,7 @@ describe('YieldmoAdapter', function () { userId: { tdid: '8d146286-91d4-4958-aff4-7e489dd1abd6' }, + transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c', ...rootParams }); @@ -63,6 +64,7 @@ describe('YieldmoAdapter', function () { ...videoParams } }, + transactionId: '54a58774-7a41-494e-8cbc-fa7b79164f0c', ...rootParams }); @@ -178,10 +180,9 @@ describe('YieldmoAdapter', function () { expect(buildAndGetPlacementInfo(bidArray)).to.equal( '[{"placement_id":"adunit-code","callback_id":"30b31c1838de1e","sizes":[[300,250],[300,600]],"bidFloor":0.1,"auctionId":"1d1a030790a475"}]' ); - // multiple placements bidArray.push(mockBannerBid( - {adUnitCode: 'adunit-2', bidId: '123a', bidderRequestId: '321', auctionId: '222'}, {bidFloor: 0.2})); + {adUnitCode: 'adunit-2', bidId: '123a', bidderRequestId: '321', auctionId: '222', transactionId: '444'}, {bidFloor: 0.2})); expect(buildAndGetPlacementInfo(bidArray)).to.equal( '[{"placement_id":"adunit-code","callback_id":"30b31c1838de1e","sizes":[[300,250],[300,600]],"bidFloor":0.1,"auctionId":"1d1a030790a475"},' + '{"placement_id":"adunit-2","callback_id":"123a","sizes":[[300,250],[300,600]],"bidFloor":0.2,"auctionId":"222"}]' @@ -193,7 +194,6 @@ describe('YieldmoAdapter', function () { let placementInfo = buildAndGetPlacementInfo(bidArray); expect(placementInfo).to.include('"ym_placement_id":"ym_1293871298"'); expect(placementInfo).not.to.include('"ym_placement_id":"ym_0987654321"'); - bidArray.push(mockBannerBid({}, {placementId: 'ym_0987654321'})); placementInfo = buildAndGetPlacementInfo(bidArray); expect(placementInfo).to.include('"ym_placement_id":"ym_1293871298"'); @@ -507,7 +507,6 @@ describe('YieldmoAdapter', function () { it('should add auction id to video bid request', function() { const auctionId = '1d1a03073455'; - expect(buildAndGetData([mockVideoBid({})]).auctionId).to.deep.equal(auctionId); }); From 8e023b161a54726db4001b7fdd98fd71808952b1 Mon Sep 17 00:00:00 2001 From: dalmenarDevST <116064809+dalmenarDevST@users.noreply.github.com> Date: Tue, 8 Nov 2022 16:08:04 +0100 Subject: [PATCH 097/367] add coppa param to payload (#9202) --- modules/seedtagBidAdapter.js | 13 ++++-- test/spec/modules/seedtagBidAdapter_spec.js | 44 ++++++++++++++++----- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/modules/seedtagBidAdapter.js b/modules/seedtagBidAdapter.js index 5c4a3af866c..850ac5610f5 100644 --- a/modules/seedtagBidAdapter.js +++ b/modules/seedtagBidAdapter.js @@ -1,6 +1,7 @@ import { isArray, _map, triggerPixel } 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 = 'seedtag'; const SEEDTAG_ALIAS = 'st'; @@ -177,7 +178,7 @@ function ttfb() { return ttfb >= 0 && ttfb <= performance.now() ? ttfb : 0; } -export function getTimeoutUrl (data) { +export function getTimeoutUrl(data) { let queryParams = ''; if ( isArray(data) && data[0] && @@ -235,7 +236,6 @@ export const spec = { if (gdprApplies !== undefined) payload['ga'] = gdprApplies; payload['cd'] = bidderRequest.gdprConsent.consentString; } - if (bidderRequest.uspConsent) { payload['uspConsent'] = bidderRequest.uspConsent } @@ -244,6 +244,11 @@ export const spec = { payload.schain = validBidRequests[0].schain; } + let coppa = config.getConfig('coppa') + if (coppa) { + payload.coppa = coppa + } + const payloadString = JSON.stringify(payload) return { method: 'POST', @@ -258,10 +263,10 @@ export const spec = { * @param {ServerResponse} serverResponse A successful response from the server. * @return {Bid[]} An array of bids which were nested inside the server. */ - interpretResponse: function(serverResponse) { + interpretResponse: function (serverResponse) { const serverBody = serverResponse.body; if (serverBody && serverBody.bids && isArray(serverBody.bids)) { - return _map(serverBody.bids, function(bid) { + return _map(serverBody.bids, function (bid) { return buildBidResponse(bid); }); } else { diff --git a/test/spec/modules/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js index 05d609e8003..bd726bfe971 100644 --- a/test/spec/modules/seedtagBidAdapter_spec.js +++ b/test/spec/modules/seedtagBidAdapter_spec.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { spec, getTimeoutUrl } from 'modules/seedtagBidAdapter.js'; import * as utils from 'src/utils.js'; +import { config } from '../../../src/config.js'; const PUBLISHER_ID = '0000-0000-01'; const ADUNIT_ID = '000000'; @@ -357,6 +358,29 @@ describe('Seedtag Adapter', function () { }); }); + describe('COPPA param', function () { + it('should add COPPA param to payload when prebid config has parameter COPPA equal to true', function () { + config.setConfig({ coppa: true }) + + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.coppa).to.equal(true); + }) + + it('should not add COPPA param to payload when prebid config has parameter COPPA equal to false', function () { + config.setConfig({ coppa: false }) + + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.coppa).to.be.undefined; + }) + + it('should not add COPPA param to payload when prebid config has not parameter COPPA', function () { + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.coppa).to.be.undefined; + }) + }) describe('schain param', function () { it('should add schain to payload when exposed on validBidRequest', function () { // https://github.com/prebid/Prebid.js/blob/master/modules/schain.md#sample-code-for-passing-the-schain-object @@ -536,11 +560,11 @@ describe('Seedtag Adapter', function () { const timeoutUrl = getTimeoutUrl(timeoutData); expect(timeoutUrl).to.equal( 'https://s.seedtag.com/se/hb/timeout?publisherToken=' + - params.publisherId + - '&adUnitId=' + - params.adUnitId + - '&timeout=' + - timeout + params.publisherId + + '&adUnitId=' + + params.adUnitId + + '&timeout=' + + timeout ); }); @@ -552,11 +576,11 @@ describe('Seedtag Adapter', function () { expect( utils.triggerPixel.calledWith( 'https://s.seedtag.com/se/hb/timeout?publisherToken=' + - params.publisherId + - '&adUnitId=' + - params.adUnitId + - '&timeout=' + - timeout + params.publisherId + + '&adUnitId=' + + params.adUnitId + + '&timeout=' + + timeout ) ).to.equal(true); }); From 7046fc2effc22e6b21e7e78954b3f2d0f785554f Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 8 Nov 2022 07:21:01 -0800 Subject: [PATCH 098/367] Core & userId module: reload userIDs when GDPR consent changes (#9190) --- modules/userId/index.js | 36 +++++++++++++--------- src/consentHandler.js | 24 ++++++++++++++- test/helpers/consentData.js | 11 +++++-- test/spec/modules/userId_spec.js | 33 ++++++++++++++++++-- test/spec/unit/core/consentHandler_spec.js | 34 ++++++++++++++++++++ 5 files changed, 118 insertions(+), 20 deletions(-) diff --git a/modules/userId/index.js b/modules/userId/index.js index 8fdd4319dfc..9e9eb5057bc 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -588,20 +588,28 @@ function idSystemInitializer({delay = GreedyPromise.timeout} = {}) { return gdprDataHandler.promise.finally(initMetrics.startTiming('userId.init.gdpr')); } - let done = cancelAndTry( - GreedyPromise.all([hooksReady, startInit.promise]) - .then(timeGdpr) - .then(checkRefs((consentData) => { - initSubmodules(initModules, allModules, consentData); - })) - .then(() => startCallbacks.promise.finally(initMetrics.startTiming('userId.callbacks.pending'))) - .then(checkRefs(() => { - const modWithCb = initModules.filter(item => isFn(item.callback)); - if (modWithCb.length) { - return new GreedyPromise((resolve) => processSubmoduleCallbacks(modWithCb, resolve)); - } - })) - ); + let done = GreedyPromise.resolve(); + + function loadIds() { + done = cancelAndTry( + done.catch(() => null) + .then(() => GreedyPromise.all([hooksReady, startInit.promise])) + .then(timeGdpr) + .then(checkRefs((consentData) => { + initSubmodules(initModules, allModules, consentData); + })) + .then(() => startCallbacks.promise.finally(initMetrics.startTiming('userId.callbacks.pending'))) + .then(checkRefs(() => { + const modWithCb = initModules.filter(item => isFn(item.callback)); + if (modWithCb.length) { + return new GreedyPromise((resolve) => processSubmoduleCallbacks(modWithCb, resolve)); + } + })) + ); + } + + loadIds(); + gdprDataHandler.onConsentChange(loadIds); /** * with `ready` = true, starts initialization; with `refresh` = true, reinitialize submodules (optionally diff --git a/src/consentHandler.js b/src/consentHandler.js index 861a9894a2c..4a56cb4c402 100644 --- a/src/consentHandler.js +++ b/src/consentHandler.js @@ -1,11 +1,13 @@ -import {isStr, timestamp} from './utils.js'; +import {isStr, timestamp, deepEqual, logError} from './utils.js'; import {defer, GreedyPromise} from './utils/promise.js'; export class ConsentHandler { #enabled; #data; + #hasData = false; #defer; #ready; + #listeners; generatedTime; constructor() { @@ -14,8 +16,19 @@ export class ConsentHandler { #resolve(data) { this.#ready = true; + const hasChanged = !this.#hasData || !deepEqual(this.#data, data); this.#data = data; + this.#hasData = true; this.#defer.resolve(data); + if (hasChanged) { + this.#listeners.forEach(cb => { + try { + cb(data) + } catch (e) { + logError(e); + } + }) + } } /** @@ -27,6 +40,15 @@ export class ConsentHandler { this.#data = null; this.#ready = false; this.generatedTime = null; + this.#listeners = []; + } + + /** + * Register a callback to run each time consent data changes. + * @param {(consentData) => any} fn + */ + onConsentChange(fn) { + this.#listeners.push(fn); } /** diff --git a/test/helpers/consentData.js b/test/helpers/consentData.js index c708e397bd6..841e19ffe52 100644 --- a/test/helpers/consentData.js +++ b/test/helpers/consentData.js @@ -2,9 +2,14 @@ import {gdprDataHandler} from 'src/adapterManager.js'; import {GreedyPromise} from '../../src/utils/promise.js'; export function mockGdprConsent(sandbox, getConsentData = () => null) { - sandbox.stub(gdprDataHandler, 'enabled').get(() => true) - sandbox.stub(gdprDataHandler, 'promise').get(() => GreedyPromise.resolve(getConsentData())); - sandbox.stub(gdprDataHandler, 'getConsentData').callsFake(getConsentData) + const s1 = sandbox.stub(gdprDataHandler, 'enabled').get(() => true) + const s2 = sandbox.stub(gdprDataHandler, 'promise').get(() => GreedyPromise.resolve(getConsentData())); + const s3 = sandbox.stub(gdprDataHandler, 'getConsentData').callsFake(getConsentData) + return function unMock() { + s1.restore(); + s2.restore(); + s3.restore(); + } } beforeEach(() => { diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index f4abcc4b9f6..e4c6891b967 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -53,6 +53,8 @@ import {hook} from '../../../src/hook.js'; import {mockGdprConsent} from '../../helpers/consentData.js'; import {getPPID} from '../../../src/adserver.js'; import {uninstall as uninstallGdprEnforcement} from 'modules/gdprEnforcement.js'; +import {gdprDataHandler} from '../../../src/adapterManager.js'; +import {GreedyPromise} from '../../../src/utils/promise.js'; let assert = require('chai').assert; let expect = require('chai').expect; @@ -149,6 +151,8 @@ describe('User ID', function () { localStorage.removeItem(PBJS_USER_ID_OPTOUT_NAME); }); + let restoreGdprConsent; + beforeEach(function () { // TODO: this whole suite needs to be redesigned; it is passing by accident // some tests do not pass if consent data is available @@ -157,7 +161,7 @@ describe('User ID', function () { resetConsentData(); sandbox = sinon.sandbox.create(); consentData = null; - mockGdprConsent(sandbox, () => consentData); + restoreGdprConsent = mockGdprConsent(sandbox, () => consentData); coreStorage.setCookie(CONSENT_LOCAL_STORAGE_NAME, '', EXPIRED_COOKIE_DATE); }); @@ -985,6 +989,7 @@ describe('User ID', function () { let adUnits; let mockIdCallback; let auctionSpy; + let mockIdSystem; beforeEach(function () { sandbox = sinon.createSandbox(); @@ -998,7 +1003,7 @@ describe('User ID', function () { auctionSpy = sandbox.spy(); mockIdCallback = sandbox.stub(); - const mockIdSystem = { + mockIdSystem = { name: 'mockId', decode: function (value) { return { @@ -1023,6 +1028,30 @@ describe('User ID', function () { sandbox.restore(); }); + it('waits for GDPR if it was enabled after userId', () => { + restoreGdprConsent(); + mockIdSystem.getId = function (_, consent) { + if (consent?.given) { + return {id: {MOCKID: 'valid'}}; + } else { + return {id: {MOCKID: 'invalid'}}; + } + } + config.setConfig({ + userSync: { + auctionDelay: 0, + userIds: [{ + name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'} + }] + } + }); + const consent = {given: true}; + gdprDataHandler.setConsentData(consent); + return expectImmediateBidHook(auctionSpy, {adUnits}).then(() => { + expect(adUnits[0].bids[0].userId.mid).to.eql('valid'); + }) + }) + it('delays auction if auctionDelay is set, timing out at auction delay', function () { config.setConfig({ userSync: { diff --git a/test/spec/unit/core/consentHandler_spec.js b/test/spec/unit/core/consentHandler_spec.js index 082ff34f90c..9d5170eb667 100644 --- a/test/spec/unit/core/consentHandler_spec.js +++ b/test/spec/unit/core/consentHandler_spec.js @@ -56,4 +56,38 @@ describe('Consent data handler', () => { }) }) }); + + it('should run onConsentChange listeners when consent data changes', () => { + handler.setConsentData({consent: 'data'}); + const listener = sinon.stub(); + handler.onConsentChange(listener); + handler.setConsentData({consent: 'data'}); + sinon.assert.notCalled(listener); + const newConsent = {other: 'data'}; + handler.setConsentData(newConsent); + sinon.assert.calledWith(listener, newConsent); + }); + + it('should not choke if listener throws', () => { + handler.onConsentChange(sinon.stub().throws(new Error())); + const listener = sinon.stub(); + handler.onConsentChange(listener); + const consent = {consent: 'data'}; + handler.setConsentData(consent); + sinon.assert.calledWith(listener, consent); + }); + + Object.entries({ + 'undefined': undefined, + 'null': null + }).forEach(([t, val]) => { + it(`should run onConsentChange when consent is first set to ${t}`, () => { + const listener = sinon.stub(); + handler.onConsentChange(listener); + handler.setConsentData(val); + handler.setConsentData(val); + sinon.assert.calledOnce(listener); + sinon.assert.calledWith(listener, val); + }) + }) }) From 152ca5202b1d3a3f3c4365038f3b7f7445dd8a44 Mon Sep 17 00:00:00 2001 From: mjaworskiccx <50406214+mjaworskiccx@users.noreply.github.com> Date: Tue, 8 Nov 2022 16:57:28 +0100 Subject: [PATCH 099/367] Clickonometrics Bid Adapter : add gvlid (#9198) * adomain support * adomain support * adomain support * adomain support * adomain support * video params * docs changes * Clickonometrics adapter update --- modules/ccxBidAdapter.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/ccxBidAdapter.js b/modules/ccxBidAdapter.js index 7c6b0411023..331bace7928 100644 --- a/modules/ccxBidAdapter.js +++ b/modules/ccxBidAdapter.js @@ -8,6 +8,7 @@ const BID_URL = 'https://delivery.clickonometrics.pl/ortb/prebid/bid' const SUPPORTED_VIDEO_PROTOCOLS = [2, 3, 5, 6] const SUPPORTED_VIDEO_MIMES = ['video/mp4', 'video/x-flv'] const SUPPORTED_VIDEO_PLAYBACK_METHODS = [1, 2, 3, 4] +const GVLID = 773; function _getDeviceObj () { let device = {} @@ -19,8 +20,7 @@ function _getDeviceObj () { function _getSiteObj (bidderRequest) { let site = {} - // TODO: does the fallback to window.location make sense? - let url = bidderRequest?.refererInfo?.page || window.location.href + let url = bidderRequest?.refererInfo?.page if (url.length > 0) { url = url.split('?')[0] } @@ -140,6 +140,7 @@ function _buildResponse (bid, currency, ttl) { export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: ['banner', 'video'], isBidRequestValid: function (bid) { From 6d114e83725b403fadd889202b449de225db7275 Mon Sep 17 00:00:00 2001 From: Chris Huie Date: Tue, 8 Nov 2022 09:24:06 -0700 Subject: [PATCH 100/367] Revert "Clickonometrics Bid Adapter : add gvlid (#9198)" (#9216) This reverts commit 152ca5202b1d3a3f3c4365038f3b7f7445dd8a44. --- modules/ccxBidAdapter.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/ccxBidAdapter.js b/modules/ccxBidAdapter.js index 331bace7928..7c6b0411023 100644 --- a/modules/ccxBidAdapter.js +++ b/modules/ccxBidAdapter.js @@ -8,7 +8,6 @@ const BID_URL = 'https://delivery.clickonometrics.pl/ortb/prebid/bid' const SUPPORTED_VIDEO_PROTOCOLS = [2, 3, 5, 6] const SUPPORTED_VIDEO_MIMES = ['video/mp4', 'video/x-flv'] const SUPPORTED_VIDEO_PLAYBACK_METHODS = [1, 2, 3, 4] -const GVLID = 773; function _getDeviceObj () { let device = {} @@ -20,7 +19,8 @@ function _getDeviceObj () { function _getSiteObj (bidderRequest) { let site = {} - let url = bidderRequest?.refererInfo?.page + // TODO: does the fallback to window.location make sense? + let url = bidderRequest?.refererInfo?.page || window.location.href if (url.length > 0) { url = url.split('?')[0] } @@ -140,7 +140,6 @@ function _buildResponse (bid, currency, ttl) { export const spec = { code: BIDDER_CODE, - gvlid: GVLID, supportedMediaTypes: ['banner', 'video'], isBidRequestValid: function (bid) { From fe23164af37b647d561f03831027d9352495772f Mon Sep 17 00:00:00 2001 From: Brett Bloxom <38990705+BrettBlox@users.noreply.github.com> Date: Tue, 8 Nov 2022 12:00:59 -0700 Subject: [PATCH 101/367] Concert Bid Adapter: Update localStorage name-spacing for Concert UID (#9158) * collect EIDs for bid request * add ad slot positioning to payload * RPO-2012: Update local storage name-spacing for c_uid (#8) * Updates c_uid namespacing to be more specific for concert * fixes unit tests * remove console.log * RPO-2012: Add check for shared id (#9) * Adds check for sharedId * Updates cookie name * remove trailing comma Co-authored-by: antoin Co-authored-by: Antoin --- modules/concertBidAdapter.js | 20 ++++++++-- test/spec/modules/concertBidAdapter_spec.js | 41 +++++++++++++-------- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/modules/concertBidAdapter.js b/modules/concertBidAdapter.js index 620e77a5a08..dcea60d5231 100644 --- a/modules/concertBidAdapter.js +++ b/modules/concertBidAdapter.js @@ -1,4 +1,4 @@ -import { logWarn, logMessage, debugTurnedOn, generateUUID } from '../src/utils.js'; +import { logWarn, logMessage, debugTurnedOn, generateUUID, deepAccess } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { getStorageManager } from '../src/storageManager.js'; import { hasPurpose1Consent } from '../src/utils/gpdr.js'; @@ -178,7 +178,7 @@ export const spec = { registerBidder(spec); -const storage = getStorageManager({bidderCode: BIDDER_CODE}); +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); /** * Check or generate a UID for the current user. @@ -188,10 +188,24 @@ function getUid(bidderRequest) { return false; } - const CONCERT_UID_KEY = 'c_uid'; + const sharedId = deepAccess(bidderRequest, 'userId._sharedid.id'); + if (sharedId) { + return sharedId; + } + + const LEGACY_CONCERT_UID_KEY = 'c_uid'; + const CONCERT_UID_KEY = 'vmconcert_uid'; + + const legacyUid = storage.getDataFromLocalStorage(LEGACY_CONCERT_UID_KEY); let uid = storage.getDataFromLocalStorage(CONCERT_UID_KEY); + if (legacyUid) { + uid = legacyUid; + storage.setDataInLocalStorage(CONCERT_UID_KEY, uid); + storage.removeDataFromLocalStorage(LEGACY_CONCERT_UID_KEY); + } + if (!uid) { uid = generateUUID(); storage.setDataInLocalStorage(CONCERT_UID_KEY, uid); diff --git a/test/spec/modules/concertBidAdapter_spec.js b/test/spec/modules/concertBidAdapter_spec.js index 10ea997b304..00626472ecb 100644 --- a/test/spec/modules/concertBidAdapter_spec.js +++ b/test/spec/modules/concertBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; import sinon from 'sinon'; -import { spec } from 'modules/concertBidAdapter.js'; -import { getStorageManager } from '../../../src/storageManager.js' +import { spec, storage } from 'modules/concertBidAdapter.js'; +import { hook } from 'src/hook.js'; describe('ConcertAdapter', function () { let bidRequests; @@ -10,9 +10,8 @@ describe('ConcertAdapter', function () { let element; let sandbox; - afterEach(function () { - $$PREBID_GLOBAL$$.bidderSettings = {}; - sandbox.restore(); + before(function () { + hook.ready(); }); beforeEach(function () { @@ -39,6 +38,7 @@ describe('ConcertAdapter', function () { storageAllowed: true } }; + bidRequests = [ { bidder: 'concert', @@ -83,6 +83,11 @@ describe('ConcertAdapter', function () { sandbox.stub(document, 'getElementById').withArgs('desktop_leaderboard_variable').returns(element) }); + afterEach(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + sandbox.restore(); + }); + describe('spec.isBidRequestValid', function() { it('should return when it recieved all the required params', function() { const bid = bidRequests[0]; @@ -118,7 +123,6 @@ describe('ConcertAdapter', function () { }); it('should not generate uid if the user has opted out', function() { - const storage = getStorageManager(); storage.setDataInLocalStorage('c_nap', 'true'); const request = spec.buildRequests(bidRequests, bidRequest); const payload = JSON.parse(request.data); @@ -127,7 +131,6 @@ describe('ConcertAdapter', function () { }); it('should generate uid if the user has not opted out', function() { - const storage = getStorageManager(); storage.removeDataFromLocalStorage('c_nap'); const request = spec.buildRequests(bidRequests, bidRequest); const payload = JSON.parse(request.data); @@ -135,9 +138,22 @@ describe('ConcertAdapter', function () { expect(payload.meta.uid).to.not.equal(false); }); - it('should grab uid from local storage if it exists', function() { - const storage = getStorageManager(); - storage.setDataInLocalStorage('c_uid', 'foo'); + it('should use sharedid if it exists', function() { + storage.removeDataFromLocalStorage('c_nap'); + const request = spec.buildRequests(bidRequests, { + ...bidRequest, + userId: { + _sharedid: { + id: '123abc' + } + } + }); + const payload = JSON.parse(request.data); + expect(payload.meta.uid).to.equal('123abc'); + }) + + it('should grab uid from local storage if it exists and sharedid does not', function() { + storage.setDataInLocalStorage('vmconcert_uid', 'foo'); storage.removeDataFromLocalStorage('c_nap'); const request = spec.buildRequests(bidRequests, bidRequest); const payload = JSON.parse(request.data); @@ -211,7 +227,6 @@ describe('ConcertAdapter', function () { const opts = { iframeEnabled: true }; - const storage = getStorageManager(); storage.setDataInLocalStorage('c_nap', 'true'); const sync = spec.getUserSyncs(opts, [], bidRequest.gdprConsent, bidRequest.uspConsent); @@ -222,7 +237,6 @@ describe('ConcertAdapter', function () { const opts = { iframeEnabled: true }; - const storage = getStorageManager(); storage.removeDataFromLocalStorage('c_nap'); bidRequest.gdprConsent = { @@ -237,7 +251,6 @@ describe('ConcertAdapter', function () { const opts = { iframeEnabled: true }; - const storage = getStorageManager(); storage.removeDataFromLocalStorage('c_nap'); bidRequest.gdprConsent = { @@ -252,7 +265,6 @@ describe('ConcertAdapter', function () { const opts = { iframeEnabled: true }; - const storage = getStorageManager(); storage.removeDataFromLocalStorage('c_nap'); bidRequest.gdprConsent = { @@ -268,7 +280,6 @@ describe('ConcertAdapter', function () { const opts = { iframeEnabled: true }; - const storage = getStorageManager(); storage.removeDataFromLocalStorage('c_nap'); bidRequest.gdprConsent = { From c018b183948696e8873989b9e239134b157a8f3d Mon Sep 17 00:00:00 2001 From: Olivier Date: Wed, 9 Nov 2022 15:44:24 +0100 Subject: [PATCH 102/367] adagioBidAdapter: fix Video Ortb placement param validation (#9218) --- modules/adagioBidAdapter.js | 2 +- test/spec/modules/adagioBidAdapter_spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js index e59fd341bae..8dcd95f933b 100644 --- a/modules/adagioBidAdapter.js +++ b/modules/adagioBidAdapter.js @@ -59,7 +59,7 @@ export const ORTB_VIDEO_PARAMS = { 'w': (value) => isInteger(value), 'h': (value) => isInteger(value), 'startdelay': (value) => isInteger(value), - 'placement': (value) => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5].indexOf(v) !== -1), + 'placement': (value) => [1, 2, 3, 4, 5].indexOf(value) !== -1, 'linearity': (value) => [1, 2].indexOf(value) !== -1, 'skip': (value) => [0, 1].indexOf(value) !== -1, 'skipmin': (value) => isInteger(value), diff --git a/test/spec/modules/adagioBidAdapter_spec.js b/test/spec/modules/adagioBidAdapter_spec.js index e2fde8ff2e3..436d481c4a1 100644 --- a/test/spec/modules/adagioBidAdapter_spec.js +++ b/test/spec/modules/adagioBidAdapter_spec.js @@ -400,7 +400,7 @@ describe('Adagio bid adapter', () => { skipafter: 4, minduration: 10, maxduration: 30, - placement: [3], + placement: 3, protocols: [8] } }).build(); @@ -415,7 +415,7 @@ describe('Adagio bid adapter', () => { skipafter: 4, minduration: 10, maxduration: 30, - placement: [3], + placement: 3, protocols: [8], w: 300, h: 250 From 5e7ace9e3f499124181f1adddcd19a3488063f2a Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Wed, 9 Nov 2022 10:25:18 -0800 Subject: [PATCH 103/367] Revert "Core & userId module: reload userIDs when GDPR consent changes (#9190)" (#9225) This reverts commit 7046fc2effc22e6b21e7e78954b3f2d0f785554f. --- modules/userId/index.js | 36 +++++++++------------- src/consentHandler.js | 24 +-------------- test/helpers/consentData.js | 11 ++----- test/spec/modules/userId_spec.js | 33 ++------------------ test/spec/unit/core/consentHandler_spec.js | 34 -------------------- 5 files changed, 20 insertions(+), 118 deletions(-) diff --git a/modules/userId/index.js b/modules/userId/index.js index 9e9eb5057bc..8fdd4319dfc 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -588,28 +588,20 @@ function idSystemInitializer({delay = GreedyPromise.timeout} = {}) { return gdprDataHandler.promise.finally(initMetrics.startTiming('userId.init.gdpr')); } - let done = GreedyPromise.resolve(); - - function loadIds() { - done = cancelAndTry( - done.catch(() => null) - .then(() => GreedyPromise.all([hooksReady, startInit.promise])) - .then(timeGdpr) - .then(checkRefs((consentData) => { - initSubmodules(initModules, allModules, consentData); - })) - .then(() => startCallbacks.promise.finally(initMetrics.startTiming('userId.callbacks.pending'))) - .then(checkRefs(() => { - const modWithCb = initModules.filter(item => isFn(item.callback)); - if (modWithCb.length) { - return new GreedyPromise((resolve) => processSubmoduleCallbacks(modWithCb, resolve)); - } - })) - ); - } - - loadIds(); - gdprDataHandler.onConsentChange(loadIds); + let done = cancelAndTry( + GreedyPromise.all([hooksReady, startInit.promise]) + .then(timeGdpr) + .then(checkRefs((consentData) => { + initSubmodules(initModules, allModules, consentData); + })) + .then(() => startCallbacks.promise.finally(initMetrics.startTiming('userId.callbacks.pending'))) + .then(checkRefs(() => { + const modWithCb = initModules.filter(item => isFn(item.callback)); + if (modWithCb.length) { + return new GreedyPromise((resolve) => processSubmoduleCallbacks(modWithCb, resolve)); + } + })) + ); /** * with `ready` = true, starts initialization; with `refresh` = true, reinitialize submodules (optionally diff --git a/src/consentHandler.js b/src/consentHandler.js index 4a56cb4c402..861a9894a2c 100644 --- a/src/consentHandler.js +++ b/src/consentHandler.js @@ -1,13 +1,11 @@ -import {isStr, timestamp, deepEqual, logError} from './utils.js'; +import {isStr, timestamp} from './utils.js'; import {defer, GreedyPromise} from './utils/promise.js'; export class ConsentHandler { #enabled; #data; - #hasData = false; #defer; #ready; - #listeners; generatedTime; constructor() { @@ -16,19 +14,8 @@ export class ConsentHandler { #resolve(data) { this.#ready = true; - const hasChanged = !this.#hasData || !deepEqual(this.#data, data); this.#data = data; - this.#hasData = true; this.#defer.resolve(data); - if (hasChanged) { - this.#listeners.forEach(cb => { - try { - cb(data) - } catch (e) { - logError(e); - } - }) - } } /** @@ -40,15 +27,6 @@ export class ConsentHandler { this.#data = null; this.#ready = false; this.generatedTime = null; - this.#listeners = []; - } - - /** - * Register a callback to run each time consent data changes. - * @param {(consentData) => any} fn - */ - onConsentChange(fn) { - this.#listeners.push(fn); } /** diff --git a/test/helpers/consentData.js b/test/helpers/consentData.js index 841e19ffe52..c708e397bd6 100644 --- a/test/helpers/consentData.js +++ b/test/helpers/consentData.js @@ -2,14 +2,9 @@ import {gdprDataHandler} from 'src/adapterManager.js'; import {GreedyPromise} from '../../src/utils/promise.js'; export function mockGdprConsent(sandbox, getConsentData = () => null) { - const s1 = sandbox.stub(gdprDataHandler, 'enabled').get(() => true) - const s2 = sandbox.stub(gdprDataHandler, 'promise').get(() => GreedyPromise.resolve(getConsentData())); - const s3 = sandbox.stub(gdprDataHandler, 'getConsentData').callsFake(getConsentData) - return function unMock() { - s1.restore(); - s2.restore(); - s3.restore(); - } + sandbox.stub(gdprDataHandler, 'enabled').get(() => true) + sandbox.stub(gdprDataHandler, 'promise').get(() => GreedyPromise.resolve(getConsentData())); + sandbox.stub(gdprDataHandler, 'getConsentData').callsFake(getConsentData) } beforeEach(() => { diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index e4c6891b967..f4abcc4b9f6 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -53,8 +53,6 @@ import {hook} from '../../../src/hook.js'; import {mockGdprConsent} from '../../helpers/consentData.js'; import {getPPID} from '../../../src/adserver.js'; import {uninstall as uninstallGdprEnforcement} from 'modules/gdprEnforcement.js'; -import {gdprDataHandler} from '../../../src/adapterManager.js'; -import {GreedyPromise} from '../../../src/utils/promise.js'; let assert = require('chai').assert; let expect = require('chai').expect; @@ -151,8 +149,6 @@ describe('User ID', function () { localStorage.removeItem(PBJS_USER_ID_OPTOUT_NAME); }); - let restoreGdprConsent; - beforeEach(function () { // TODO: this whole suite needs to be redesigned; it is passing by accident // some tests do not pass if consent data is available @@ -161,7 +157,7 @@ describe('User ID', function () { resetConsentData(); sandbox = sinon.sandbox.create(); consentData = null; - restoreGdprConsent = mockGdprConsent(sandbox, () => consentData); + mockGdprConsent(sandbox, () => consentData); coreStorage.setCookie(CONSENT_LOCAL_STORAGE_NAME, '', EXPIRED_COOKIE_DATE); }); @@ -989,7 +985,6 @@ describe('User ID', function () { let adUnits; let mockIdCallback; let auctionSpy; - let mockIdSystem; beforeEach(function () { sandbox = sinon.createSandbox(); @@ -1003,7 +998,7 @@ describe('User ID', function () { auctionSpy = sandbox.spy(); mockIdCallback = sandbox.stub(); - mockIdSystem = { + const mockIdSystem = { name: 'mockId', decode: function (value) { return { @@ -1028,30 +1023,6 @@ describe('User ID', function () { sandbox.restore(); }); - it('waits for GDPR if it was enabled after userId', () => { - restoreGdprConsent(); - mockIdSystem.getId = function (_, consent) { - if (consent?.given) { - return {id: {MOCKID: 'valid'}}; - } else { - return {id: {MOCKID: 'invalid'}}; - } - } - config.setConfig({ - userSync: { - auctionDelay: 0, - userIds: [{ - name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'} - }] - } - }); - const consent = {given: true}; - gdprDataHandler.setConsentData(consent); - return expectImmediateBidHook(auctionSpy, {adUnits}).then(() => { - expect(adUnits[0].bids[0].userId.mid).to.eql('valid'); - }) - }) - it('delays auction if auctionDelay is set, timing out at auction delay', function () { config.setConfig({ userSync: { diff --git a/test/spec/unit/core/consentHandler_spec.js b/test/spec/unit/core/consentHandler_spec.js index 9d5170eb667..082ff34f90c 100644 --- a/test/spec/unit/core/consentHandler_spec.js +++ b/test/spec/unit/core/consentHandler_spec.js @@ -56,38 +56,4 @@ describe('Consent data handler', () => { }) }) }); - - it('should run onConsentChange listeners when consent data changes', () => { - handler.setConsentData({consent: 'data'}); - const listener = sinon.stub(); - handler.onConsentChange(listener); - handler.setConsentData({consent: 'data'}); - sinon.assert.notCalled(listener); - const newConsent = {other: 'data'}; - handler.setConsentData(newConsent); - sinon.assert.calledWith(listener, newConsent); - }); - - it('should not choke if listener throws', () => { - handler.onConsentChange(sinon.stub().throws(new Error())); - const listener = sinon.stub(); - handler.onConsentChange(listener); - const consent = {consent: 'data'}; - handler.setConsentData(consent); - sinon.assert.calledWith(listener, consent); - }); - - Object.entries({ - 'undefined': undefined, - 'null': null - }).forEach(([t, val]) => { - it(`should run onConsentChange when consent is first set to ${t}`, () => { - const listener = sinon.stub(); - handler.onConsentChange(listener); - handler.setConsentData(val); - handler.setConsentData(val); - sinon.assert.calledOnce(listener); - sinon.assert.calledWith(listener, val); - }) - }) }) From a64c8c0a2b549ce2daeac231ecaaced85633301e Mon Sep 17 00:00:00 2001 From: pm-azhar-mulla <75726247+pm-azhar-mulla@users.noreply.github.com> Date: Thu, 10 Nov 2022 12:52:40 +0530 Subject: [PATCH 104/367] PubMatic Bid Adapter: convert bid cpm to float (#9219) * Convert cpm to float * modified test case Co-authored-by: pm-azhar-mulla --- modules/pubmaticBidAdapter.js | 2 +- test/spec/modules/pubmaticBidAdapter_spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 9e2d2bc55f8..296a4314ac8 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -1254,7 +1254,7 @@ export const spec = { seatbidder.bid.forEach(bid => { let newBid = { requestId: bid.impid, - cpm: (parseFloat(bid.price) || 0).toFixed(2), + cpm: parseFloat((bid.price || 0).toFixed(2)), width: bid.w, height: bid.h, creativeId: bid.crid || bid.id, diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index 13b4e31b5c7..6b240cb2d06 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -3406,7 +3406,7 @@ describe('PubMatic adapter', function () { let 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].cpm).to.equal(parseFloat((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) { @@ -3430,7 +3430,7 @@ describe('PubMatic adapter', function () { 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)); + expect(response[1].cpm).to.equal(parseFloat((bidResponses.body.seatbid[1].bid[0].price).toFixed(2))); expect(response[1].width).to.equal(bidResponses.body.seatbid[1].bid[0].w); expect(response[1].height).to.equal(bidResponses.body.seatbid[1].bid[0].h); if (bidResponses.body.seatbid[1].bid[0].crid) { From 4082e8ad23a99ed23f4775322988d21afca5de34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udi=20Talias=20=E2=9A=9B=EF=B8=8F?= Date: Thu, 10 Nov 2022 09:51:40 +0200 Subject: [PATCH 105/367] Vidazoo Bid Adapter: cache optimizations (#9209) * feat(module): multi size request * fix getUserSyncs added tests * update(module): package-lock.json from master * feat(module): VidazooBidAdapter - send top query params to server * feat(module): vidazoo bid adapter - added performance optimization Co-authored-by: roman Co-authored-by: Saar Amrani <89377180+saar120@users.noreply.github.com> Co-authored-by: Saar Amrani --- modules/vidazooBidAdapter.js | 15 ++++++++++++++- test/spec/modules/vidazooBidAdapter_spec.js | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index 195851ad23a..fa44bde74f1 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -12,6 +12,7 @@ const TTL_SECONDS = 60 * 5; const DEAL_ID_EXPIRY = 1000 * 60 * 15; const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 60; const SESSION_ID_KEY = 'vidSid'; +const OPT_CACHE_KEY = 'vdzwopt'; export const SUPPORTED_ID_SYSTEMS = { 'britepoolid': 1, 'criteoId': 1, @@ -66,6 +67,7 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { const cId = extractCID(params); const pId = extractPID(params); const subDomain = extractSubDomain(params); + const ptrace = getCacheOpt(); let data = { url: encodeURIComponent(topWindowUrl), @@ -83,7 +85,8 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { bidderVersion: BIDDER_VERSION, prebidVersion: '$prebid.version$', res: `${screen.width}x${screen.height}`, - schain: schain + schain: schain, + ptrace: ptrace }; appendUserIdsToRequestPayload(data, userId); @@ -258,6 +261,16 @@ export function getVidazooSessionId() { return getStorageItem(SESSION_ID_KEY) || ''; } +export function getCacheOpt() { + let data = storage.getDataFromLocalStorage(OPT_CACHE_KEY); + if (!data) { + data = String(Date.now()); + storage.setDataInLocalStorage(OPT_CACHE_KEY, data); + } + + return data; +} + export function getStorageItem(key) { try { return tryParseJSON(storage.getDataFromLocalStorage(key)); diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index d30b9f31417..856ceaf438d 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -182,6 +182,7 @@ describe('VidazooBidAdapter', function () { bidderVersion: adapter.version, prebidVersion: version, schain: BID.schain, + ptrace: '1000', res: `${window.top.screen.width}x${window.top.screen.height}`, uqs: getTopWindowQueryParams(), 'ext.param1': 'loremipsum', From 31b070cfb71394dd2c3a00c774af55d7f255a741 Mon Sep 17 00:00:00 2001 From: azuryo <108641852+azuryo@users.noreply.github.com> Date: Thu, 10 Nov 2022 23:20:56 +0900 Subject: [PATCH 106/367] Microad Bid Adapter: Support Audience ID Ext and UID2.0 (#9157) * Microad Bid Adapter: Support ext params * Microad Bid Adapter: Support Unified ID 2.0 * Microad bid Adapter: Add source --- modules/microadBidAdapter.js | 33 +++++++++----- test/spec/modules/microadBidAdapter_spec.js | 48 +++++++++++++++++++++ 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/modules/microadBidAdapter.js b/modules/microadBidAdapter.js index 1b31000df43..13aea0f3f77 100644 --- a/modules/microadBidAdapter.js +++ b/modules/microadBidAdapter.js @@ -1,4 +1,5 @@ -import { deepAccess, isEmpty, isStr } from '../src/utils.js'; +import { deepAccess, isArray, isEmpty, isStr } from '../src/utils.js'; +import { find } from '../src/polyfill.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; @@ -24,15 +25,16 @@ const NATIVE_CODE = 2; const VIDEO_CODE = 4; const AUDIENCE_IDS = [ - {type: 6, bidKey: 'userId.imuid'}, - {type: 8, bidKey: 'userId.id5id.uid'}, - {type: 9, bidKey: 'userId.tdid'}, - {type: 10, bidKey: 'userId.novatiq.snowflake'}, - {type: 11, bidKey: 'userId.parrableId.eid'}, - {type: 12, bidKey: 'userId.dacId.id'}, - {type: 13, bidKey: 'userId.idl_env'}, - {type: 14, bidKey: 'userId.criteoId'}, - {type: 15, bidKey: 'userId.pubcid'} + {type: 6, bidKey: 'userId.imuid', source: 'intimatemerger.com'}, + {type: 8, bidKey: 'userId.id5id.uid', source: 'id5-sync.com'}, + {type: 9, bidKey: 'userId.tdid', source: 'adserver.org'}, + {type: 10, bidKey: 'userId.novatiq.snowflake', source: 'novatiq.com'}, + {type: 11, bidKey: 'userId.parrableId.eid', source: 'parrable.com'}, + {type: 12, bidKey: 'userId.dacId.id', source: 'dac.co.jp'}, + {type: 13, bidKey: 'userId.idl_env', source: 'liveramp.com'}, + {type: 14, bidKey: 'userId.criteoId', source: 'criteo.com'}, + {type: 15, bidKey: 'userId.pubcid', source: 'pubcid.org'}, + {type: 17, bidKey: 'userId.uid2.id', source: 'uidapi.com'} ]; function createCBT() { @@ -100,10 +102,19 @@ export const spec = { } const aidsParams = [] + const userIdAsEids = bid.userIdAsEids; AUDIENCE_IDS.forEach((audienceId) => { const bidAudienceId = deepAccess(bid, audienceId.bidKey); if (!isEmpty(bidAudienceId) && isStr(bidAudienceId)) { - aidsParams.push({ type: audienceId.type, id: bidAudienceId }); + const aidParam = { type: audienceId.type, id: bidAudienceId }; + // Set ext + if (isArray(userIdAsEids)) { + const targetEid = find(userIdAsEids, (eid) => eid.source === audienceId.source) || {}; + if (!isEmpty(deepAccess(targetEid, 'uids.0.ext'))) { + aidParam.ext = targetEid.uids[0].ext; + } + } + aidsParams.push(aidParam); // Set Ramp ID if (audienceId.type === 13) params['idl_env'] = bidAudienceId; } diff --git a/test/spec/modules/microadBidAdapter_spec.js b/test/spec/modules/microadBidAdapter_spec.js index cca337c83f2..98edfce20bc 100644 --- a/test/spec/modules/microadBidAdapter_spec.js +++ b/test/spec/modules/microadBidAdapter_spec.js @@ -330,6 +330,54 @@ describe('microadBidAdapter', () => { }) }) }) + + Object.entries({ + 'ID5 ID': { + userId: {id5id: {uid: 'id5id-sample'}}, + userIdAsEids: [ + { + source: 'id5-sync.com', + uids: [{id: 'id5id-sample', aType: 1, ext: {linkType: 2, abTestingControlGroup: false}}] + } + ], + expected: { + aids: JSON.stringify([{type: 8, id: 'id5id-sample', ext: {linkType: 2, abTestingControlGroup: false}}]) + } + }, + 'Unified ID': { + userId: {tdid: 'unified-sample'}, + userIdAsEids: [ + { + source: 'adserver.org', + uids: [{id: 'unified-sample', aType: 1, ext: {rtiPartner: 'TDID'}}] + } + ], + expected: {aids: JSON.stringify([{type: 9, id: 'unified-sample', ext: {rtiPartner: 'TDID'}}])} + }, + 'not add': { + userId: {id5id: {uid: 'id5id-sample'}}, + userIdAsEids: [], + expected: { + aids: JSON.stringify([{type: 8, id: 'id5id-sample'}]) + } + } + }).forEach(([test, arg]) => { + it(`should ${test} ext if it is available in request parameters`, () => { + const bidRequestWithUserId = { + ...bidRequestTemplate, + userId: arg.userId, + userIdAsEids: arg.userIdAsEids + } + const requests = spec.buildRequests([bidRequestWithUserId], bidderRequest) + requests.forEach((request) => { + expect(request.data).to.deep.equal({ + ...expectedResultTemplate, + cbt: request.data.cbt, + ...arg.expected + }) + }) + }); + }) }); describe('interpretResponse', () => { From db0c7f9993911d5808d348b07eb22e822d807db5 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 10 Nov 2022 21:23:46 +0000 Subject: [PATCH 107/367] Prebid 7.25.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 48ef496ee8e..7c8b7ac89b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.25.0-pre", + "version": "7.25.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index d98f313f4dc..685e9bd892d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.25.0-pre", + "version": "7.25.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 056ec5e1f7df55f412e0d040270e77f859a32ae3 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 10 Nov 2022 21:23:46 +0000 Subject: [PATCH 108/367] Increment version to 7.26.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7c8b7ac89b8..462484cb962 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.25.0", + "version": "7.26.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 685e9bd892d..8df1268bbd2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.25.0", + "version": "7.26.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 25b46f92490d5e13376632836020cebdbdd1e459 Mon Sep 17 00:00:00 2001 From: nkloeber <100145701+nkloeber@users.noreply.github.com> Date: Fri, 11 Nov 2022 14:25:25 +0100 Subject: [PATCH 109/367] Add support for additional content signals under the iab_content (#9235) --- modules/yieldlabBidAdapter.js | 27 ++-- test/spec/modules/yieldlabBidAdapter_spec.js | 125 +++++++++++++++++++ 2 files changed, 144 insertions(+), 8 deletions(-) diff --git a/modules/yieldlabBidAdapter.js b/modules/yieldlabBidAdapter.js index e5e452b4ce0..e6758e78022 100644 --- a/modules/yieldlabBidAdapter.js +++ b/modules/yieldlabBidAdapter.js @@ -370,21 +370,32 @@ function getContentObject(bid) { } /** - * Creates a string for iab_content object + * Creates a string for iab_content object by + * 1. flatten the iab content object + * 2. encoding the values + * 3. joining array of defined keys ('keyword', 'cat') into one value seperated with '|' + * 4. encoding the whole string * @param {Object} iabContent * @returns {String} */ function createIabContentString(iabContent) { const arrKeys = ['keywords', 'cat'] const str = [] - for (const key in iabContent) { - if (iabContent.hasOwnProperty(key)) { - const value = (arrKeys.indexOf(key) !== -1 && Array.isArray(iabContent[key])) - ? iabContent[key].map(node => encodeURIComponent(node)).join('|') : encodeURIComponent(iabContent[key]) - str.push(''.concat(key, ':', value)) + const transformObjToParam = (obj = {}, extraKey = '') => { + for (const key in obj) { + if ((arrKeys.indexOf(key) !== -1 && Array.isArray(obj[key]))) { + // Array of defined keyword which have to be joined into one value from "key: [value1, value2, value3]" to "key:value1|value2|value3" + str.push(''.concat(key, ':', obj[key].map(node => encodeURIComponent(node)).join('|'))) + } else if (typeof obj[key] !== 'object') { + str.push(''.concat(extraKey + key, ':', encodeURIComponent(obj[key]))) + } else { + // Object has to be further flattened + transformObjToParam(obj[key], ''.concat(extraKey, key, '.')); + } } - } - return encodeURIComponent(str.join(',')) + return str.join(','); + }; + return encodeURIComponent(transformObjToParam(iabContent)) } /** diff --git a/test/spec/modules/yieldlabBidAdapter_spec.js b/test/spec/modules/yieldlabBidAdapter_spec.js index 4c39fe5fe29..9155884106c 100644 --- a/test/spec/modules/yieldlabBidAdapter_spec.js +++ b/test/spec/modules/yieldlabBidAdapter_spec.js @@ -80,6 +80,81 @@ const NATIVE_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { } }) +const IAB_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { + params: { + adslotId: '1111', + supplyId: '2222', + iabContent: { + id: 'foo', + episode: '99', + title: 'bar', + series: 'baz', + season: 's01', + artist: 'foobar', + genre: 'barbaz', + isrc: 'CC-XXX-YY-NNNNN', + url: 'https://foo.test', + cat: ['cat1', 'cat2,ppp', 'cat3|||//'], + context: '2', + keywords: ['k1', 'k2', 'k3', 'k4'], + live: '0', + album: 'foo', + cattax: '3', + prodq: 2, + contentrating: 'foo', + userrating: 'bar', + qagmediarating: 2, + sourcerelationship: 1, + len: 12345, + language: 'en', + embeddable: 0, + producer: { + id: 'foo', + name: 'bar', + cattax: 532, + cat: [1, 'foo', true], + domain: 'producer.test' + }, + data: { + id: 'foo', + name: 'bar', + segment: [{ + name: 'foo', + value: 'bar', + ext: { + foo: { + bar: 'bar' + } + }, + }, { + name: 'foo2', + value: 'bar2', + ext: { + test: { + nums: { + int: 123, + float: 123.123 + }, + bool: true, + string: 'foo2' + } + } + }], + }, + network: { + id: 'foo', + name: 'bar', + domain: 'network.test' + }, + channel: { + id: 'bar', + name: 'foo', + domain: 'channel.test' + } + } + } +}) + const RESPONSE = { advertiser: 'yieldlab', curl: 'https://www.yieldlab.de', @@ -251,6 +326,56 @@ describe('yieldlabBidAdapter', () => { const request = spec.buildRequests([{...requestWithoutIabContent, ...siteConfig}]) expect(request.url).to.include('iab_content=id%3Aid_from_config') }) + + it('flattens the iabContent, encodes the values, joins the keywords into one value, and than encodes the iab_content request param ', () => { + const expectedIabContentValue = encodeURIComponent( + 'id:foo,' + + 'episode:99,' + + 'title:bar,' + + 'series:baz,' + + 'season:s01,' + + 'artist:foobar,' + + 'genre:barbaz,' + + 'isrc:CC-XXX-YY-NNNNN,' + + 'url:https%3A%2F%2Ffoo.test,' + + 'cat:cat1|cat2%2Cppp|cat3%7C%7C%7C%2F%2F,' + + 'context:2,' + + 'keywords:k1|k2|k3|k4,' + + 'live:0,' + + 'album:foo,' + + 'cattax:3,' + + 'prodq:2,' + + 'contentrating:foo,' + + 'userrating:bar,' + + 'qagmediarating:2,' + + 'sourcerelationship:1,' + + 'len:12345,' + + 'language:en,' + + 'embeddable:0,' + + 'producer.id:foo,' + + 'producer.name:bar,' + + 'producer.cattax:532,' + + 'cat:1|foo|true,' + + 'producer.domain:producer.test,' + + 'data.id:foo,data.name:bar,' + + 'data.segment.0.name:foo,' + + 'data.segment.0.value:bar,' + + 'data.segment.0.ext.foo.bar:bar,' + + 'data.segment.1.name:foo2,' + + 'data.segment.1.value:bar2,' + + 'data.segment.1.ext.test.nums.int:123,' + + 'data.segment.1.ext.test.nums.float:123.123,' + + 'data.segment.1.ext.test.bool:true,' + + 'data.segment.1.ext.test.string:foo2,' + + 'network.id:foo,network.name:bar,' + + 'network.domain:network.test,' + + 'channel.id:bar,' + + 'channel.name:foo,' + + 'channel.domain:channel.test' + ) + const request = spec.buildRequests([IAB_REQUEST()], REQPARAMS) + expect(request.url).to.include('iab_content=' + expectedIabContentValue) + }) }) it('passes unencoded schain string to bid request when complete == 0', () => { From 06ce1ab1b53b38de89bdd641b4147ae146c9b785 Mon Sep 17 00:00:00 2001 From: preved-medved Date: Mon, 14 Nov 2022 11:51:02 +0000 Subject: [PATCH 110/367] SmartyTech Bid Adapter : initial adapter release (#9196) * Add new bid adapter for company smartytech * change domain to prod * update unit tests * remove unused code * remove unused code --- modules/smartytechBidAdapter.js | 78 +++++++++ modules/smartytechBidAdapter.md | 44 +++++ .../spec/modules/smartytechBidAdapter_spec.js | 162 ++++++++++++++++++ 3 files changed, 284 insertions(+) create mode 100644 modules/smartytechBidAdapter.js create mode 100644 modules/smartytechBidAdapter.md create mode 100644 test/spec/modules/smartytechBidAdapter_spec.js diff --git a/modules/smartytechBidAdapter.js b/modules/smartytechBidAdapter.js new file mode 100644 index 00000000000..231ca315de8 --- /dev/null +++ b/modules/smartytechBidAdapter.js @@ -0,0 +1,78 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {buildUrl} from '../src/utils.js' + +const BIDDER_CODE = 'smartytech'; +export const ENDPOINT_PROTOCOL = 'https'; +export const ENDPOINT_DOMAIN = 'server.smartytech.io'; +export const ENDPOINT_PATH = '/hb/bidder'; + +export const spec = { + code: BIDDER_CODE, + + isBidRequestValid: function (bidRequest) { + return !!parseInt(bidRequest.params.endpointId); + }, + + buildRequests: function (validBidRequests, bidderRequest) { + const referer = bidderRequest?.refererInfo?.page || window.location.href; + + const bidRequests = validBidRequests.map((validBidRequest) => { + return { + endpointId: validBidRequest.params.endpointId, + adUnitCode: validBidRequest.adUnitCode, + sizes: validBidRequest.sizes, + bidId: validBidRequest.bidId, + referer: referer + }; + }); + + let adPartnerRequestUrl = buildUrl({ + protocol: ENDPOINT_PROTOCOL, + hostname: ENDPOINT_DOMAIN, + pathname: ENDPOINT_PATH, + }); + + return { + method: 'POST', + url: adPartnerRequestUrl, + data: bidRequests + }; + }, + + interpretResponse: function (serverResponse, bidRequest) { + if (typeof serverResponse.body === 'undefined') { + return []; + } + + const validBids = bidRequest.data; + const keys = Object.keys(serverResponse.body) + const responseBody = serverResponse.body; + + return keys.filter(key => { + return responseBody[key].ad + }).map(key => { + return { + bid: validBids.find(b => b.adUnitCode === key), + response: responseBody[key] + } + }).map(item => spec.adResponse(item.bid.bidId, item.response)); + }, + + adResponse: function (requestId, response) { + const bidObject = { + requestId, + ad: response.ad, + cpm: response.cpm, + width: response.width, + height: response.height, + ttl: 60, + creativeId: response.creativeId, + netRevenue: true, + currency: response.currency, + } + return bidObject; + }, + +} + +registerBidder(spec); diff --git a/modules/smartytechBidAdapter.md b/modules/smartytechBidAdapter.md new file mode 100644 index 00000000000..dbfc2833c78 --- /dev/null +++ b/modules/smartytechBidAdapter.md @@ -0,0 +1,44 @@ +# Overview + +Module Name: SmartyTech Bidder Adapter + +Module Type: Bidder Adapter + +Maintainer: info@adpartner.pro + +# Description + +You can use this adapter to get a bid from smartytech.io. + +About us : https://smartytech.io + +# Test Parameters + +```javascript + var adUnits = [ + { + code: 'div-smartytech-example', + sizes: [[300, 250]], + bids: [ + { + bidder: "smartytech", + params: { + endpointId: 14 + } + } + ] + }, + { + code: 'div-smartytech-example-2', + sizes: [[300, 250]], + bids: [ + { + bidder: "smartytech", + params: { + endpointId: 14 + } + } + ] + } +]; +``` diff --git a/test/spec/modules/smartytechBidAdapter_spec.js b/test/spec/modules/smartytechBidAdapter_spec.js new file mode 100644 index 00000000000..78503d7a6f0 --- /dev/null +++ b/test/spec/modules/smartytechBidAdapter_spec.js @@ -0,0 +1,162 @@ +import {expect} from 'chai'; +import {spec, ENDPOINT_PROTOCOL, ENDPOINT_DOMAIN, ENDPOINT_PATH} from 'modules/smartytechBidAdapter'; +import {newBidder} from 'src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'smartytech'; + +describe('SmartyTechDSPAdapter: inherited functions', function () { + let adapter; + beforeEach(() => { + adapter = newBidder(spec); + }); + it('exists and is a function', function () { + expect(adapter.callBids).to.be.exist.and.to.be.a('function'); + }); + it(`bidder code is ${BIDDER_CODE}`, function () { + expect(spec.code).to.be.equal(BIDDER_CODE); + }) +}); + +describe('SmartyTechDSPAdapter: isBidRequestValid', function () { + it('Invalid bid request. Should return false', function () { + const invalidBidFixture = { + params: { + use_id: 13144375 + } + } + expect(spec.isBidRequestValid(invalidBidFixture)).to.be.false + }); + it('Valid bid request. Should return true', function () { + const validBidFixture = { + params: { + endpointId: 13144375 + } + } + expect(spec.isBidRequestValid(validBidFixture)).to.be.true + }); +}); + +function mockRandomSizeArray(len) { + return Array.apply(null, {length: len}).map(i => { + return [Math.floor(Math.random() * 800), Math.floor(Math.random() * 800)] + }); +} + +function mockBidRequestListData(size) { + return Array.apply(null, {length: size}).map((i, index) => { + const id = Math.floor(Math.random() * 800) * (index + 1); + return { + adUnitCode: `adUnitCode-${id}`, + sizes: mockRandomSizeArray(index + 1), + bidId: `bidId-${id}`, + params: { + endpointId: id + } + } + }); +} + +function mockRefererData() { + return { + refererInfo: { + page: 'https://some-test.page' + } + } +} + +function mockResponseData(requestData) { + let data = {} + + requestData.data.forEach((request, index) => { + const sizeArrayIndex = Math.floor(Math.random() * (request.sizes.length - 1)); + const rndIndex = Math.floor(Math.random() * 800); + + data[request.adUnitCode] = { + ad: `ad-${rndIndex}`, + width: request.sizes[sizeArrayIndex][0], + height: request.sizes[sizeArrayIndex][1], + creativeId: `creative-id-${index}`, + cpm: Math.floor(Math.random() * 100), + currency: `UAH-${rndIndex}` + }; + }); + return { + body: data + } +}; + +describe('SmartyTechDSPAdapter: buildRequests', () => { + let mockBidRequest; + let mockReferer; + beforeEach(() => { + mockBidRequest = mockBidRequestListData(8); + mockReferer = mockRefererData(); + }); + it('has return data', () => { + const request = spec.buildRequests(mockBidRequest, mockReferer); + expect(request).not.null; + }); + it('correct request URL', () => { + const request = spec.buildRequests(mockBidRequest, mockReferer); + expect(request.url).to.be.equal(`${ENDPOINT_PROTOCOL}://${ENDPOINT_DOMAIN}${ENDPOINT_PATH}`) + }); + it('correct request method', () => { + const request = spec.buildRequests(mockBidRequest, mockReferer); + expect(request.method).to.be.equal(`POST`) + }); + it('correct request data', () => { + const data = spec.buildRequests(mockBidRequest, mockReferer).data; + data.forEach((request, index) => { + expect(request.adUnitCode).to.be.equal(mockBidRequest[index].adUnitCode); + expect(request.sizes).to.be.equal(mockBidRequest[index].sizes); + expect(request.bidId).to.be.equal(mockBidRequest[index].bidId); + expect(request.endpointId).to.be.equal(mockBidRequest[index].params.endpointId); + expect(request.referer).to.be.equal(mockReferer.refererInfo.page); + }) + }); +}); + +describe('SmartyTechDSPAdapter: interpretResponse', () => { + let mockBidRequest; + let mockReferer; + let request; + let mockResponse; + beforeEach(() => { + const brData = mockBidRequestListData(2); + mockReferer = mockRefererData(); + request = spec.buildRequests(brData, mockReferer); + mockBidRequest = { + data: brData + } + mockResponse = mockResponseData(request); + }); + + it('interpretResponse: empty data request', () => { + delete mockResponse['body'] + const data = spec.interpretResponse(mockResponse, mockBidRequest); + expect(data.length).to.be.equal(0); + }); + + it('interpretResponse: response data and convert data arrays has same length', () => { + const keys = Object.keys(mockResponse.body); + const data = spec.interpretResponse(mockResponse, mockBidRequest); + expect(data.length).to.be.equal(keys.length); + }); + + it('interpretResponse: convert to correct data', () => { + const keys = Object.keys(mockResponse.body); + const data = spec.interpretResponse(mockResponse, mockBidRequest); + + data.forEach((responseItem, index) => { + expect(responseItem.ad).to.be.equal(mockResponse.body[keys[index]].ad); + expect(responseItem.cpm).to.be.equal(mockResponse.body[keys[index]].cpm); + expect(responseItem.creativeId).to.be.equal(mockResponse.body[keys[index]].creativeId); + expect(responseItem.currency).to.be.equal(mockResponse.body[keys[index]].currency); + expect(responseItem.netRevenue).to.be.true; + expect(responseItem.ttl).to.be.equal(60); + expect(responseItem.requestId).to.be.equal(mockBidRequest.data[index].bidId); + expect(responseItem.width).to.be.equal(mockResponse.body[keys[index]].width); + expect(responseItem.height).to.be.equal(mockResponse.body[keys[index]].height); + }); + }); +}); From 12cad7b43f1458121ac574d2a657af49f8c96535 Mon Sep 17 00:00:00 2001 From: asurovenko-zeta <80847074+asurovenko-zeta@users.noreply.github.com> Date: Mon, 14 Nov 2022 15:30:14 +0100 Subject: [PATCH 111/367] ZetaSppBidAdapter: provide tmax (#9240) Co-authored-by: Surovenko Alexey --- modules/zeta_global_sspBidAdapter.js | 4 ++++ .../modules/zeta_global_sspBidAdapter_spec.js | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/modules/zeta_global_sspBidAdapter.js b/modules/zeta_global_sspBidAdapter.js index 4689683fbc7..6c5b9783782 100644 --- a/modules/zeta_global_sspBidAdapter.js +++ b/modules/zeta_global_sspBidAdapter.js @@ -129,6 +129,10 @@ export const spec = { deepSetValue(payload, 'regs.ext.us_privacy', bidderRequest.uspConsent); } + if (bidderRequest?.timeout) { + payload.tmax = bidderRequest.timeout; + } + provideEids(validBidRequests[0], payload); const url = params.shortname ? ENDPOINT_URL.concat('?shortname=', params.shortname) : ENDPOINT_URL; return { diff --git a/test/spec/modules/zeta_global_sspBidAdapter_spec.js b/test/spec/modules/zeta_global_sspBidAdapter_spec.js index 3bd17697f2d..d6befa0fc78 100644 --- a/test/spec/modules/zeta_global_sspBidAdapter_spec.js +++ b/test/spec/modules/zeta_global_sspBidAdapter_spec.js @@ -104,7 +104,8 @@ describe('Zeta Ssp Bid Adapter', function () { }, uspConsent: 'someCCPAString', params: params, - userIdAsEids: eids + userIdAsEids: eids, + timeout: 500 }]; const videoRequest = [{ @@ -344,4 +345,18 @@ describe('Zeta Ssp Bid Adapter', function () { expect(payload.imp[1].banner.w).to.eql(600); expect(payload.imp[1].banner.h).to.eql(400); }); + + it('Test provide tmax', function () { + const request = spec.buildRequests(bannerRequest, bannerRequest[0]); + const payload = JSON.parse(request.data); + + expect(payload.tmax).to.eql(500); + }); + + it('Test provide tmax without value', function () { + const request = spec.buildRequests(videoRequest, videoRequest[0]); + const payload = JSON.parse(request.data); + + expect(payload.tmax).to.be.undefined; + }); }); From 0470f7085b6267b52dd99aa1b87c386e17bbc2c9 Mon Sep 17 00:00:00 2001 From: Fatih Kaya Date: Mon, 14 Nov 2022 17:51:24 +0300 Subject: [PATCH 112/367] Admatic Bid Adapter: pixad alias and bid floor features activated (#9204) * Admatic Bidder Adaptor * Update admaticBidAdapter.md * Update admaticBidAdapter.md * remove floor parameter * Update admaticBidAdapter.js * Admatic Bid Adapter: alias and bid floor features activated * Admatic adapter: host param control changed * Alias name changed. * Revert "Admatic adapter: host param control changed" This reverts commit de7ac85981b1ba3ad8c5d1dc95c5dadbdf5b9895. * added alias feature and host param * Revert "added alias feature and host param" This reverts commit 6ec8f4539ea6be403a0d7e08dad5c7a5228f28a1. * Revert "Alias name changed." This reverts commit 661c54f9b2397e8f25c257144d73161e13466281. * Revert "Admatic Bid Adapter: alias and bid floor features activated" This reverts commit 7a2e0e29c49e2f876b68aafe886b336fe2fe6fcb. * Revert "Update admaticBidAdapter.js" This reverts commit 7a845b7151bbb08addfb58ea9bd5b44167cc8a4e. * Revert "remove floor parameter" This reverts commit 7a23b055ccd4ea23d23e73248e82b21bc6f69d90. * Admatic adapter: host param control && Add new Bidder * Revert "Admatic adapter: host param control && Add new Bidder" This reverts commit 3c797b120c8e0fe2b851381300ac5c4b1f92c6e2. * commit new features * Update admaticBidAdapter.js * updated for coverage * sync updated * Update adloader.js --- modules/admaticBidAdapter.js | 167 +++++++----- modules/admaticBidAdapter.md | 4 +- src/adloader.js | 1 - test/spec/modules/admaticBidAdapter_spec.js | 265 +++++++++++++++++++- 4 files changed, 372 insertions(+), 65 deletions(-) diff --git a/modules/admaticBidAdapter.js b/modules/admaticBidAdapter.js index 039f27e5de0..ec4401b77c9 100644 --- a/modules/admaticBidAdapter.js +++ b/modules/admaticBidAdapter.js @@ -1,94 +1,93 @@ import { getValue, logError, deepAccess, getBidIdParameter, isArray } from '../src/utils.js'; -import { loadExternalScript } from '../src/adloader.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; - -const ENDPOINT_URL = 'https://layer.serve.admatic.com.tr/pb'; -const SYNC_URL = 'https://cdn.serve.admatic.com.tr/showad/sync.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +const SYNC_URL = 'https://cdn.serve.admatic.com.tr/showad/sync.html'; const BIDDER_CODE = 'admatic'; - export const spec = { - code: 'admatic', - supportedMediaTypes: ['video', '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. + code: BIDDER_CODE, + aliases: [ + {code: 'pixad'} + ], + supportedMediaTypes: [BANNER, VIDEO], + /** f + * @param {object} bid + * @return {boolean} */ - isBidRequestValid: function(bid) { + isBidRequestValid: (bid) => { let isValid = false; - if (typeof bid.params !== 'undefined') { - let isValidNetworkId = _validateId(getValue(bid.params, 'networkId')); - isValid = isValidNetworkId;// && isValidTypeId; + if (bid?.params) { + const isValidNetworkId = _validateId(getValue(bid.params, 'networkId')); + const isValidHost = _validateString(getValue(bid.params, 'host')); + isValid = isValidNetworkId && isValidHost; } if (!isValid) { - logError('AdMatic networkId parameters are required. Bid aborted.'); + logError(`${bid.bidder} networkId and host parameters are required. Bid aborted.`); } return isValid; }, + /** - * Make a server request from the list of BidRequests. - * - * @param {validBidRequests[]} an array of bids - * @return ServerRequest Info describing the request to the server. + * @param {BidRequest[]} validBidRequests + * @return {ServerRequest} */ - buildRequests: function(validBidRequests, bidderRequest) { + buildRequests: (validBidRequests, bidderRequest) => { const bids = validBidRequests.map(buildRequestObject); const networkId = getValue(validBidRequests[0].params, 'networkId'); + const host = getValue(validBidRequests[0].params, 'host'); const currency = getValue(validBidRequests[0].params, 'currency') || 'TRY'; - - setTimeout(() => { - loadExternalScript(SYNC_URL, BIDDER_CODE); - }, bidderRequest.timeout); + const bidderName = validBidRequests[0].bidder; const payload = { - 'user': { - 'ua': navigator.userAgent + user: { + ua: navigator.userAgent }, - 'blacklist': [], - 'site': { - 'page': location.href, - 'ref': location.origin, - 'publisher': { - 'name': location.hostname, - 'publisherId': networkId + blacklist: [], + site: { + page: location.href, + ref: location.origin, + publisher: { + name: location.hostname, + publisherId: networkId } }, imp: bids, ext: { - 'cur': currency, - 'type': 'admatic' + cur: currency, + bidder: bidderName } }; - const payloadString = JSON.stringify(payload); - return { - method: 'POST', - url: ENDPOINT_URL, - data: payloadString, - options: { - contentType: 'application/json' - } - }; + if (payload) { + return { method: 'POST', url: `https://${host}/pb?bidder=${bidderName}`, data: payload, options: { contentType: 'application/json' } }; + } + }, + + getUserSyncs: function (syncOptions, responses) { + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: SYNC_URL + }]; + } }, + /** - * 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. + * @param {*} response + * @param {ServerRequest} request + * @return {Bid[]} */ interpretResponse: (response, request) => { const body = response.body || response; const bidResponses = []; - if (body.data.length > 0) { - body.data.forEach(function (bid) { + if (body && body?.data && isArray(body.data)) { + body.data.forEach(bid => { const resbid = { requestId: bid.id, cpm: bid.price, width: bid.width, height: bid.height, - currency: body.cur, + currency: body.cur || 'TRY', netRevenue: true, ad: bid.party_tag, creativeId: bid.creative_id, @@ -96,22 +95,68 @@ export const spec = { advertiserDomains: bid && bid.adomain ? bid.adomain : [] }, ttl: 360, - bidder: 'admatic', - timeToRespond: 1, - requestTimestamp: 1 + bidder: bid.bidder }; + bidResponses.push(resbid); }); - }; + } return bidResponses; } }; +function enrichSlotWithFloors(slot, bidRequest) { + try { + const slotFloors = {}; + + if (bidRequest.getFloor) { + if (bidRequest.mediaTypes?.banner) { + slotFloors.banner = {}; + const bannerSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes')) + bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = bidRequest.getFloor({ size: bannerSize, mediaType: BANNER })); + } + + if (bidRequest.mediaTypes?.video) { + slotFloors.video = {}; + const videoSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize')) + videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = bidRequest.getFloor({ size: videoSize, mediaType: VIDEO })); + } + + if (Object.keys(slotFloors).length > 0) { + if (!slot) { + slot = {} + } + Object.assign(slot, { + floors: slotFloors + }); + } + } + } catch (e) { + logError('Could not parse floors from Prebid: ' + e); + } +} + +function parseSizes(sizes, parser = s => s) { + if (sizes == undefined) { + return []; + } + 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 buildRequestObject(bid) { const reqObj = {}; reqObj.size = getSizes(bid); reqObj.id = getBidIdParameter('bidId', bid); - reqObj.floor = getValue(bid.params, 'floor') || 0.01; + + enrichSlotWithFloors(reqObj, bid); + return reqObj; } @@ -144,4 +189,8 @@ function _validateId(id) { return (parseInt(id) > 0); } +function _validateString(str) { + return (typeof str == 'string'); +} + registerBidder(spec); diff --git a/modules/admaticBidAdapter.md b/modules/admaticBidAdapter.md index de84998d0af..2bf9afb3cdc 100644 --- a/modules/admaticBidAdapter.md +++ b/modules/admaticBidAdapter.md @@ -19,7 +19,7 @@ Use `admatic` as bidder. bidder: 'admatic', params: { networkId: 12345, - floor: 0.5 + host: 'layer.serve.admatic.com.tr' } }] },{ @@ -29,7 +29,7 @@ Use `admatic` as bidder. bidder: 'admatic', params: { networkId: 12345, - floor: 0.5 + host: 'layer.serve.admatic.com.tr' } }] }]; diff --git a/src/adloader.js b/src/adloader.js index 330b52b3ed5..64408683e9f 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -6,7 +6,6 @@ const _requestCache = new WeakMap(); const _approvedLoadExternalJSList = [ 'debugging', 'adloox', - 'admatic', 'criteo', 'outstream', 'adagio', diff --git a/test/spec/modules/admaticBidAdapter_spec.js b/test/spec/modules/admaticBidAdapter_spec.js index c7d391cfaca..65a7b4111b7 100644 --- a/test/spec/modules/admaticBidAdapter_spec.js +++ b/test/spec/modules/admaticBidAdapter_spec.js @@ -3,7 +3,7 @@ import {spec, storage} from 'modules/admaticBidAdapter.js'; import {newBidder} from 'src/adapters/bidderFactory.js'; import {getStorageManager} from 'src/storageManager'; -const ENDPOINT = 'https://layer.serve.admatic.com.tr/v1'; +const ENDPOINT = 'https://layer.serve.admatic.com.tr/pb?bidder=admatic'; describe('admaticBidAdapter', () => { const adapter = newBidder(spec); @@ -18,7 +18,8 @@ describe('admaticBidAdapter', () => { let bid = { 'bidder': 'admatic', 'params': { - 'networkId': 10433394 + 'networkId': 10433394, + 'host': 'layer.serve.admatic.com.tr' }, 'adUnitCode': 'adunit-code', 'sizes': [[300, 250], [300, 600]], @@ -37,10 +38,268 @@ describe('admaticBidAdapter', () => { delete bid.params; bid.params = { - 'networkId': 0 + 'networkId': 0, + 'host': 'layer.serve.admatic.com.tr' }; expect(spec.isBidRequestValid(bid)).to.equal(false); }); }); + + describe('buildRequests', function () { + it('sends bid request to ENDPOINT via POST', function () { + let validRequest = [ { + 'bidder': 'admatic', + 'params': { + 'networkId': 10433394, + 'host': 'layer.serve.admatic.com.tr' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [728, 90]] + } + }, + getFloor: inputParams => { + if (inputParams.mediaType === BANNER && inputParams.size[0] === 300 && inputParams.size[1] === 250) { + return { + currency: 'USD', + floor: 1.0 + }; + } else if (inputParams.mediaType === BANNER && inputParams.size[0] === 728 && inputParams.size[1] === 90) { + return { + currency: 'USD', + floor: 2.0 + }; + } else { + return {} + } + }, + 'user': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36' + }, + 'blacklist': [], + 'site': { + 'page': 'http://localhost:8888/admatic.html', + 'ref': 'http://localhost:8888', + 'publisher': { + 'name': 'localhost', + 'publisherId': 12321312 + } + }, + 'imp': [ + { + 'size': [ + { + 'w': 300, + 'h': 250 + }, + { + 'w': 728, + 'h': 90 + } + ], + 'id': '2205da7a81846b', + 'floors': { + 'banner': { + '300x250': { 'currency': 'USD', 'floor': 1 }, + '728x90': { 'currency': 'USD', 'floor': 2 } + } + } + } + ], + 'ext': { + 'cur': 'USD', + 'bidder': 'admatic' + } + } ]; + let bidderRequest = { + 'bidder': 'admatic', + 'params': { + 'networkId': 10433394, + 'host': 'layer.serve.admatic.com.tr' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [728, 90]] + } + }, + getFloor: inputParams => { + if (inputParams.mediaType === BANNER && inputParams.size[0] === 300 && inputParams.size[1] === 250) { + return { + currency: 'USD', + floor: 1.0 + }; + } else if (inputParams.mediaType === BANNER && inputParams.size[0] === 728 && inputParams.size[1] === 90) { + return { + currency: 'USD', + floor: 2.0 + }; + } else { + return {} + } + }, + 'user': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36' + }, + 'blacklist': [], + 'site': { + 'page': 'http://localhost:8888/admatic.html', + 'ref': 'http://localhost:8888', + 'publisher': { + 'name': 'localhost', + 'publisherId': 12321312 + } + }, + 'imp': [ + { + 'size': [ + { + 'w': 300, + 'h': 250 + }, + { + 'w': 728, + 'h': 90 + } + ], + 'id': '2205da7a81846b', + 'floors': { + 'banner': { + '300x250': { 'currency': 'USD', 'floor': 1 }, + '728x90': { 'currency': 'USD', 'floor': 2 } + } + } + } + ], + 'ext': { + 'cur': 'USD', + 'bidder': 'admatic' + } + }; + const request = spec.buildRequests(validRequest, bidderRequest); + expect(request.url).to.equal(ENDPOINT); + expect(request.method).to.equal('POST'); + }); + + it('should properly build a banner request with floors', function () { + let bidRequests = [ + { + 'bidder': 'admatic', + 'params': { + 'networkId': 10433394, + 'host': 'layer.serve.admatic.com.tr' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [728, 90]] + } + }, + getFloor: inputParams => { + if (inputParams.mediaType === BANNER && inputParams.size[0] === 300 && inputParams.size[1] === 250) { + return { + currency: 'USD', + floor: 1.0 + }; + } else if (inputParams.mediaType === BANNER && inputParams.size[0] === 728 && inputParams.size[1] === 90) { + return { + currency: 'USD', + floor: 2.0 + }; + } else { + return {} + } + } + }, + ]; + let bidderRequest = { + 'bidder': 'admatic', + 'params': { + 'networkId': 10433394, + 'host': 'layer.serve.admatic.com.tr' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [728, 90]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'creativeId': 'er2ee', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [728, 90]] + } + } + }; + const request = spec.buildRequests(bidRequests, bidderRequest); + request.data.imp[0].floors = { + 'banner': { + '300x250': { 'currency': 'USD', 'floor': 1 }, + '728x90': { 'currency': 'USD', 'floor': 2 } + } + }; + }); + }); + + describe('interpretResponse', function () { + it('should get correct bid responses', function() { + let bids = { body: { + data: [ + { + 'id': 1, + 'creative_id': '374', + 'width': 300, + 'height': 250, + 'price': 0.01, + 'bidder': 'admatic', + 'adomain': ['admatic.com.tr'], + 'party_tag': '
' + } + ], + 'queryId': 'cdnbh24rlv0hhkpfpln0', + 'status': true + }}; + + let expectedResponse = [ + { + requestId: 1, + cpm: 0.01, + width: 300, + height: 250, + currency: 'TRY', + netRevenue: true, + ad: '
', + creativeId: '374', + meta: { + advertiserDomains: ['admatic.com.tr'] + }, + ttl: 360, + bidder: 'admatic' + } + ]; + const request = { + ext: { + 'cur': 'TRY', + 'type': 'admatic' + } + }; + let result = spec.interpretResponse(bids, {data: request}); + expect(result).to.eql(expectedResponse); + }); + + it('handles nobid responses', function () { + let request = { + ext: { + 'cur': 'TRY', + 'type': 'admatic' + } + }; + let bids = { body: { + data: [], + 'queryId': 'cdnbh24rlv0hhkpfpln0', + 'status': true + }}; + + let result = spec.interpretResponse(bids, {data: request}); + expect(result.length).to.equal(0); + }); + }); }); From cc501e167cffb8cb4c839022ad58981acab156d0 Mon Sep 17 00:00:00 2001 From: takuhou Date: Tue, 15 Nov 2022 09:54:03 +0900 Subject: [PATCH 113/367] YieldOne Bid Adapter: update documentation, test and code style (#9233) * add parameter test * change new_format to single_format * fix adomain typo * add parameter test * add jsdoc comment and update readme * change @return to @returns * change param and returns * add typeof and change param/returns * change returns value * change flux to 1x1 Co-authored-by: TakuhoSanpei --- modules/yieldoneBidAdapter.js | 68 +++++++++-- modules/yieldoneBidAdapter.md | 118 +++++++++++++++++-- test/spec/modules/yieldoneBidAdapter_spec.js | 36 +++++- 3 files changed, 199 insertions(+), 23 deletions(-) diff --git a/modules/yieldoneBidAdapter.js b/modules/yieldoneBidAdapter.js index 4c5f1687641..d408a0595f9 100644 --- a/modules/yieldoneBidAdapter.js +++ b/modules/yieldoneBidAdapter.js @@ -4,6 +4,17 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import { Renderer } from '../src/Renderer.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; +/** + * @typedef {import('../src/adapters/bidderFactory').Bid} Bid + * @typedef {import('../src/adapters/bidderFactory').BidRequest} BidRequest + * @typedef {import('../src/adapters/bidderFactory').BidderSpec} BidderSpec + * @typedef {import('../src/adapters/bidderFactory').ServerRequest} ServerRequest + * @typedef {import('../src/adapters/bidderFactory').ServerResponse} ServerResponse + * @typedef {import('../src/adapters/bidderFactory').SyncOptions} SyncOptions + * @typedef {import('../src/adapters/bidderFactory').UserSync} UserSync + * @typedef {import('../src/auction').BidderRequest} BidderRequest + */ + const BIDDER_CODE = 'yieldone'; const ENDPOINT_URL = 'https://y.one.impact-ad.jp/h_bid'; const USER_SYNC_URL = 'https://y.one.impact-ad.jp/push_sync'; @@ -13,13 +24,25 @@ const VIEWABLE_PERCENTAGE_URL = 'https://img.ak.impact-ad.jp/ic/pone/ivt/firstvi const DEFAULT_VIDEO_SIZE = {w: 640, h: 360}; +/** @type BidderSpec */ export const spec = { code: BIDDER_CODE, aliases: ['y1'], supportedMediaTypes: [BANNER, VIDEO], + /** + * Determines whether or not the given bid request is valid. + * @param {BidRequest} bid The bid params to validate. + * @returns {boolean} True if this is a valid bid, and false otherwise. + */ isBidRequestValid: function(bid) { return !!(bid.params.placementId); }, + /** + * Make a server request from the list of BidRequests. + * @param {Bid[]} validBidRequests - An array of bids. + * @param {BidderRequest} bidderRequest - bidder request object. + * @returns {ServerRequest|ServerRequest[]} ServerRequest Info describing the request to the server. + */ buildRequests: function(validBidRequests, bidderRequest) { return validBidRequests.map(bidRequest => { const params = bidRequest.params; @@ -96,6 +119,12 @@ export const spec = { }; }); }, + /** + * Unpack the response from the server into a list of bids. + * @param {ServerResponse} serverResponse - A successful response from the server. + * @param {BidRequest} bidRequests + * @returns {Bid[]} - An array of bids which were nested inside the server. + */ interpretResponse: function(serverResponse, bidRequest) { const bidResponses = []; const response = serverResponse.body; @@ -188,6 +217,11 @@ export const spec = { } return bidResponses; }, + /** + * Register the user sync pixels which should be dropped after the auction. + * @param {SyncOptions} syncOptions Which user syncs are allowed? + * @returns {UserSync[]} The user syncs which should be dropped. + */ getUserSyncs: function(syncOptions) { if (syncOptions.iframeEnabled) { return [{ @@ -202,7 +236,7 @@ export const spec = { * NOTE: server side does not yet support multiple formats. * @param {Object} bidRequest - * @param {boolean} [enabledOldFormat = true] - default: `true`. - * @return {string|null} - `"banner"` or `"video"` or `null`. + * @returns {string|null} - `"banner"` or `"video"` or `null`. */ function getMediaType(bidRequest, enabledOldFormat = true) { let hasBannerType = Boolean(deepAccess(bidRequest, 'mediaTypes.banner')); @@ -239,7 +273,7 @@ function getMediaType(bidRequest, enabledOldFormat = true) { * @param {Object} bidRequest.banner - * @param {Array} bidRequest.banner.sizes - * @param {boolean} [enabledOldFormat = true] - default: `true`. - * @return {string} - strings like `"300x250"` or `"300x250,728x90"`. + * @returns {string} - strings like `"300x250"` or `"300x250,728x90"`. */ function getBannerSizes(bidRequest, enabledOldFormat = true) { let sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); @@ -254,10 +288,10 @@ function getBannerSizes(bidRequest, enabledOldFormat = true) { /** * @param {Object} bidRequest - * @param {boolean} [enabledOldFormat = true] - default: `true`. - * @param {boolean} [enabledFlux = true] - default: `true`. - * @return {{w: number, h: number}} - + * @param {boolean} [enabled1x1 = true] - default: `true`. + * @returns {{w: number, h: number}} - */ -function getVideoSize(bidRequest, enabledOldFormat = true, enabledFlux = true) { +function getVideoSize(bidRequest, enabledOldFormat = true, enabled1x1 = true) { /** * @param {Array | Array>} sizes - * @return {{w: number, h: number} | null} - @@ -287,10 +321,10 @@ function getVideoSize(bidRequest, enabledOldFormat = true, enabledFlux = true) { playerSize = playerSize || _getPlayerSize(bidRequest.sizes); } - if (enabledFlux) { - // NOTE: `video.playerSize` in Flux is always [1,1]. + if (enabled1x1) { + // NOTE: `video.playerSize` in 1x1 is always [1,1]. if (playerSize && (playerSize.w === 1 && playerSize.h === 1)) { - // NOTE: `params.playerSize` is a specific object to support `FLUX`. + // NOTE: `params.playerSize` is a specific object to support `1x1`. playerSize = _getPlayerSize(deepAccess(bidRequest, 'params.playerSize')); } } @@ -298,6 +332,11 @@ function getVideoSize(bidRequest, enabledOldFormat = true, enabledFlux = true) { return playerSize || DEFAULT_VIDEO_SIZE; } +/** + * Create render for outstream video. + * @param {Object} serverResponse.body - + * @returns {Renderer} - Prebid Renderer object + */ function newRenderer(response) { const renderer = Renderer.install({ id: response.uid, @@ -314,12 +353,21 @@ function newRenderer(response) { return renderer; } +/** + * Handles an outstream response after the library is loaded + * @param {Object} bid + */ function outstreamRender(bid) { bid.renderer.push(() => { window.DACIVTPREBID.renderPrebid(bid); }); } +/** + * Create render for cmer outstream video. + * @param {Object} serverResponse.body - + * @returns {Renderer} - Prebid Renderer object + */ function newCmerRenderer(response) { const renderer = Renderer.install({ id: response.uid, @@ -336,6 +384,10 @@ function newCmerRenderer(response) { return renderer; } +/** + * Handles an outstream response after the library is loaded + * @param {Object} bid + */ function cmerRender(bid) { bid.renderer.push(() => { window.CMERYONEPREBID.renderPrebid(bid); diff --git a/modules/yieldoneBidAdapter.md b/modules/yieldoneBidAdapter.md index 1414d4e464f..d1306a08202 100644 --- a/modules/yieldoneBidAdapter.md +++ b/modules/yieldoneBidAdapter.md @@ -13,8 +13,7 @@ Connect to YIELDONE for bids. THE YIELDONE adapter requires setup and approval from the YIELDONE team. Please reach out to your account team or y1s@platform-one.co.jp for more information. -Note: THE YIELDONE adapter do not support "multi-format" scenario... if both -banner and video are specified as mediatypes, YIELDONE will treat it as a video unit. +YIELDONE adapter supports Banner, Video and Multi-Format(video, banner) currently. # Test Parameters ```javascript @@ -24,13 +23,16 @@ var adUnits = [ code: 'banner-div', mediaTypes: { banner: { - sizes: [[300, 250], [336, 280]] + sizes: [ + [300, 250], + [336, 280] + ] } }, bids: [{ bidder: 'yieldone', params: { - placementId: '36891' + placementId: '36891' // required } }] }, @@ -44,11 +46,109 @@ var adUnits = [ }, }, bids: [{ - bidder: 'yieldone', - params: { - placementId: '41993' - } - }] + bidder: "yieldone", + params: { + placementId: "36892", // required + playerParams: { // optional + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }] + }, + // Video adUnit(mediaTypes.video.playerSize: [1,1]) + { + code: 'video-1x1-div', + mediaTypes: { + video: { + playerSize: [[1, 1]], + context: 'outstream' + }, + }, + bids: [{ + bidder: 'yieldone', + params: { + placementId: "36892", // required + playerSize: [640, 360], // required + playerParams: { // optional + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }] + }, + // Multi-Format adUnit + { + code: "multi-format-div", + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [1, 1] + ] + }, + video: { + playerSize: [640, 360], + context: "outstream" + } + }, + bids: [{ + // * "video" bid object should be placed before "banner" bid object. + // This bid will request a "video" media type ad. + bidder: "yieldone", + params: { + placementId: "36892", // required + playerParams: { // required + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }, + { + // This bid will request a "banner" media type ad. + bidder: "yieldone", + params: { + placementId: "36891" // required + } + } + ] + }, + // Multi-Format adUnit(mediaTypes.video.playerSize: [1,1]) + { + code: "multi-format-1x1-div", + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [1, 1] + ] + }, + video: { + playerSize: [1, 1], + context: "outstream" + } + }, + bids: [{ + // * "video" bid object should be placed before "banner" bid object. + // This bid will request a "video" media type ad. + bidder: "yieldone", + params: { + placementId: "36892", // required + playerSize: [640, 360], // required + playerParams: { // required + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }, + { + // This bid will request a "banner" media type ad. + bidder: "yieldone", + params: { + placementId: "36891" // required + } + } + ] } ``` diff --git a/test/spec/modules/yieldoneBidAdapter_spec.js b/test/spec/modules/yieldoneBidAdapter_spec.js index 59bd4a80081..a10247411db 100644 --- a/test/spec/modules/yieldoneBidAdapter_spec.js +++ b/test/spec/modules/yieldoneBidAdapter_spec.js @@ -140,7 +140,7 @@ describe('yieldoneBidAdapter', function() { }); }); - describe('New Format', function () { + describe('Single Format', function () { const bidRequests = [ { params: {placementId: '0'}, @@ -206,8 +206,11 @@ describe('yieldoneBidAdapter', function() { it('width and height should be set as separate parameters on outstream requests', function () { expect(request[0].data).to.not.have.property('w'); + expect(request[0].data).to.not.have.property('h'); expect(request[1].data).to.not.have.property('w'); + expect(request[1].data).to.not.have.property('h'); expect(request[2].data).to.not.have.property('w'); + expect(request[2].data).to.not.have.property('h'); expect(request[3].data.w).to.equal(1280); expect(request[3].data.h).to.equal(720); expect(request[4].data.w).to.equal(1920); @@ -260,12 +263,13 @@ describe('yieldoneBidAdapter', function() { it('width and height should be set as separate parameters on outstream requests', function () { expect(request[0].data).to.not.have.property('w'); + expect(request[0].data).to.not.have.property('h'); expect(request[1].data.w).to.equal(1920); expect(request[1].data.h).to.equal(1080); }); }); - describe('FLUX Format', function () { + describe('1x1 Format', function () { const bidRequests = [ { // It will be treated as a banner. @@ -326,6 +330,7 @@ describe('yieldoneBidAdapter', function() { it('width and height should be set as separate parameters on outstream requests', function () { expect(request[0].data).to.not.have.property('w'); + expect(request[0].data).to.not.have.property('h'); expect(request[1].data.w).to.equal(1920); expect(request[1].data.h).to.equal(1080); expect(request[2].data.w).to.equal(DEFAULT_VIDEO_SIZE.w); @@ -500,9 +505,9 @@ describe('yieldoneBidAdapter', function() { 'currency': 'JPY', 'statusMessage': 'Bid available', 'dealId': 'P1-FIX-7800-DSP-MON', - 'admoain': [ + 'adomain': [ 'www.example.com' - ] + ], } }; @@ -528,7 +533,16 @@ describe('yieldoneBidAdapter', function() { }]; let result = spec.interpretResponse(serverResponseBanner, bidRequestBanner[0]); expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + expect(result[0].requestId).to.equal(expectedResponse[0].requestId); + expect(result[0].cpm).to.equal(expectedResponse[0].cpm); + expect(result[0].width).to.equal(expectedResponse[0].width); + expect(result[0].height).to.equal(expectedResponse[0].height); + expect(result[0].creativeId).to.equal(expectedResponse[0].creativeId); + expect(result[0].dealId).to.equal(expectedResponse[0].dealId); + expect(result[0].currency).to.equal(expectedResponse[0].currency); expect(result[0].mediaType).to.equal(expectedResponse[0].mediaType); + expect(result[0].ad).to.equal(expectedResponse[0].ad); + expect(result[0].meta.advertiserDomains[0]).to.equal(expectedResponse[0].meta.advertiserDomains[0]); }); let serverResponseVideo = { @@ -537,7 +551,7 @@ describe('yieldoneBidAdapter', function() { 'height': 360, 'width': 640, 'cpm': 0.0536616, - 'dealId': 'P1-FIX-766-DSP-MON', + 'dealId': 'P1-FIX-7800-DSP-MON', 'crid': '2494768', 'currency': 'JPY', 'statusMessage': 'Bid available', @@ -575,7 +589,7 @@ describe('yieldoneBidAdapter', function() { 'currency': 'JPY', 'netRevenue': true, 'ttl': 3000, - 'referrer': '', + 'referrer': 'http%3A%2F%2Flocalhost%3A9876%2F%3Fid%3D74552836', 'meta': { 'advertiserDomains': [] }, @@ -588,9 +602,19 @@ describe('yieldoneBidAdapter', function() { }]; let result = spec.interpretResponse(serverResponseVideo, bidRequestVideo[0]); expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + expect(result[0].requestId).to.equal(expectedResponse[0].requestId); + expect(result[0].cpm).to.equal(expectedResponse[0].cpm); + expect(result[0].width).to.equal(expectedResponse[0].width); + expect(result[0].height).to.equal(expectedResponse[0].height); + expect(result[0].creativeId).to.equal(expectedResponse[0].creativeId); + expect(result[0].dealId).to.equal(expectedResponse[0].dealId); + expect(result[0].currency).to.equal(expectedResponse[0].currency); + expect(result[0].vastXml).to.equal(expectedResponse[0].vastXml); expect(result[0].mediaType).to.equal(expectedResponse[0].mediaType); + expect(result[0].referrer).to.equal(expectedResponse[0].referrer); expect(result[0].renderer.id).to.equal(expectedResponse[0].renderer.id); expect(result[0].renderer.url).to.equal(expectedResponse[0].renderer.url); + expect(result[0].meta.advertiserDomains[0]).to.equal(expectedResponse[0].meta.advertiserDomains[0]); }); it('handles empty bid response', function () { From 4d6c88dcb508b92467b06b0f352a60dd8dfb3e9e Mon Sep 17 00:00:00 2001 From: John Conway Date: Tue, 15 Nov 2022 04:52:25 -0500 Subject: [PATCH 114/367] Zeus Prime RTD Module: initial module release (#9165) * docs(zeusPrime): added zeusPrimeRtdProvider documenation * test: added zeusPrimeRtdProvider tests * feat: added zeusPrime rtd submodule * chore: fix issue with params in the initModule function * chore: lint fixes * chore: lint fixes for tests * test: mock subtle since some tests run insecure crypto.subtle is only available in secure instances on new browsers, and browserstack runs some tests not in secure mode, so crypto.subtle is undefine. This just creates a mock sublte to avoid this in the tests. * test: try to override subtle when it doesnt exist in tests * test: remove subtle restore * chore: added ZeusPrime to .submodules.json --- modules/.submodules.json | 3 +- modules/zeusPrimeRtdProvider.js | 357 +++++++++++++++ modules/zeusPrimeRtdProvider.md | 60 +++ .../spec/modules/zeusPrimeRtdProvider_spec.js | 410 ++++++++++++++++++ 4 files changed, 829 insertions(+), 1 deletion(-) create mode 100644 modules/zeusPrimeRtdProvider.js create mode 100644 modules/zeusPrimeRtdProvider.md create mode 100644 test/spec/modules/zeusPrimeRtdProvider_spec.js diff --git a/modules/.submodules.json b/modules/.submodules.json index aad778be67b..52bbc638c79 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -71,7 +71,8 @@ "reconciliationRtdProvider", "sirdataRtdProvider", "timeoutRtdProvider", - "weboramaRtdProvider" + "weboramaRtdProvider", + "zeusPrimeRtdProvider" ], "fpdModule": [ "enrichmentFpdModule", diff --git a/modules/zeusPrimeRtdProvider.js b/modules/zeusPrimeRtdProvider.js new file mode 100644 index 00000000000..28c46957c50 --- /dev/null +++ b/modules/zeusPrimeRtdProvider.js @@ -0,0 +1,357 @@ +/** + * This module adds Zeus Insights For Publishers (ZIP) provider to the real time data module + * The {@link module:modules/realTimeData} module is required + * + * This module will request the article topics for the current page and add them as page keyvalues + * for the ad requests. + * + * @module modules/zeusInsightsForPublishersRtdProvider + * @requires module:modules/realTimeData + */ + +import { logInfo, logError, logWarn, logMessage } from '../src/utils.js' +import { submodule } from '../src/hook.js' +import { ajaxBuilder } from '../src/ajax.js' + +class Logger { + get showDebug() { + if (this._showDebug === true || this._showDebug === false) { + return this._showDebug + } + + return window.zeusPrime?.debug || false + } + set showDebug(shouldShow) { + this._showDebug = shouldShow + } + + get error() { + return logError.bind(this, 'zeusPrimeRtdProvider: ') + } + get warn() { + return logWarn.bind(this, 'zeusPrimeRtdProvider: ') + } + get info() { + return logInfo.bind(this, 'zeusPrimeRtdProvider: ') + } + get debug() { + if (this.showDebug) { + return logMessage.bind(this, 'zeusPrimeRtdProvider: ') + } + + return () => {} + } +} + +var logger = new Logger() + +function loadCommandQueue() { + window.zeusPrime = window.zeusPrime || { cmd: [] } + const queue = [...window.zeusPrime.cmd] + + window.zeusPrime.cmd = [] + window.zeusPrime.cmd.push = (callback) => { + callback(window.zeusPrime) + } + + queue.forEach((callback) => callback(window.zeusPrime)) +} + +function markStatusComplete(key) { + const status = window?.zeusPrime?.status + if (status) { + status[key] = true + } +} + +function createStatus() { + if (window.zeusPrime && !window.zeusPrime.status) { + Object.defineProperty(window.zeusPrime, 'status', { + enumerable: false, + value: { + initComplete: false, + primeKeyValueSet: false, + insightsReqSent: false, + insightsReqReceived: false, + insightsKeyValueSet: false, + scriptComplete: false, + }, + }) + } +} + +function loadPrimeQueryParams() { + try { + const params = new URLSearchParams(window.location.search) + params.forEach((paramValue, paramKey) => { + if (!paramKey.startsWith('zeus_prime_')) { + return + } + + let key = paramKey.replace('zeus_prime_', '') + let value = paramValue.toLowerCase() + + if (value === 'true' || value === '1') { + value = true + } else if (value === 'false' || value === '0') { + value = false + } + + window.zeusPrime[key] = value + }) + } catch (_) {} +} + +const DEFAULT_API = 'https://insights.zeustechnology.com' + +function init(gamId = null, options = {}) { + window.zeusPrime = window.zeusPrime || { cmd: [] } + + window.zeusPrime.gamId = gamId || options.gamId || window.zeusPrime.gamId || undefined + window.zeusPrime.api = DEFAULT_API + window.zeusPrime.hostname = options.hostname || window.location?.hostname || '' + window.zeusPrime.pathname = options.pathname || window.location?.pathname || '' + window.zeusPrime.pageUrl = `${window.zeusPrime.hostname}${window.zeusPrime.pathname}` + window.zeusPrime.pageHash = options.pageHash || null + window.zeusPrime.debug = window.zeusPrime.debug || options.debug === true || false + window.zeusPrime.disabled = window.zeusPrime.disabled || options.disabled === true || false + + loadPrimeQueryParams() + + logger.showDebug = window.zeusPrime.debug + + createStatus() + markStatusComplete('initComplete') +} + +function setTargeting() { + const { gamId, hostname } = window.zeusPrime + + if (typeof gamId !== 'string') { + throw new Error(`window.zeusPrime.gamId must be a string. Received: ${String(gamId)}`) + } + + addKeyValueToGoogletag(`zeus_${gamId}`, hostname) + logger.debug(`Setting zeus_${gamId}=${hostname}`) + markStatusComplete('primeKeyValueSet') +} + +function setPrimeAsDisabled() { + addKeyValueToGoogletag('zeus_prime', 'false') + logger.debug('Disabling prime; Setting key-value zeus_prime to false') +} + +function addKeyValueToGoogletag(key, value) { + window.googletag = window.googletag || { cmd: [] } + window.googletag.cmd.push(function () { + window.googletag.pubads().setTargeting(key, value) + }) +} + +function isInsightsPage(pathname = '') { + const NOT_SECTIONS = [ + { + test: /\/search/, + type: 'search', + }, + { + test: /\/author/, + type: 'author', + }, + { + test: /\/event/, + type: 'event', + }, + { + test: /\/homepage/, + type: 'front', + }, + { + test: /^\/?$/, + type: 'front', + }, + ] + + const typeObj = NOT_SECTIONS.find((pg) => pathname.match(pg.test)) + return typeObj === undefined +} + +async function getUrlHash(canonical) { + try { + const buf = await window.crypto.subtle.digest( + 'SHA-1', + new TextEncoder('utf-8').encode(canonical) + ) + const hashed = Array.prototype.map + .call(new Uint8Array(buf), (x) => `00${x.toString(16)}`.slice(-2)) + .join('') + + return hashed + } catch (e) { + logger.error('Failed to load hash', e.message) + logger.debug('Exception', e) + return '' + } +} + +async function sendPrebidRequest(url) { + return new Promise((resolve, reject) => { + const ajax = ajaxBuilder() + ajax(url, { + success: (responseText, response) => { + resolve({ + ...response, + status: response.status, + json: () => JSON.parse(responseText), + }) + }, + + error: (responseText, response) => { + if (!response.status) { + reject(response) + } + + let json = responseText + if (responseText) { + try { + json = JSON.parse(responseText) + } catch (_) { + json = null + } + } + + resolve({ + status: response.status, + json: () => json || null, + responseValue: json, + }) + }, + }) + }) +} + +async function requestTopics() { + const { api, hostname, pageUrl } = window.zeusPrime + + if (!window.zeusPrime.pageHash) { + window.zeusPrime.pageHash = await getUrlHash(pageUrl) + } + + const pageHash = window.zeusPrime.pageHash + const zeusInsightsUrl = `${api}/${hostname}/${pageHash}?article_location=${pageUrl}` + + logger.debug('Requesting topics', zeusInsightsUrl) + try { + markStatusComplete('insightsReqSent') + const response = await sendPrebidRequest(zeusInsightsUrl) + if (response.status === 200) { + logger.debug('topics found') + markStatusComplete('insightsReqReceived') + return await response.json() + } else if ( + response.status === 204 || + response.status < 200 || + (response.status >= 300 && response.status <= 399) + ) { + logger.debug('no topics found') + markStatusComplete('insightsReqReceived') + return null + } else { + logger.error(`Topics request returned error: ${response.status}`) + markStatusComplete('insightsReqReceived') + return null + } + } catch (e) { + logger.error('failed to request topics', e) + return null + } +} + +function setTopicsTargeting(topics = []) { + if (topics.length === 0) { + return + } + + window.googletag = window.googletag || { cmd: [] } + window.googletag.cmd.push(function () { + window.googletag.pubads().setTargeting('zeus_insights', topics) + }) + + markStatusComplete('insightsKeyValueSet') +} + +async function startTopicsRequest() { + if (isInsightsPage(window.zeusPrime.pathname)) { + const response = await requestTopics() + if (response) { + setTopicsTargeting(response?.topics) + } + } else { + logger.debug('This page is not eligible for topics, request will be skipped') + } +} + +async function run(gamId, options = {}) { + logger.showDebug = options.debug || false + + try { + init(gamId, options) + loadCommandQueue() + + if (window.zeusPrime.disabled) { + setPrimeAsDisabled() + } else { + setTargeting() + await startTopicsRequest() + } + } catch (e) { + logger.error('Failed to run.', e.message || e) + } finally { + markStatusComplete('scriptComplete') + } +} + +/** + * @preserve + * Initializes the ZeusPrime RTD Submodule. The config provides the GamID for this + * site that is used to configure Prime. + * @param {object} config The Prebid configuration for this module. + * @param {object} config.params The parameters for this module. + * @param {string} config.params.gamId The Gam ID (or Network Code) in GAM for this site. + */ +function initModule(config) { + const { params } = config || {} + const { gamId, ...rest } = params || {} + run(gamId, rest) +} + +/** + * @preserve + * @type {RtdSubmodule} + */ +const zeusPrimeSubmodule = { + /** + * @preserve + * The name of the plugin. + * @type {string} + */ + name: 'zeusPrime', + + /** + * @preserve + * ZeusPrime use + */ + init: initModule, +} + +/** + * @preserve + * Register the Sub Module. + */ +function registerSubModule() { + submodule('realTimeData', zeusPrimeSubmodule) +} + +registerSubModule() + +export { zeusPrimeSubmodule } diff --git a/modules/zeusPrimeRtdProvider.md b/modules/zeusPrimeRtdProvider.md new file mode 100644 index 00000000000..f3a6c5018d5 --- /dev/null +++ b/modules/zeusPrimeRtdProvider.md @@ -0,0 +1,60 @@ +# Overview + +Module Name: Zeus Prime RTD Provider +Module Type: Rtd Provider +Maintainer: support@zeustechnology.com + +## Description + +The Zeus Prime RTD Provider provides integration of Zeus Prime onto sites with Prebid. This module will request information from Zeus Prime servers to add the page level targeting required for Prime into the customer's ad setup. + +Zeus Prime runs as soon as the code is initialized, so it can retrieve the information required from the Zeus Prime server to create the targeting key-values. Zeus Prime will provide two page level key-values: `zeus_` and `zeus_insights`. Zeus Prime provides contextual information about a pages content, and does not provide user information that could present privacy implications. + +For more information and help with setting up Zeus Prime, see the [onboarding documentation site](https://onboarding.zeustechnology.com). + +## Usage + +To use Zeus Prime, add `zeusPrimeRtdProvider` into your Prebid build: + +``` +gulp build --modules=rtdModule,zeusPrimeRtdProvider +``` + +> Note that the global RTD module, `rtdModule`, is required for the Zeus Prime RTD module. + +Once the code is included, configure Zeus Prime in your Prebid configuration: + +```javascript +pbjs.setConfig({ + ..., + realTimeData: { + dataProviders: [{ + name: 'zeusPrime', + waitForIt: false, + params: { + gamId: '' + } + }] + }, + ... +}) +``` + +## Parameters + +The parameters below describe the configuration object used to configure Zeus Prime. + +| Name | Type | Description | Default | +|------------------------|----------|-----------------------------------------------------------------------------------------------|---------| +| name | String | This will always be `zeusPrime` | - | +| waitForIt | Boolean | Should be false since Zeus Prime runs on initial load and not during the bidding cycle. | `false` | +| params | Object | | - | +| params.gamId | String | The gamId or Google Ad Manager Network Code to access your Google Ad Manager instance. | - | + +### `gamId` Parameter + +Zeus Prime requires the gamId parameter, or the Google Ad Manager Network Code, to reference your account. See the [Google documentation](https://support.google.com/admanager/answer/7674889?hl=en) to find out where you can retrieve the Network Code. + +## Troubleshooting + +For troubleshooting steps and guides to assist with verifying your Zeus Prime installation, see our [installation documentation](https://onboarding.zeustechnology.com/docs/installation). \ No newline at end of file diff --git a/test/spec/modules/zeusPrimeRtdProvider_spec.js b/test/spec/modules/zeusPrimeRtdProvider_spec.js new file mode 100644 index 00000000000..294d98df377 --- /dev/null +++ b/test/spec/modules/zeusPrimeRtdProvider_spec.js @@ -0,0 +1,410 @@ +import { zeusPrimeSubmodule } from 'modules/zeusPrimeRtdProvider'; +import { server } from 'test/mocks/xhr.js'; +import * as utils from 'src/utils'; + +async function waitForStatus(statusVar) { + const MAX_COUNT = 20; + let count = 0; + while ( + count <= MAX_COUNT && + window.zeusPrime.status && + window.zeusPrime.status[statusVar] !== true + ) { + count += 1; + await new Promise((resolve) => setTimeout(resolve, 10)); + } + + if (count === MAX_COUNT) { + throw new Error('Timeout waiting for zeusPrimeRtdProvider to complete'); + } +} + +/** + * Execute all the commands in the googletag.cmd queue. + */ +function executeGoogletagTargeting() { + window.googletag.cmd.forEach((cmd) => cmd()); +} + +describe('Zeus Prime RTD submodule', () => { + let logErrorSpy; + let logMessageSpy; + let setTargetingStub; + let originalGtag; + + beforeEach(() => { + logErrorSpy = sinon.spy(utils, 'logError'); + logMessageSpy = sinon.spy(utils, 'logMessage'); + setTargetingStub = sinon.stub(); + window.zeusPrime = { cmd: [] }; + originalGtag = window.googletag; + window.googletag = { + cmd: [], + pubads: () => ({ + setTargeting: setTargetingStub, + }), + }; + + // Mock subtle since this doesnt exists in some test environments due to security in newer browsers. + if (typeof window.crypto.subtle === 'undefined') { + Object.defineProperty(crypto, 'subtle', { value: { digest: () => 'mockHash' } }) + } + }); + + afterEach(() => { + logErrorSpy.restore(); + logMessageSpy.restore(); + window.googletag = originalGtag; + }); + + it('should init and set key-value for zeus_', async () => { + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + hostname: 'www.example.com', + pathname: '/', + }, + }); + + // wait for the script to finish + await waitForStatus('scriptComplete'); + + // execute any googletag commands added to the queue during execution + executeGoogletagTargeting(); + + expect(window.googletag.cmd).to.have.length(1); + sinon.assert.callCount(setTargetingStub, 1); + sinon.assert.calledWith(setTargetingStub, 'zeus_1234', 'www.example.com'); + }); + + it('should init and set key-value for zeus_ from command queue', async () => { + window.zeusPrime.cmd.push((prime) => (prime.gamId = '9876')); + zeusPrimeSubmodule.init({ + params: { + hostname: 'www.example.com', + pathname: '/', + }, + }); + + // wait for the script to finish + await waitForStatus('scriptComplete'); + + // execute any googletag commands added to the queue during execution + executeGoogletagTargeting(); + + expect(window.googletag.cmd).to.have.length(1); + sinon.assert.callCount(setTargetingStub, 1); + sinon.assert.calledWith(setTargetingStub, 'zeus_9876', 'www.example.com'); + }); + + it('should init with values from location and set key-value for zeus_', async () => { + zeusPrimeSubmodule.init({ params: { gamId: '1234' } }); + + // wait for the script to finish + await waitForStatus('scriptComplete'); + + // execute any googletag commands added to the queue during execution + executeGoogletagTargeting(); + + expect(window.googletag.cmd).to.have.length(1); + sinon.assert.callCount(setTargetingStub, 1); + sinon.assert.calledWith(setTargetingStub, 'zeus_1234', 'localhost'); + expect(window.zeusPrime.pathname).to.equal('/context.html'); + }); + + it('should emit error when gamId is not set', async () => { + zeusPrimeSubmodule.init({}); + + // wait for the script to finish + await waitForStatus('scriptComplete'); + + // execute any googletag commands added to the queue during execution + executeGoogletagTargeting(); + + expect(window.googletag.cmd).to.have.length(0); + sinon.assert.callCount(setTargetingStub, 0); + sinon.assert.calledWith( + logErrorSpy, + 'zeusPrimeRtdProvider: ', + 'Failed to run.', + 'window.zeusPrime.gamId must be a string. Received: undefined' + ); + }); + + it('should not make a call to the server when url is a homepage', async () => { + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + hostname: 'www.example.com', + pathname: '/', + }, + }); + + // wait for the script to finish + await waitForStatus('scriptComplete'); + + expect(server.requests).to.have.length(0); + }); + + it('should make a call to the server and set key-vlaue when url is an article page and returns topics', async () => { + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + hostname: 'www.example.com', + pathname: '/article/some-article', + }, + }); + + // Wait for request to be sent + await waitForStatus('insightsReqReceived'); + + // Response + server.requests[0].respond( + 200, + { 'Content-Type': 'application/json' }, + '{"topics": ["bs0"]}' + ); + + // Wait for the script to process the response + await waitForStatus('scriptComplete'); + + // execute any googletag commands added to the queue during execution + executeGoogletagTargeting(); + + expect(server.requestCount).to.be.equal(1); + expect(window.googletag.cmd).to.have.length(2); + sinon.assert.calledTwice(setTargetingStub); + sinon.assert.calledWith( + setTargetingStub.firstCall, + 'zeus_1234', + 'www.example.com' + ); + sinon.assert.calledWith(setTargetingStub.secondCall, 'zeus_insights', [ + 'bs0', + ]); + sinon.assert.notCalled(logErrorSpy); + }); + + it('should not set insights keyvalue when server returns 204', async () => { + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + hostname: 'www.example.com', + pathname: '/article/some-article', + }, + }); + + // Wait for request to be sent + await waitForStatus('insightsReqReceived'); + + // Response + server.requests[0].respond(204, { 'Content-Type': 'application/json' }); + + // Wait for the script to process the response + await waitForStatus('scriptComplete'); + + // execute any googletag commands added to the queue during execution + executeGoogletagTargeting(); + + expect(server.requestCount).to.be.equal(1); + expect(window.googletag.cmd).to.have.length(1); + sinon.assert.calledOnce(setTargetingStub); + sinon.assert.calledWith( + setTargetingStub.firstCall, + 'zeus_1234', + 'www.example.com' + ); + sinon.assert.notCalled(logErrorSpy); + }); + + it('should not set insights keyvalue when server returns empty topics array', async () => { + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + hostname: 'www.example.com', + pathname: '/article/some-article', + }, + }); + + // Wait for request to be sent + await waitForStatus('insightsReqReceived'); + + // Respond + server.requests[0].respond( + 200, + { 'Content-Type': 'application/json' }, + '{ "topics": [] }' + ); + + // Wait for the script to process the response + await waitForStatus('scriptComplete'); + + // execute any googletag commands added to the queue during execution + executeGoogletagTargeting(); + + expect(server.requestCount).to.be.equal(1); + expect(window.googletag.cmd).to.have.length(1); + sinon.assert.calledOnce(setTargetingStub); + sinon.assert.calledWith( + setTargetingStub.firstCall, + 'zeus_1234', + 'www.example.com' + ); + sinon.assert.notCalled(logErrorSpy); + }); + + it('should not set insights keyvalue and emit error when server returns error status (400)', async () => { + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + hostname: 'www.example.com', + pathname: '/article/some-article', + }, + }); + + // Wait for request to be sent + await waitForStatus('insightsReqReceived'); + + // Response + server.requests[0].respond( + 404, + { 'Content-Type': 'application/json' }, + '{"message": "Not found"}' + ); + + // Wait for the script to process the response + await waitForStatus('scriptComplete'); + + // execute any googletag commands added to the queue during execution + executeGoogletagTargeting(); + + expect(server.requestCount).to.be.equal(1); + expect(window.googletag.cmd).to.have.length(1); + sinon.assert.calledOnce(setTargetingStub); + sinon.assert.calledWith( + setTargetingStub.firstCall, + 'zeus_1234', + 'www.example.com' + ); + sinon.assert.calledWith( + logErrorSpy, + 'zeusPrimeRtdProvider: ', + 'Topics request returned error: 404' + ); + }); + + it('should not set insights keyvalue and emit error when response is not received (network request)', async () => { + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + hostname: 'www.example.com', + pathname: '/article/some-article', + }, + }); + + // Wait for request to be sent + await waitForStatus('insightsReqReceived'); + + // Response + server.requests[0].error(); + + // Wait for the script to process the response + await waitForStatus('scriptComplete'); + + // execute any googletag commands added to the queue during execution + executeGoogletagTargeting(); + + expect(server.requestCount).to.be.equal(1); + expect(window.googletag.cmd).to.have.length(1); + sinon.assert.calledOnce(setTargetingStub); + sinon.assert.calledWith( + setTargetingStub.firstCall, + 'zeus_1234', + 'www.example.com' + ); + sinon.assert.calledWith( + logErrorSpy, + 'zeusPrimeRtdProvider: ', + 'failed to request topics' + ); + }); + + it('fails gracefully when crypto fails', async () => { + const digestStub = sinon.stub(window.crypto.subtle, 'digest'); + digestStub.throwsException('Failed to generate digest.'); + + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + hostname: 'www.example.com', + pathname: '/article/some-article', + }, + }); + + // Wait for request to be sent + await waitForStatus('scriptComplete'); + + sinon.assert.calledWith( + logErrorSpy, + 'zeusPrimeRtdProvider: ', + 'Failed to load hash' + ); + + digestStub.restore(); + }); + + it('script should add zeus_prime key and not send request when disabled is set', async () => { + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + disabled: true, + hostname: 'www.example.com', + pathname: '/article/some-article', + }, + }); + + // Wait for request to be sent + await waitForStatus('scriptComplete'); + + // execute any googletag commands added to the queue during execution + executeGoogletagTargeting(); + + expect(server.requestCount).to.be.equal(0); + expect(window.googletag.cmd).to.have.length(1); + sinon.assert.calledWith(setTargetingStub, 'zeus_prime', 'false'); + }); + + it('debug true enables debug logging', async () => { + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + debug: true, + hostname: 'www.example.com', + pathname: '/article/some-article', + }, + }); + + // Wait for request to be sent + await waitForStatus('scriptComplete'); + + sinon.assert.called(logMessageSpy); + sinon.assert.notCalled(logErrorSpy); + }); + + it('debug false disables debug logging', async () => { + window.zeusPrime.disabled = false; + zeusPrimeSubmodule.init({ + params: { + gamId: '1234', + hostname: 'www.example.com', + pathname: '/article/some-article', + }, + }); + + // Wait for request to be sent + await waitForStatus('scriptComplete'); + + sinon.assert.notCalled(logMessageSpy); + sinon.assert.notCalled(logErrorSpy); + }); +}); From 0813039d91c91639903d5b7a92991fff2082cf79 Mon Sep 17 00:00:00 2001 From: Oleksandr Soldatov Date: Tue, 15 Nov 2022 11:53:01 +0200 Subject: [PATCH 115/367] Captify RTD Submodule: Initial release (#9180) * Captify Live-classification Rtd Submodule * Fix code-review comments --- .../gpt/captifyRtdProvider_example.html | 167 ++++++++++++ modules/.submodules.json | 1 + modules/captifyRtdProvider.js | 146 ++++++++++ modules/captifyRtdProvider.md | 68 +++++ test/spec/modules/captifyRtdProvider_spec.js | 253 ++++++++++++++++++ 5 files changed, 635 insertions(+) create mode 100644 integrationExamples/gpt/captifyRtdProvider_example.html create mode 100644 modules/captifyRtdProvider.js create mode 100644 modules/captifyRtdProvider.md create mode 100644 test/spec/modules/captifyRtdProvider_spec.js diff --git a/integrationExamples/gpt/captifyRtdProvider_example.html b/integrationExamples/gpt/captifyRtdProvider_example.html new file mode 100644 index 00000000000..955fbf8be70 --- /dev/null +++ b/integrationExamples/gpt/captifyRtdProvider_example.html @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + +
+

+ Module will add key/value pairs in ad calls. + Check out for captify_segments key in the payload sent to Xandr to endpoint https://ib.adnxs.com/ut/v3/prebid : keywords.key[captify_segments] should have an array of string as value. + This array will have Xandr RTSS segment ids. +

+
+

Basic Prebid.js Example with CaptifyRTD

+
Div-1
+
+ +
+ + + diff --git a/modules/.submodules.json b/modules/.submodules.json index 52bbc638c79..f8c30459e1e 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -57,6 +57,7 @@ "akamaiDapRtdProvider", "blueconicRtdProvider", "browsiRtdProvider", + "captifyRtdProvider", "dgkeywordRtdProvider", "geoedgeRtdProvider", "hadronRtdProvider", diff --git a/modules/captifyRtdProvider.js b/modules/captifyRtdProvider.js new file mode 100644 index 00000000000..b97aa49a48e --- /dev/null +++ b/modules/captifyRtdProvider.js @@ -0,0 +1,146 @@ +/** + * This module adds Captify real time data provider module + * The {@link module:modules/realTimeData} module is required + * The module will fetch segments (page-centric) from Captify live-classification server + * @module modules/captifyRtdProvider + * @requires module:modules/realTimeData + */ +import { submodule } from '../src/hook.js'; +import { getRefererInfo } from '../src/refererDetection.js'; +import { ajax } from '../src/ajax.js'; +import { config } from '../src/config.js'; +import {deepAccess, isArray, isEmptyStr, isNumber, logError} from '../src/utils.js'; +import {getGlobal} from '../src/prebidGlobal.js'; + +const MODULE_NAME = 'realTimeData'; +const SUBMODULE_NAME = 'CaptifyRTDModule'; +const DEFAULT_LC_URL = 'https://live-classification.cpx.to/prebid-segments'; + +const STATUS = { + SUCCESS: 200, + ACCEPTED: 202, +}; + +/** + * Set `appnexusAuctionKeywords` that appnexus bidder will read and send in request to Xandr + * @param {Array} segments captify segments for Appnexus(Xandr) system, in form of [id1, id2, id3] + * where id1, id2, id3 - actual Xandr segment ids with keywords enabled + */ +export function setAppnexusSegments(segments) { + config.setConfig({ + appnexusAuctionKeywords: { + 'captify_segments': segments, + }, + }) +} + +/** + * Function returns only bidders that contained both, in moduleConfig and at least one adUnit. + * @param {Array} bidders Contains list of bidders, to set targeting for + * @param {Object} data Response of live-classification service + */ +export function addSegmentData(bidders, data) { + for (const bidder of bidders) { + if (bidder === 'appnexus') { setAppnexusSegments(data['xandr']) } + } +} + +/** + * Function returns only bidders that contained in both, moduleConfig and at least one adUnit. + * @param {Object} moduleConfig Config object passed to the module + * @param {Object} reqBidsConfigObj Config object for the bidders; each adapter has its own entry + */ +export function getMatchingBidders(moduleConfig, reqBidsConfigObj) { + const biddersFromConf = deepAccess(moduleConfig, 'params.bidders'); + + const adUnitBidders = reqBidsConfigObj.adUnits + .flatMap(({bids}) => bids.map(({bidder}) => bidder)) + .filter((e, i, a) => a.indexOf(e) === i); + + if (!isArray(adUnitBidders) || !adUnitBidders.length) { + logError(SUBMODULE_NAME, 'Missing parameter bidders in bidRequestConfig'); + return []; + } + + return biddersFromConf.filter(bidder => adUnitBidders.includes(bidder)); +} + +/** + * Main function that sets Captify targeting for various bidders + * @param {Object} moduleConfig Config object passed to the module + * @param {Function} onDone callback function that executed when everything is done + * @param {Object} reqBidsConfigObj Config object for the bidders; each adapter has its own entry + * @param {Object} gcv contains data related to user consent, if applies + */ +export function setCaptifyTargeting(reqBidsConfigObj, onDone, moduleConfig, gcv) { + const pbjsVer = getGlobal(); + const ref = getRefererInfo().referer; + const url = document.URL; + const pubId = moduleConfig.params.pubId; + const bidders = getMatchingBidders(moduleConfig, reqBidsConfigObj) + const requestBody = { + pubId, + ref, + url, + pbjsVer, + gcv + }; + let requestUrl = moduleConfig.params.url; + if (!requestUrl || isEmptyStr(requestUrl)) { + requestUrl = DEFAULT_LC_URL; + } + + if (!bidders.length) { + logError(SUBMODULE_NAME, 'There are no matched bidders to work with'); + return; + } + + ajax(requestUrl, { + success: function (response, req) { + if (req.status === STATUS.SUCCESS) { + try { + const data = JSON.parse(response); + if (data) { + addSegmentData(bidders, data); + } + } catch (e) { + logError(SUBMODULE_NAME, 'Unable to parse live-classification data' + e); + } + } + onDone(); + }, + error: function () { + onDone(); + logError(SUBMODULE_NAME, 'Unable to get live-classification data'); + } + }, + JSON.stringify(requestBody), + { + contentType: 'application/json', + method: 'POST', + }); +} + +export function init(moduleConfig, userConsent) { + // Validate bidders + const biddersFromConf = deepAccess(moduleConfig, 'params.bidders'); + if (!isArray(biddersFromConf) || !biddersFromConf.length) { + logError(SUBMODULE_NAME, 'Missing parameter bidders in moduleConfig'); + return false + } + const publisherId = deepAccess(moduleConfig, 'params.pubId'); + // Publisher Id + if (!isNumber(publisherId)) { + logError(SUBMODULE_NAME, 'Missing parameter pubId in moduleConfig'); + return false + } + return true +} + +export const captifySubmodule = { + name: SUBMODULE_NAME, + init: init, + setCaptifyTargeting +}; + +submodule(MODULE_NAME, captifySubmodule); diff --git a/modules/captifyRtdProvider.md b/modules/captifyRtdProvider.md new file mode 100644 index 00000000000..a1a8e9c273f --- /dev/null +++ b/modules/captifyRtdProvider.md @@ -0,0 +1,68 @@ +# Captify Real-Time Data Submodule + +# Overview + + Module Name: Captify Rtd Provider + Module Type: Rtd Provider + Layout: integrationExamples/gpt/captifyRtdProvider_example.html + Maintainer: prebid@captify.tech + +# Description + +Captify uses publisher first-party on-site search data to power machine learning algorithms to create a suite of +contextual based targeting solutions that activate in a cookieless environment. + +The RTD submodule allows bid requests to be classified by our live-classification service on the first ad call, +maximising value for publishers by increasing scale for advertisers. + +Segments will be attached to bid request objects sent to different SSPs in order to optimize targeting. + +Contact prebid@captify.tech for information. + +### Publisher Usage + +Compile the Captify RTD module into your Prebid build: + +`npm ci && gulp build --modules=rtdModule,appnexusBidAdapter,captifyRtdProvider` + +Add the Captify RTD provider to your Prebid config. + +```javascript +pbjs.setConfig({ + realTimeData: { + auctionDelay: 1000, + dataProviders: [ + { + name: "CaptifyRTDModule", + waitForIt: true, + params: { + pubId: 123456, + bidders: ['appnexus'], + } + } + ] + } +}); +``` + +### Parameter Description +This module is configured as part of the `realTimeData.dataProviders` object. + +| Name |Type | Description |Mandatory | Notes | +| :------------- | :------------ | :------------------------------------------------------------------ |:---------|:------------ | +| name | String | Real time data module name | yes | Always 'CaptifyRTDModule' | +| waitForIt | Boolean | Should be `true` if there's an `auctionDelay` defined (recommended) | no | Default `false` | +| params | Object | | | | +| params.pubId | Integer | Partner ID, required to get results and provided by Captify | yes | Use 123456 for tests and speak to your Captify account manager to receive your pubId | +| params.bidders | Array | List of bidders for which you would like data to be set | yes | Currently only 'appnexus' supported | +| params.url | String | Captify live-classification service url | no | Defaults to `https://live-classification.cpx.to/prebid-segments` + +### Testing + +To view an example of available segments returned by Captify: + +`gulp serve --modules=rtdModule,captifyRtdProvider,appnexusBidAdapter` + +and then point your browser at: + +`http://localhost:9999/integrationExamples/gpt/captifyRtdProvider_example.html?pbjs_debug=true` diff --git a/test/spec/modules/captifyRtdProvider_spec.js b/test/spec/modules/captifyRtdProvider_spec.js new file mode 100644 index 00000000000..2e1052e000f --- /dev/null +++ b/test/spec/modules/captifyRtdProvider_spec.js @@ -0,0 +1,253 @@ +import {addSegmentData, captifySubmodule, getMatchingBidders, setCaptifyTargeting} from 'modules/captifyRtdProvider.js'; +import {server} from 'test/mocks/xhr.js'; +import {config} from 'src/config.js'; +import {deepAccess} from '../../../src/utils'; + +const responseHeader = {'Content-Type': 'application/json'}; +const defaultRequestUrl = 'https://live-classification.cpx.to/prebid-segments'; + +describe('captifyRtdProvider', function () { + describe('init function', function () { + it('successfully instantiates, when configured properly', function () { + const config = { + params: { + pubId: 123456, + bidders: ['appnexus'], + } + }; + expect(captifySubmodule.init(config, null)).to.equal(true); + }); + + it('return false on init, when config is invalid', function () { + const config = { + params: {} + }; + expect(captifySubmodule.init(config, null)).to.equal(false); + expect(captifySubmodule.init(null, null)).to.equal(false); + }); + + it('return false on init, when pubId is absent', function () { + const config = { + params: { + bidders: ['appnexus'], + } + }; + expect(captifySubmodule.init(config, null)).to.equal(false); + expect(captifySubmodule.init(null, null)).to.equal(false); + }); + + it('return false on init, when bidders is empty array', function () { + const config = { + params: { + bidders: [], + pubId: 123, + } + }; + expect(captifySubmodule.init(config, null)).to.equal(false); + expect(captifySubmodule.init(null, null)).to.equal(false); + }); + }); + + describe('addSegmentData function', function () { + it('adds segment data', function () { + config.resetConfig(); + + let data = { + xandr: [111111, 222222], + }; + + addSegmentData(['appnexus'], data); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.eql(data['xandr']); + }); + }); + + describe('getMatchingBidders function', function () { + it('returns only bidders that used within adUnits', function () { + const moduleConfig = { + params: { + pubId: 123, + bidders: ['appnexus', 'pubmatic'], + } + }; + let reqBidsConfigObj = { + adUnits: [{ + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13144370 + } + }] + }] + }; + + let matchedBidders = getMatchingBidders(moduleConfig, reqBidsConfigObj); + expect(matchedBidders).to.eql(['appnexus']); + }); + + it('return empty result, when there are no bidders configured for adUnits', function () { + const moduleConfig = { + params: { + pubId: 123, + bidders: ['pubmatic'], + } + }; + let reqBidsConfigObj = { + adUnits: [{ + bids: [] + }] + }; + expect(getMatchingBidders(moduleConfig, reqBidsConfigObj)).to.be.empty; + }); + + it('return empty result, when there are no bidders matched', function () { + const moduleConfig = { + params: { + pubId: 123, + bidders: ['pubmatic'], + } + }; + let reqBidsConfigObj = { + adUnits: [{ + bids: [{ + params: { + bidder: 'appnexus', + placementId: 13144370, + } + }] + }] + }; + expect(getMatchingBidders(moduleConfig, reqBidsConfigObj)).to.be.empty; + }); + + it('return empty result, when there are no adUnits with bidders', function () { + const moduleConfig = { + params: { + pubId: 123, + bidders: ['pubmatic'], + } + }; + let reqBidsConfigObj = { + adUnits: [{ + bids: [{ + params: { + placementId: 13144370, + } + }] + }] + }; + expect(getMatchingBidders(moduleConfig, reqBidsConfigObj)).to.be.empty; + }); + }); + + describe('integration test with mock live-classification response', function () { + const moduleConfig = { + params: { + pubId: 123456, + bidders: ['appnexus'], + } + }; + + const reqBidsConfigObj = { + adUnits: [{ + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13144370 + } + }, { + bidder: 'other' + }] + }] + }; + + const expectedUrlParam = 'http://localhost:9876/context.html'; + + it('gets data from async request and adds segment data', function () { + config.resetConfig(); + let data = {xandr: [111111, 222222]}; + const callbackSpy = sinon.spy(); + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, moduleConfig, {}); + let request = server.requests[0]; + let requestBody = JSON.parse(server.requests[0].requestBody); + expect(request.url).to.be.eq(defaultRequestUrl); + expect(requestBody['pubId']).to.eq(moduleConfig.params.pubId); + expect(requestBody['url']).to.eq(expectedUrlParam); + request.respond(200, responseHeader, JSON.stringify(data)); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.eql(data['xandr']); + expect(callbackSpy.calledOnce).to.be.true; + }); + + it('do not send classification request, if no matching adUnits on page', function () { + config.resetConfig(); + let reqBidsConfigObj = { + adUnits: [{ + bids: [ + {bidder: 'pubmatic'} + ] + }] + }; + const callbackSpy = sinon.spy(); + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, moduleConfig, {}); + expect(server.requests).to.be.empty; + }); + + it('gets data from async request and adds segment data, using URL from config', function () { + config.resetConfig(); + let data = {xandr: [111111, 222222]}; + const callbackSpy = sinon.spy(); + const testUrl = 'http://my-test-server.com/path'; + const conf = { + params: { + url: testUrl, + pubId: 123456, + bidders: ['appnexus'], + } + }; + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, conf, {}); + let request = server.requests[0]; + let requestBody = JSON.parse(server.requests[0].requestBody); + expect(request.url).to.be.eq(testUrl); + expect(requestBody['pubId']).to.eq(conf.params.pubId); + expect(requestBody['url']).to.eq(expectedUrlParam); + request.respond(200, responseHeader, JSON.stringify(data)); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.eql(data['xandr']); + expect(callbackSpy.calledOnce).to.be.true; + }); + + it('do not set anything, in case server responded with 202', function () { + config.resetConfig(); + const callbackSpy = sinon.spy(); + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, moduleConfig, {}); + let request = server.requests[0]; + let requestBody = JSON.parse(server.requests[0].requestBody); + expect(request.url).to.be.eq(defaultRequestUrl); + expect(requestBody['pubId']).to.eq(moduleConfig.params.pubId); + expect(requestBody['url']).to.eq(expectedUrlParam); + request.respond(202, responseHeader, ''); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.be.undefined; + expect(callbackSpy.calledOnce).to.be.true; + }); + + it('do not set anything, in case server responded with error', function () { + config.resetConfig(); + const callbackSpy = sinon.spy(); + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, moduleConfig, {}); + let request = server.requests[0]; + expect(request.url).to.be.eq(defaultRequestUrl); + request.respond(500, null, ''); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.be.undefined; + expect(callbackSpy.calledOnce).to.be.true; + }); + + it('do not set anything, in case request error', function () { + config.resetConfig(); + const callbackSpy = sinon.spy(); + setCaptifyTargeting(reqBidsConfigObj, callbackSpy, moduleConfig, {}); + let request = server.requests[0]; + expect(request.url).to.be.eq(defaultRequestUrl); + request.abort('test error'); + expect(deepAccess(config.getConfig(), 'appnexusAuctionKeywords.captify_segments')).to.be.undefined; + expect(callbackSpy.calledOnce).to.be.true; + }); + }); +}); From e7b2e86412d3f4b709954aa10457557f0c37c743 Mon Sep 17 00:00:00 2001 From: Mikhail Ivanchenko Date: Tue, 15 Nov 2022 15:18:38 +0300 Subject: [PATCH 116/367] nextMillennium Bid Adapter: a new cookiesync URL (#9221) * add video support * Sync URL was changed --- modules/nextMillenniumBidAdapter.js | 42 +++++++++---------- .../modules/nextMillenniumBidAdapter_spec.js | 7 ++-- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/modules/nextMillenniumBidAdapter.js b/modules/nextMillenniumBidAdapter.js index 762c571f1e6..802a8ac25b0 100644 --- a/modules/nextMillenniumBidAdapter.js +++ b/modules/nextMillenniumBidAdapter.js @@ -22,7 +22,7 @@ import { getRefererInfo } from '../src/refererDetection.js'; const BIDDER_CODE = 'nextMillennium'; const ENDPOINT = 'https://pbs.nextmillmedia.com/openrtb2/auction'; const TEST_ENDPOINT = 'https://test.pbs.nextmillmedia.com/openrtb2/auction'; -const SYNC_ENDPOINT = 'https://statics.nextmillmedia.com/load-cookie.html?v=4'; +const SYNC_ENDPOINT = 'https://cookies.nextmillmedia.com/sync?'; const TIME_TO_LIVE = 360; const VIDEO_PARAMS = [ 'api', 'linearity', 'maxduration', 'mimes', 'minduration', 'placement', @@ -198,28 +198,24 @@ export const spec = { }, getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { - if (!syncOptions.iframeEnabled) { - return; - }; - - let syncurl = gdprConsent && gdprConsent.gdprApplies ? `${SYNC_ENDPOINT}&gdpr=1&gdpr_consent=${gdprConsent.consentString}` : SYNC_ENDPOINT; - - let bidders = []; - if (responses) { - _each(responses, (response) => { - if (!(response && response.body && response.body.ext && response.body.ext.responsetimemillis)) return; - _each(Object.keys(response.body.ext.responsetimemillis), b => bidders.push(b)); - }); - }; - - if (bidders.length) { - syncurl += `&bidders=${bidders.join(',')}`; - }; - - return [{ - type: 'iframe', - url: syncurl - }]; + const pixels = []; + let syncUrl = SYNC_ENDPOINT; + + if (gdprConsent && gdprConsent.gdprApplies) { + syncUrl += 'gdpr=1&gdpr_consent=' + gdprConsent.consentString; + } + if (uspConsent) { + syncUrl += 'us_privacy=' + uspConsent; + } + + if (syncOptions.iframeEnabled) { + pixels.push({type: 'iframe', url: syncUrl + 'type=iframe'}); + } + if (syncOptions.pixelEnabled) { + pixels.push({type: 'image', url: syncUrl + 'type=image'}); + } + + return pixels; }, }; diff --git a/test/spec/modules/nextMillenniumBidAdapter_spec.js b/test/spec/modules/nextMillenniumBidAdapter_spec.js index 36920245070..2b5ae801489 100644 --- a/test/spec/modules/nextMillenniumBidAdapter_spec.js +++ b/test/spec/modules/nextMillenniumBidAdapter_spec.js @@ -148,14 +148,15 @@ describe('nextMillenniumBidAdapterTests', function() { it('Test getUserSyncs function', function () { const syncOptions = { - 'iframeEnabled': true + 'iframeEnabled': false, + 'pixelEnabled': true } const userSync = spec.getUserSyncs(syncOptions); 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('iframe'); - expect(userSync[0].url).to.be.equal('https://statics.nextmillmedia.com/load-cookie.html?v=4'); + expect(userSync[0].type).to.be.equal('image'); + expect(userSync[0].url).to.be.equal('https://cookies.nextmillmedia.com/sync?type=image'); }); it('validate_response_params', function() { From cb766ccf4da3a316bc20c0440f1577e1f5f1590a Mon Sep 17 00:00:00 2001 From: ahmadlob <109217988+ahmadlob@users.noreply.github.com> Date: Tue, 15 Nov 2022 15:11:52 +0200 Subject: [PATCH 117/367] Taboola Bid Adapter: unsupport dynamic endpoint (#9237) * create taboola adapter * create taboola adapter md * taboolaBidAdapter.js - small fixes taboolaBidAdapter_spec.js - new UT * taboolaBidAdapter.js - small fixes taboolaBidAdapter_spec.js - new UT * update the md * update the Maintainer email * * update MD page * refactor code for better readability * small fix in UT * * add privacy to the request builder * add relevant Ut * small fixes in UT * * code refactoring + add more accurate way to get page url and referer * add relevant Ut * small fixes in md * * code refactoring + gte user id * add relevant Ut * small fixes * * code refactoring + gte user id * add relevant Ut * small fixes * * update end point url * update UT * Update banner End point structure * small fixes + update epi url * remove the destruction from the bidResponse property * (update the unit tests) remove the destruction from the bidResponse property * fix tests * fix tests - run stubs on each test * rerun because of another adapter flaky test * rerun because of another adapter flaky test * fix cors issue, switch between height, width position * update badv, bcat to be based in the ortb2 to support prebid 7 new protocols + update Ut * retry run circleci * retry run circleci * pull from upstream update md (placement + pub ) * update badv, bcat UT * rerun build * rerun build * support storageAllowed restriction on unit tests for prebid 7 * create taboola adapter * create taboola adapter md * taboolaBidAdapter.js - small fixes taboolaBidAdapter_spec.js - new UT * taboolaBidAdapter.js - small fixes taboolaBidAdapter_spec.js - new UT * update the md * update the Maintainer email * * update MD page * refactor code for better readability * small fix in UT * * add privacy to the request builder * add relevant Ut * small fixes in UT * * code refactoring + add more accurate way to get page url and referer * add relevant Ut * small fixes in md * * code refactoring + gte user id * add relevant Ut * small fixes * * code refactoring + gte user id * add relevant Ut * small fixes * * update end point url * update UT * Update banner End point structure * small fixes + update epi url * remove the destruction from the bidResponse property * (update the unit tests) remove the destruction from the bidResponse property * fix tests * fix tests - run stubs on each test * rerun because of another adapter flaky test * rerun because of another adapter flaky test * fix cors issue, switch between height, width position * update badv, bcat to be based in the ortb2 to support prebid 7 new protocols + update Ut * retry run circleci * retry run circleci * pull from upstream update md (placement + pub ) * update badv, bcat UT * rerun build * rerun build * support storageAllowed restriction on unit tests for prebid 7 * support storageAllowed restriction on unit tests for prebid 7 * add it also to the aftereach * add it also to the aftereach * change the api endpoint https protocol * update Taboola prebid documentation: tagId, publisherId, bidFloor. * update bid response ttl to 60 seconds. * update Taboola prebid documentation. * update-ttl-passing * Update taboolaBidAdapter_spec.js * add fallback default value in case of null * add semicolons * . * . * . * .. * ... * support-dynamic-endpoint-url * support-dynamic-endpoint-url * support-dynamic-endpoint-url * support-dynamic-endpoint-url * support-dynamic-endpoint-url * support-dynamic-endpoint-url * support-dynamic-endpoint-url * optional-chaining * set netRevenue to true. * fix bid response in case we have multiple impressions * add test * fix lint * unsupport-dynamic-endpoint Co-authored-by: Michael Co-authored-by: mikiz <31058500+mikizi@users.noreply.github.com> Co-authored-by: jenny.l Co-authored-by: jennylt <48404417+jennylt@users.noreply.github.com> Co-authored-by: Shakhal Levinson Co-authored-by: shakhaltb <108469576+shakhaltb@users.noreply.github.com> --- modules/taboolaBidAdapter.js | 6 +- modules/taboolaBidAdapter.md | 2 - test/spec/modules/taboolaBidAdapter_spec.js | 77 --------------------- 3 files changed, 3 insertions(+), 82 deletions(-) diff --git a/modules/taboolaBidAdapter.js b/modules/taboolaBidAdapter.js index d4bf6623f9b..9bd42651796 100644 --- a/modules/taboolaBidAdapter.js +++ b/modules/taboolaBidAdapter.js @@ -9,7 +9,7 @@ import {getStorageManager} from '../src/storageManager.js'; const BIDDER_CODE = 'taboola'; const GVLID = 42; const CURRENCY = 'USD'; -export const END_POINT_URL = 'https://hb.bidder.taboola.com/TaboolaHBOpenRTBRequestHandlerServlet'; +export const END_POINT_URL = 'https://display.bidder.taboola.com/OpenRTB/TaboolaHB/auction'; const USER_ID = 'user-id'; const STORAGE_KEY = `taboola global:${USER_ID}`; const COOKIE_KEY = 'trc_cookie_storage'; @@ -80,7 +80,7 @@ export const spec = { buildRequests: (validBidRequests, bidderRequest) => { const [bidRequest] = validBidRequests; const {refererInfo, gdprConsent = {}, uspConsent} = bidderRequest; - const {publisherId, endpointUrl} = bidRequest.params; + const {publisherId} = bidRequest.params; const site = getSiteProperties(bidRequest.params, refererInfo); const device = {ua: navigator.userAgent}; const imps = getImps(validBidRequests); @@ -124,7 +124,7 @@ export const spec = { regs }; - const url = [endpointUrl || END_POINT_URL, publisherId].join('/'); + const url = [END_POINT_URL, publisherId].join('/'); return { url, diff --git a/modules/taboolaBidAdapter.md b/modules/taboolaBidAdapter.md index d63616d23a9..79538d0d48b 100644 --- a/modules/taboolaBidAdapter.md +++ b/modules/taboolaBidAdapter.md @@ -31,7 +31,6 @@ The Taboola Bidding adapter requires setup before beginning. Please contact us o bidfloor: 0.25, // Optional - default is null bcat: ['IAB1-1'], // Optional - default is [] badv: ['example.com'], // Optional - default is [] - endpointUrl: ['https://example.com'] // Optional } }] }]; @@ -46,6 +45,5 @@ The Taboola Bidding adapter requires setup before beginning. Please contact us o | `bcat` | optional | List of blocked advertiser categories (IAB) | `['IAB1-1']` | `Array` | | `badv` | optional | Blocked Advertiser Domains | `'example.com'` | `String Url` | | `bidfloor` | optional | CPM bid floor | `0.25` | `Float` | -| `endpointUrl` | optional | Endpoint Url (only if provided by Taboola) | `https://example.com` | `String` | diff --git a/test/spec/modules/taboolaBidAdapter_spec.js b/test/spec/modules/taboolaBidAdapter_spec.js index 9af11363957..c0b16ac40fc 100644 --- a/test/spec/modules/taboolaBidAdapter_spec.js +++ b/test/spec/modules/taboolaBidAdapter_spec.js @@ -89,45 +89,6 @@ describe('Taboola Adapter', function () { } expect(spec.isBidRequestValid(bid)).to.equal(true) }) - - it('should succeed when url is null', function () { - const bid = { - bidder: 'taboola', - params: { - publisherId: 'publisherId', - tagId: 'below the article', - endpointUrl: null - }, - ...displayBidRequestParams - } - expect(spec.isBidRequestValid(bid)).to.equal(true) - }) - - it('should succeed when url is empty string', function () { - const bid = { - bidder: 'taboola', - params: { - publisherId: 'publisherId', - tagId: 'below the article', - endpointUrl: '' - }, - ...displayBidRequestParams - } - expect(spec.isBidRequestValid(bid)).to.equal(true) - }) - - it('should succeed when url is filled', function () { - const bid = { - bidder: 'taboola', - params: { - publisherId: 'publisherId', - tagId: 'below the article', - endpointUrl: 'https://example.com' - }, - ...displayBidRequestParams - } - expect(spec.isBidRequestValid(bid)).to.equal(true) - }) }) describe('buildRequests', function () { @@ -189,44 +150,6 @@ describe('Taboola Adapter', function () { expect(res.data).to.deep.equal(JSON.stringify(expectedData)); }); - it('should fill the url when it is passed', function () { - const commonBidRequestWithUrl = { - bidder: 'taboola', - params: { - publisherId: 'publisherId', - tagId: 'placement name', - endpointUrl: 'https://example.com' - }, - bidId: 'aa43860a-4644-442a-b5e0-93f268cs4d19', - auctionId: '65746dca-26f3-4186-be13-dfa63469b1b7', - } - let defaultBidRequestWithUrl = { - ...commonBidRequestWithUrl, - ...displayBidRequestParams, - } - const res = spec.buildRequests([defaultBidRequestWithUrl], commonBidderRequest); - expect(res.url).to.equal(`${commonBidRequestWithUrl.params.endpointUrl}/${commonBidRequest.params.publisherId}`); - }) - - it('should fill default url when url param is empty string', function () { - const commonBidRequestWithUrl = { - bidder: 'taboola', - params: { - publisherId: 'publisherId', - tagId: 'placement name', - endpointUrl: '' - }, - bidId: 'aa43860a-4644-442a-b5e0-93f268cs4d19', - auctionId: '65746dca-26f3-4186-be13-dfa63469b1b7', - } - let defaultBidRequestWithUrl = { - ...commonBidRequestWithUrl, - ...displayBidRequestParams, - } - const res = spec.buildRequests([defaultBidRequestWithUrl], commonBidderRequest); - expect(res.url).to.equal(`${END_POINT_URL}/${commonBidRequestWithUrl.params.publisherId}`); - }) - it('should pass optional parameters in request', function () { const optionalParams = { bidfloor: 0.25, From e717dcdfdead403d1c0369259c63480cd3b85b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Sok=C3=B3=C5=82?= <88041828+smart-adserver@users.noreply.github.com> Date: Tue, 15 Nov 2022 14:42:50 +0100 Subject: [PATCH 118/367] Smartadserver Bid Adapter: discard bid response if ad and adUrl empty (#9213) * Discard bid response if ad and adUrl empty * Restore removeAll in U.T. * Restore one more removeAll --- modules/smartadserverBidAdapter.js | 2 +- .../modules/smartadserverBidAdapter_spec.js | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/modules/smartadserverBidAdapter.js b/modules/smartadserverBidAdapter.js index 5d64cad27b5..b1a69407df4 100644 --- a/modules/smartadserverBidAdapter.js +++ b/modules/smartadserverBidAdapter.js @@ -209,7 +209,7 @@ export const spec = { const bidResponses = []; let response = serverResponse.body; try { - if (response && !response.isNoAd) { + if (response && !response.isNoAd && (response.ad || response.adUrl)) { const bidRequest = JSON.parse(bidRequestString.data); let bidResponse = { diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js index 727a7d7c1d6..18308481e1a 100644 --- a/test/spec/modules/smartadserverBidAdapter_spec.js +++ b/test/spec/modules/smartadserverBidAdapter_spec.js @@ -200,6 +200,27 @@ describe('Smart bid adapter tests', function () { }).to.not.throw(); }); + it('Should not nest response if ad and adUrl empty', () => { + const BID_RESPONSE_EMPTY = { + body: { + ad: null, + adUrl: null, + cpm: 0.92, + isNoAd: false + } + }; + + const request = spec.buildRequests(DEFAULT_PARAMS); + const bids = spec.interpretResponse(BID_RESPONSE_EMPTY, request[0]); + + expect(bids).to.have.lengthOf(0); + expect(() => { + spec.interpretResponse(BID_RESPONSE_EMPTY, { + data: 'invalid Json' + }); + }).to.not.throw(); + }); + it('Verify parse response', function () { const request = spec.buildRequests(DEFAULT_PARAMS); const bids = spec.interpretResponse(BID_RESPONSE, request[0]); From 39958eab94b751377ebd2dfdff5a98bb9f0b0c97 Mon Sep 17 00:00:00 2001 From: pm-azhar-mulla <75726247+pm-azhar-mulla@users.noreply.github.com> Date: Tue, 15 Nov 2022 19:39:59 +0530 Subject: [PATCH 119/367] updated the correct variable while setting cookie (#9234) Co-authored-by: pm-azhar-mulla --- modules/userId/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/userId/index.js b/modules/userId/index.js index 8fdd4319dfc..fe47ac5c16d 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -240,7 +240,7 @@ export function setStoredValue(submodule, value) { const valueStr = isPlainObject(value) ? JSON.stringify(value) : value; if (storage.type === COOKIE) { const setCookie = cookieSetter(submodule); - setCookie(null, value, expiresStr); + setCookie(null, valueStr, expiresStr); if (typeof storage.refreshInSeconds === 'number') { setCookie('_last', new Date().toUTCString(), expiresStr); } From 4e6904202a00be39c67845c74b55c113f688adef Mon Sep 17 00:00:00 2001 From: Gino <53079123+Skylinar@users.noreply.github.com> Date: Tue, 15 Nov 2022 16:34:20 +0100 Subject: [PATCH 120/367] Smartx Bid Adapter: Add Schain support (#9244) * Add smartclipBidAdapter * smartxBidAdapter.js - removed unused variables, removed debug, added window before the outstream related functions * - made outstream player configurable * remove wrong named files * camelcase * fix * Out-Stream render update to SmartPlay 5.2 * ESlint fix * ESlint fix * ESlint fix * adjust tests, fixes * ESlint * adjusted desired bitrate examples * added bid.meta.advertiserDomains support * bug fix for numeric elementID outstream render * fix renderer url * support for floors module * bugfixes to be openRTB 2.5 compliant * update internal renderer usage * remove unused outstream_function logic * bugfix outstream options for default outstream renderer configuration * [PREB-10] fix empty title not configurable * add pbjs version * testing with outstream 5.3.0 * pbjs version into content.ext * made visibilityThreshold configurable * adjust position of pbjs version * Merge branch 'master' of https://github.com/prebid/Prebid.js into HEAD * update smartclip outstream player version to support outstream 6 release along with necessary config changes * Add support for schain * vacuuming Co-authored-by: smartclip AdTechnology Co-authored-by: Gino Cirlini Co-authored-by: smartclip-adtech <65160328+smartclip-adtech@users.noreply.github.com> --- modules/smartxBidAdapter.js | 17 +++++++----- test/spec/modules/smartxBidAdapter_spec.js | 32 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/modules/smartxBidAdapter.js b/modules/smartxBidAdapter.js index e5f71265e34..f8438a35000 100644 --- a/modules/smartxBidAdapter.js +++ b/modules/smartxBidAdapter.js @@ -67,7 +67,6 @@ export const spec = { * @return ServerRequest Info describing the request to the server. */ buildRequests: function (bidRequests, bidderRequest) { - // TODO: does the fallback make sense here? const page = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; const isPageSecure = !!page.match(/^https:/) @@ -197,6 +196,15 @@ export const spec = { userExt.fpc = pubcid; } + // Add schain object if available + if (bid && bid.schain) { + requestPayload['source'] = { + ext: { + schain: bid.schain + } + }; + } + // Only add the user object if it's not empty if (!isEmpty(userExt)) { requestPayload.user = { @@ -204,9 +212,7 @@ export const spec = { }; } - // requestPayload.user.ext.ver = pbjs.version; - - // Targeting + // Add targeting if (getBidIdParameter('data', bid.params.user)) { var targetingarr = []; for (var i = 0; i < bid.params.user.data.length; i++) { @@ -225,8 +231,6 @@ export const spec = { } } - // Todo: USER ID MODULE - requestPayload.user = { ext: userExt, data: targetingarr @@ -269,7 +273,6 @@ export const spec = { } /** * Make sure currency and price are the right ones - * TODO: what about the pre_market_bid partners sizes? */ _each(currentBidRequest.params.pre_market_bids, function (pmb) { if (pmb.deal_id == smartxBid.id) { diff --git a/test/spec/modules/smartxBidAdapter_spec.js b/test/spec/modules/smartxBidAdapter_spec.js index 58ce50efb8e..5bd08064c79 100644 --- a/test/spec/modules/smartxBidAdapter_spec.js +++ b/test/spec/modules/smartxBidAdapter_spec.js @@ -342,6 +342,38 @@ describe('The smartx adapter', function () { expect(request.data.imp[0].video.minduration).to.equal(3); expect(request.data.imp[0].video.maxduration).to.equal(15); }); + + it('should pass schain param', function () { + var request; + + bid.schain = { + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + hp: 1 + } + ] + } + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.source).to.deep.equal({ + ext: { + schain: { + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + hp: 1 + } + ] + } + } + }) + }); }); describe('interpretResponse', function () { From ba3d37159214dc9915ba7e6c28b27033d6e27eb6 Mon Sep 17 00:00:00 2001 From: mmoschovas <63253416+mmoschovas@users.noreply.github.com> Date: Tue, 15 Nov 2022 16:12:47 -0500 Subject: [PATCH 121/367] Fix to merge site fpd into payload as opposed to overwriting (#9247) --- modules/ttdBidAdapter.js | 7 ++++--- test/spec/modules/ttdBidAdapter_spec.js | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/modules/ttdBidAdapter.js b/modules/ttdBidAdapter.js index a855c07dc86..56dc44827b7 100644 --- a/modules/ttdBidAdapter.js +++ b/modules/ttdBidAdapter.js @@ -132,14 +132,15 @@ function getUser(bidderRequest) { } function getSite(bidderRequest, firstPartyData) { - var site = { + var site = utils.mergeDeep({ page: utils.deepAccess(bidderRequest, 'refererInfo.page'), ref: utils.deepAccess(bidderRequest, 'refererInfo.ref'), publisher: { id: utils.deepAccess(bidderRequest, 'bids.0.params.publisherId'), }, - ...firstPartyData.site - }; + }, + firstPartyData.site + ); var publisherDomain = bidderRequest.refererInfo.domain; if (publisherDomain) { diff --git a/test/spec/modules/ttdBidAdapter_spec.js b/test/spec/modules/ttdBidAdapter_spec.js index 60c00f4e4b9..346f1ef88f6 100644 --- a/test/spec/modules/ttdBidAdapter_spec.js +++ b/test/spec/modules/ttdBidAdapter_spec.js @@ -310,6 +310,19 @@ describe('ttdBidAdapter', function () { expect(requestBody.imp[0].banner.expdir).to.equal(expdir); }); + it('merges first party site data', function () { + const ortb2 = { + site: { + publisher: { + domain: 'https://foo.bar', + } + } + }; + const requestBody = testBuildRequests(baseBannerBidRequests, {...baseBidderRequest, ortb2}).data; + config.resetConfig(); + expect(requestBody.site.publisher).to.deep.equal({domain: 'https://foo.bar', id: '13144370'}); + }); + it('sets keywords properly if sent', function () { const ortb2 = { site: { From 625d2755d23187a92af0a5e7b5afe16f0c30a9d3 Mon Sep 17 00:00:00 2001 From: BaronJHYu <254878848@qq.com> Date: Wed, 16 Nov 2022 21:00:33 +0800 Subject: [PATCH 122/367] Discovery Bid Adapter : parameter updates (#9249) * Mediago Bid Adapter:new adapter * remove console * change spec file to fix CircleCI * change spec file to fix CircleCI * change spec file * Update mediagoBidAdapter.js * Update mediagoBidAdapter.js * rerun CurcleCi * update mediagoBidAdapter * update discoveryBidAdapter Co-authored-by: BaronYu --- modules/discoveryBidAdapter.js | 55 +++++++++++++------ modules/discoveryBidAdapter.md | 13 +++-- test/spec/modules/discoveryBidAdapter_spec.js | 17 +++--- 3 files changed, 54 insertions(+), 31 deletions(-) diff --git a/modules/discoveryBidAdapter.js b/modules/discoveryBidAdapter.js index 4f22a41cf9f..fab3920efcc 100644 --- a/modules/discoveryBidAdapter.js +++ b/modules/discoveryBidAdapter.js @@ -12,7 +12,8 @@ let itemMaps = {}; const MEDIATYPE = [BANNER, NATIVE]; /* ----- _ss_pp_id:start ------ */ -const COOKIE_KEY_MGUID = '_ss_pp_id'; +const COOKIE_KEY_SSPPID = '_ss_pp_id'; +const COOKIE_KEY_MGUID = '__mguid_'; const NATIVERET = { id: 'id', @@ -58,14 +59,20 @@ const NATIVERET = { * @return {string} */ const getUserID = () => { - const i = storage.getCookie(COOKIE_KEY_MGUID); + let idd = storage.getCookie(COOKIE_KEY_SSPPID); + let idm = storage.getCookie(COOKIE_KEY_MGUID); - if (i === null) { + if (idd && !idm) { + idm = idd + } else if (idm && !idd) { + idd = idm + } else if (!idd && !idm) { const uuid = utils.generateUUID(); storage.setCookie(COOKIE_KEY_MGUID, uuid); + storage.setCookie(COOKIE_KEY_SSPPID, uuid); return uuid; } - return i; + return idd; }; /* ----- _ss_pp_id:end ------ */ @@ -80,7 +87,6 @@ function getKv(obj, ...keys) { let o = obj; for (let key of keys) { - // console.log(key, o); if (o && o[key]) { o = o[key]; } else { @@ -222,7 +228,7 @@ function getItems(validBidRequests, bidderRequest) { let id = '' + (i + 1); if (mediaTypes.native) { - ret = {...NATIVERET, ...{id, bidFloor}} + ret = { ...NATIVERET, ...{ id, bidFloor } } } // banner if (mediaTypes.banner) { @@ -249,6 +255,7 @@ function getItems(validBidRequests, bidderRequest) { pos: 1, }, ext: {}, + tagid: globals['tagid'], }; } itemMaps[id] = { @@ -273,14 +280,19 @@ function getParam(validBidRequests, bidderRequest) { let auctionId = getKv(bidderRequest, 'auctionId'); let items = getItems(validBidRequests, bidderRequest); - const location = utils.deepAccess(bidderRequest, 'refererInfo.referer'); - const timeout = bidderRequest.timeout || 2000; + const domain = utils.deepAccess(bidderRequest, 'refererInfo.domain') || document.domain; + const location = utils.deepAccess(bidderRequest, 'refererInfo.referer'); + const page = utils.deepAccess(bidderRequest, 'refererInfo.page'); + const referer = utils.deepAccess(bidderRequest, 'refererInfo.ref'); + if (items && items.length) { let c = { id: 'pp_hbjs_' + auctionId, at: 1, + bcat: globals['bcat'], + badv: globals['adv'], cur: ['USD'], device: { connectiontype: 0, @@ -295,16 +307,16 @@ function getParam(validBidRequests, bidderRequest) { }, tmax: timeout, site: { - name: globals['media'], - domain: globals['media'], - page: location, - ref: location, + name: domain, + domain: domain, + page: page || location, + ref: referer, mobile: isMobile, cat: [], // todo publisher: { + id: globals['publisher'] // todo - id: globals['media'], - name: globals['media'], + // name: xxx }, }, imp: items, @@ -329,10 +341,19 @@ export const spec = { if (bid.params.token) { globals['token'] = bid.params.token; } - if (bid.params.media) { - globals['media'] = bid.params.media; + if (bid.params.publisher) { + globals['publisher'] = bid.params.publisher; + } + if (bid.params.tagid) { + globals['tagid'] = bid.params.tagid; + } + if (bid.params.bcat) { + globals['bcat'] = Array.isArray(bid.params.bcat) ? bid.params.bcat : []; + } + if (bid.params.badv) { + globals['badv'] = Array.isArray(bid.params.badv) ? bid.params.badv : []; } - return !!(bid.params.token && bid.params.media); + return !!(bid.params.token && bid.params.publisher && bid.params.tagid); }, /** diff --git a/modules/discoveryBidAdapter.md b/modules/discoveryBidAdapter.md index 6e7197863a5..e951b0b7448 100644 --- a/modules/discoveryBidAdapter.md +++ b/modules/discoveryBidAdapter.md @@ -1,15 +1,15 @@ # Overview ``` -Module Name: DiscoveryDSP Bid Adapter +Module Name: discovery Bid Adapter Module Type: Bidder Adapter ``` # Description -Module that connects to popIn's demand sources +Module that connects to popIn's demand sources. -The DiscoveryDSP Bidding adapter requires setup before beginning. Please contact us at +The discovery Bidding adapter requires setup before beginning. Please contact us at # Test Parameters ``` @@ -32,7 +32,8 @@ The DiscoveryDSP Bidding adapter requires setup before beginning. Please contact bidder: "discovery", params: { token: "a1b067897e4ae093d1f94261e0ddc6c9", - media: 'test_media' // your media host + tagid: 'test_tagid', + publisher: 'test_publisher' }, }, ], @@ -45,13 +46,13 @@ The DiscoveryDSP Bidding adapter requires setup before beginning. Please contact sizes: [[300, 250]], }, }, - // Replace this object to test a new adapter! bids: [ { bidder: "discovery", params: { token: "d0f4902b616cc5c38cbe0a08676d0ed9", - media: 'test_media' // your media host + tagid: 'test_tagid', + publisher: 'test_publisher' }, }, ], diff --git a/test/spec/modules/discoveryBidAdapter_spec.js b/test/spec/modules/discoveryBidAdapter_spec.js index a30afd96ad1..078add73046 100644 --- a/test/spec/modules/discoveryBidAdapter_spec.js +++ b/test/spec/modules/discoveryBidAdapter_spec.js @@ -1,14 +1,14 @@ import { expect } from 'chai'; import { spec } from 'modules/discoveryBidAdapter.js'; -describe('DiscoveryDSP:BidAdapterTests', function () { +describe('discovery:BidAdapterTests', function () { let bidRequestData = { - bidderCode: 'DiscoveryDSP', + bidderCode: 'discovery', auctionId: 'ff66e39e-4075-4d18-9854-56fde9b879ac', bidderRequestId: '4fec04e87ad785', bids: [ { - bidder: 'DiscoveryDSP', + bidder: 'discovery', params: { token: 'd0f4902b616cc5c38cbe0a08676d0ed9', }, @@ -32,25 +32,26 @@ describe('DiscoveryDSP:BidAdapterTests', function () { }; let request = []; - it('DiscoveryDSP:validate_pub_params', function () { + it('discovery:validate_pub_params', function () { expect( spec.isBidRequestValid({ - bidder: 'DiscoveryDSP', + bidder: 'discovery', params: { token: ['d0f4902b616cc5c38cbe0a08676d0ed9'], - media: ['test_media'] + tagid: ['test_tagid'], + publisher: ['test_publisher'] }, }) ).to.equal(true); }); - it('DiscoveryDSP:validate_generated_params', function () { + it('discovery:validate_generated_params', function () { request = spec.buildRequests(bidRequestData.bids, bidRequestData); let req_data = JSON.parse(request.data); expect(req_data.imp).to.have.lengthOf(1); }); - it('DiscoveryDSP:validate_response_params', function () { + it('discovery:validate_response_params', function () { let tempAdm = '' tempAdm += '%3Cscr'; tempAdm += 'ipt%3E'; From e7b981d51636bef2a56237ccb36d79913432bccc Mon Sep 17 00:00:00 2001 From: mcourouble <117740024+mcourouble@users.noreply.github.com> Date: Wed, 16 Nov 2022 14:10:27 +0100 Subject: [PATCH 123/367] Smartadserver Bid Adapter: add support for SDA user and site (#9231) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Smartadserver Bid Adapter: Add support for SDA user and site * Smartadserver Bid Adapter: Fix SDA support getConfig and add to unit testing Co-authored-by: Krzysztof Sokół <88041828+smart-adserver@users.noreply.github.com> --- modules/smartadserverBidAdapter.js | 6 +- .../modules/smartadserverBidAdapter_spec.js | 59 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/modules/smartadserverBidAdapter.js b/modules/smartadserverBidAdapter.js index b1a69407df4..6ff0e592542 100644 --- a/modules/smartadserverBidAdapter.js +++ b/modules/smartadserverBidAdapter.js @@ -133,6 +133,8 @@ export const spec = { // use bidderRequest.bids[] to get bidder-dependent request info const adServerCurrency = config.getConfig('currency.adServerCurrency'); + const sellerDefinedAudience = deepAccess(bidderRequest, 'ortb2.user.data', config.getAnyConfig('ortb2.user.data')); + const sellerDefinedContext = deepAccess(bidderRequest, 'ortb2.site.content.data', config.getAnyConfig('ortb2.site.content.data')); // pull requested transaction ID from bidderRequest.bids[].transactionId return validBidRequests.reduce((bidRequests, bid) => { @@ -154,7 +156,9 @@ export const spec = { timeout: config.getConfig('bidderTimeout'), bidId: bid.bidId, prebidVersion: '$prebid.version$', - schain: spec.serializeSupplyChain(bid.schain) + schain: spec.serializeSupplyChain(bid.schain), + sda: sellerDefinedAudience, + sdc: sellerDefinedContext }; if (bidderRequest && bidderRequest.gdprConsent) { diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js index 18308481e1a..db61983c9c9 100644 --- a/test/spec/modules/smartadserverBidAdapter_spec.js +++ b/test/spec/modules/smartadserverBidAdapter_spec.js @@ -158,12 +158,44 @@ describe('Smart bid adapter tests', function () { } }; + var sellerDefinedAudience = [ + { + 'name': 'hearst.com', + 'ext': { 'segtax': 1 }, + 'segment': [ + { 'id': '1001' }, + { 'id': '1002' } + ] + } + ]; + + var sellerDefinedContext = [ + { + 'name': 'cnn.com', + 'ext': { 'segtax': 2 }, + 'segment': [ + { 'id': '2002' } + ] + } + ]; + it('Verify build request', function () { config.setConfig({ 'currency': { 'adServerCurrency': 'EUR' + }, + ortb2: { + 'user': { + 'data': sellerDefinedAudience + }, + 'site': { + 'content': { + 'data': sellerDefinedContext + } + } } }); + const request = spec.buildRequests(DEFAULT_PARAMS); 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'); @@ -186,6 +218,8 @@ describe('Smart bid adapter tests', function () { expect(requestContent).to.have.property('buid').and.to.equal('7569'); expect(requestContent).to.have.property('appname').and.to.equal('Mozilla'); expect(requestContent).to.have.property('ckid').and.to.equal(42); + expect(requestContent).to.have.property('sda').and.to.deep.equal(sellerDefinedAudience); + expect(requestContent).to.have.property('sdc').and.to.deep.equal(sellerDefinedContext); }); it('Verify parse response with no ad', function () { @@ -358,6 +392,7 @@ describe('Smart bid adapter tests', function () { describe('gdpr tests', function () { afterEach(function () { + config.setConfig({ ortb2: undefined }); config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); }); @@ -489,6 +524,16 @@ describe('Smart bid adapter tests', function () { config.setConfig({ 'currency': { 'adServerCurrency': 'EUR' + }, + ortb2: { + 'user': { + 'data': sellerDefinedAudience + }, + 'site': { + 'content': { + 'data': sellerDefinedContext + } + } } }); const request = spec.buildRequests(INSTREAM_DEFAULT_PARAMS); @@ -507,6 +552,8 @@ describe('Smart bid adapter tests', function () { expect(requestContent).to.have.property('buid').and.to.equal('7569'); expect(requestContent).to.have.property('appname').and.to.equal('Mozilla'); expect(requestContent).to.have.property('ckid').and.to.equal(42); + expect(requestContent).to.have.property('sda').and.to.deep.equal(sellerDefinedAudience); + expect(requestContent).to.have.property('sdc').and.to.deep.equal(sellerDefinedContext); expect(requestContent).to.have.property('isVideo').and.to.equal(true); expect(requestContent).to.have.property('videoData'); expect(requestContent.videoData).to.have.property('videoProtocol').and.to.equal(6); @@ -748,6 +795,16 @@ describe('Smart bid adapter tests', function () { config.setConfig({ 'currency': { 'adServerCurrency': 'EUR' + }, + ortb2: { + 'user': { + 'data': sellerDefinedAudience + }, + 'site': { + 'content': { + 'data': sellerDefinedContext + } + } } }); const request = spec.buildRequests(OUTSTREAM_DEFAULT_PARAMS); @@ -766,6 +823,8 @@ describe('Smart bid adapter tests', function () { expect(requestContent).to.have.property('buid').and.to.equal('7579'); expect(requestContent).to.have.property('appname').and.to.equal('Mozilla'); expect(requestContent).to.have.property('ckid').and.to.equal(43); + expect(requestContent).to.have.property('sda').and.to.deep.equal(sellerDefinedAudience); + expect(requestContent).to.have.property('sdc').and.to.deep.equal(sellerDefinedContext); expect(requestContent).to.have.property('isVideo').and.to.equal(false); expect(requestContent).to.have.property('videoData'); expect(requestContent.videoData).to.have.property('videoProtocol').and.to.equal(7); From f5e6c61404c93b1a055c81071bebaf277b15e4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udi=20Talias=20=E2=9A=9B=EF=B8=8F?= Date: Wed, 16 Nov 2022 18:13:38 +0200 Subject: [PATCH 124/367] VidazooBidAdapter: get bid floor using `bid.getFloor` (#9238) * feat(module): multi size request * fix getUserSyncs added tests * update(module): package-lock.json from master * feat(module): VidazooBidAdapter - send top query params to server * added bid.getFloor handler Co-authored-by: roman Co-authored-by: Saar Amrani <89377180+saar120@users.noreply.github.com> Co-authored-by: Saar Amrani --- modules/vidazooBidAdapter.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index fa44bde74f1..ac74dd18405 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -1,4 +1,4 @@ -import {_each, deepAccess, parseSizesInput, parseUrl, uniques} from '../src/utils.js'; +import { _each, deepAccess, parseSizesInput, parseUrl, uniques, isFn } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { getStorageManager } from '../src/storageManager.js'; @@ -59,7 +59,8 @@ function isBidRequestValid(bid) { function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { const { params, bidId, userId, adUnitCode, schain } = bid; - const { bidFloor, ext } = params; + const { ext } = params; + let { bidFloor } = params; const hashUrl = hashCode(topWindowUrl); const dealId = getNextDealId(hashUrl); const uniqueDealId = getUniqueDealId(hashUrl); @@ -69,6 +70,18 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { const subDomain = extractSubDomain(params); const ptrace = getCacheOpt(); + if (isFn(bid.getFloor)) { + const floorInfo = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*' + }); + + if (floorInfo.currency === 'USD') { + bidFloor = floorInfo.floor; + } + } + let data = { url: encodeURIComponent(topWindowUrl), uqs: getTopWindowQueryParams(), From c3f789bb64a2d298b80b747ced74feea4cd0ba57 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Thu, 17 Nov 2022 00:55:05 +0300 Subject: [PATCH 125/367] Viqeo Bid Adapter: initial adapter release (#8920) * add viqeo prebid adapter * added bid params to docs * updated to Outstream * updated to Outstream (tests) --- modules/viqeoBidAdapter.js | 180 ++++++++++++++++++++++ modules/viqeoBidAdapter.md | 56 +++++++ test/spec/modules/viqeoBidAdapter_spec.js | 124 +++++++++++++++ 3 files changed, 360 insertions(+) create mode 100644 modules/viqeoBidAdapter.js create mode 100644 modules/viqeoBidAdapter.md create mode 100644 test/spec/modules/viqeoBidAdapter_spec.js diff --git a/modules/viqeoBidAdapter.js b/modules/viqeoBidAdapter.js new file mode 100644 index 00000000000..5762a794c8e --- /dev/null +++ b/modules/viqeoBidAdapter.js @@ -0,0 +1,180 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {logError, logInfo, _each, mergeDeep, isFn, isNumber, isPlainObject} from '../src/utils.js' +import {VIDEO} from '../src/mediaTypes.js'; +import {Renderer} from '../src/Renderer.js'; + +const BIDDER_CODE = 'viqeo'; +const DEFAULT_MIMES = ['application/javascript']; +const VIQEO_ENDPOINT = 'https://ads.betweendigital.com/openrtb_bid'; +const RENDERER_URL = 'https://cdn.viqeo.tv/js/vq_starter.js'; +const DEFAULT_CURRENCY = 'USD'; +const DEFAULT_SSPID = 44697; + +function getBidFloor(bid) { + const {floor, currency} = bid.params; + const curr = currency || DEFAULT_CURRENCY; + if (!isFn(bid.getFloor)) { + return {floor: isNumber(floor) ? floor : 0, currency: curr}; + } + const floorInfo = bid.getFloor({currency: curr, mediaType: VIDEO, size: '*'}); + if (isPlainObject(floorInfo) && isNumber(floorInfo.floor) && floorInfo.currency === curr) { + return floorInfo; + } + return {floor: floor || 0, currency: currency || DEFAULT_CURRENCY}; +} + +function getVideoTargetingParams({mediaTypes: {video}}) { + const result = {}; + Object.keys(Object(video)) + .forEach(key => { + if (key === 'playerSize') { + result.w = video.playerSize[0][0]; + result.h = video.playerSize[0][1]; + } else if (key !== 'context') { + result[key] = video[key]; + } + }) + return result; +} + +/** + * @type {BidderSpec} + */ +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [VIDEO], + /** + * @param {BidRequest} bidRequest The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: ({params}) => { + if (!params) { + logError('failed validation: params not declared'); + return false; + } + if (!params.user && !params.user?.buyeruid) { + logError('failed validation: user.buyeruid not declared'); + return false; + } + if (!params.playerOptions) { + logError('failed validation: playerOptions not declared'); + return false; + } + const {profileId, videoId, playerId} = params.playerOptions; + if (!profileId) { + logError('failed validation: profileId not declared'); + return false; + } + if (!videoId && !playerId) { + logError('failed validation: videoId or playerId not declared'); + return false; + } + return true; + }, + /** + * @param validBidRequests {BidRequest[]} + * @returns {ServerRequest[]} + */ + buildRequests: (validBidRequests) => { + logInfo('validBidRequests', validBidRequests); + const bidRequests = []; + _each(validBidRequests, (bid, i) => { + const { + params: {test, sspId, endpointUrl}, + mediaTypes: {video}, + } = bid; + const ortb2 = bid.ortb2 || {}; + const user = bid.params.user || {}; + const device = bid.params.device || {}; + const site = bid.params.site || {}; + const w = window; + const floorInfo = getBidFloor(bid); + const data = { + id: bid.bidId, + test, + imp: [{ + id: `${i}`, + tagid: bid.adUnitCode, + video: { + ...getVideoTargetingParams(bid), + mimes: video.mimes || DEFAULT_MIMES, + }, + bidfloor: floorInfo.floor, + bidfloorcur: floorInfo.currency, + secure: 1 + }], + site: test === 1 ? { + page: 'https://viqeo.tv', + domain: 'viqeo.tv' + } : mergeDeep({ + domain: w.location.hostname, + page: w.location.href + }, ortb2.site, site), + device: mergeDeep({ + w: w.screen.width, + h: w.screen.height, + ua: w.navigator.userAgent, + }, ortb2.device, device), + user: mergeDeep({...user}, ortb2.user), + app: bid.params.app, + }; + bidRequests.push({ + url: endpointUrl || `${VIQEO_ENDPOINT}/?sspId=${sspId || DEFAULT_SSPID}`, + method: 'POST', + data, + bids: validBidRequests, + }); + }); + return bidRequests; + }, + /** + * @param {ServerResponse} serverResponse + * @param {BidRequest} bidRequests + * @return {Bid[]} + */ + interpretResponse: (serverResponse, bidRequests) => { + logInfo('serverResponse', serverResponse); + const bidResponses = []; + if (!serverResponse || !serverResponse.body) { + logError('empty response'); + return []; + } + try { + const {id, seatbid, cur} = serverResponse.body; + _each(seatbid, (sb) => { + const {bid} = sb; + _each(bid, (b) => { + const bidRequest = bidRequests.bids.find(({bidId}) => bidId === id); + const renderer = Renderer.install({ + url: bidRequest?.params?.renderUrl || RENDERER_URL, + }); + renderer.setRender((bid) => { + if (window.VIQEO) { + window.VIQEO.renderPrebid(bid); + } else { + logError('failed get window.VIQEO'); + } + }); + bidResponses.push({ + requestId: id, + currency: cur, + cpm: b.price, + ttl: b.exp, + netRevenue: true, + creativeId: b.cid, + width: b.w || bidRequest?.mediaTypes[VIDEO].playerSize[0][0], + height: b.h || bidRequest?.mediaTypes[VIDEO].playerSize[0][1], + vastXml: b.adm, + vastUrl: b.nurl, + mediaType: VIDEO, + renderer, + }) + }) + }); + } catch (error) { + logError(error); + } + return bidResponses; + }, +} +registerBidder(spec); diff --git a/modules/viqeoBidAdapter.md b/modules/viqeoBidAdapter.md new file mode 100644 index 00000000000..b4a020bf057 --- /dev/null +++ b/modules/viqeoBidAdapter.md @@ -0,0 +1,56 @@ +# Overview + +**Module Name**: Viqeo Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: muravjovv1@gmail.com + +# Description + +Viqeo Bidder Adapter for Prebid.js. About: https://viqeo.tv/ + +### Bid params + +{: .table .table-bordered .table-striped } +| Name | Scope | Description | Example | Type | +|-----------------------------|----------|----------------------------------------------------------------------------------------------------------------------------|--------------------------|-----------| +| `user` | required | The object containing user data (See OpenRTB spec) | `user: {}` | `object` | +| `user.buyeruid` | required | User id | `"12345"` | `string` | +| `playerOptions` | required | The object containing Viqeo player options | `playerOptions: {}` | `object` | +| `playerOptions.profileId` | required | Viqeo profile id | `1382` | `number` | +| `playerOptions.videId` | optional | Viqeo video id | `"ed584da454c7205ca7e4"` | `string` | +| `playerOptions.playerId` | optional | Viqeo player id | `1` | `number` | +| `device` | optional | The object containing device data (See OpenRTB spec) | `device: {}` | `object` | +| `site` | optional | The object containing site data (See OpenRTB spec) | `site: {}` | `object` | +| `app` | optional | The object containing app data (See OpenRTB spec) | `app: {}` | `object` | +| `floor` | optional | Bid floor price | `0.5` | `number` | +| `currency` | optional | 3-letter ISO 4217 code defining the currency of the bid. | `EUR` | `string` | +| `test` | optional | Flag which will induce a sample bid response when true; only set to true for testing purposes (1 = true, 0 = false) | `1` | `integer` | +| `sspId` | optional | For debug, request id | `1` | `number` | +| `renderUrl` | optional | For debug, script player url | `"https://viqeo.tv"` | `string` | +| `endpointUrl` | optional | For debug, api endpoint | `"https://viqeo.tv"` | `string` | + +# Test Parameters +``` + var adUnits = [{ + code: 'your-slot', // use exactly the same code as your slot div id. + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480] + } + }, + bids: [{ + bidder: 'viqeo', + params: { + user: { + buyeruid: '1', + }, + playerOptions: { + videoId: 'ed584da454c7205ca7e4', + profileId: 1382, + }, + test: 1, + } + }] + }]; +``` diff --git a/test/spec/modules/viqeoBidAdapter_spec.js b/test/spec/modules/viqeoBidAdapter_spec.js new file mode 100644 index 00000000000..8f597318af9 --- /dev/null +++ b/test/spec/modules/viqeoBidAdapter_spec.js @@ -0,0 +1,124 @@ +import {expect} from 'chai'; +import {spec} from 'modules/viqeoBidAdapter'; + +describe('viqeoBidAdapter', function () { + it('minimal params', function () { + expect(spec.isBidRequestValid({ + bidder: 'viqeo', + params: { + user: { + buyeruid: '1', + }, + playerOptions: { + videoId: 'ed584da454c7205ca7e4', + profileId: 1382, + }, + }})).to.equal(true); + }); + it('minimal params no playerOptions', function () { + expect(spec.isBidRequestValid({ + bidder: 'viqeo', + params: { + currency: 'EUR', + }})).to.equal(false); + }); + it('build request check data', function () { + const bidRequestData = [{ + bidId: 'id1', + bidder: 'viqeo', + params: { + user: { + buyeruid: '1', + }, + currency: 'EUR', + floor: 0.5, + playerOptions: { + videoId: 'ed584da454c7205ca7e4', + profileId: 1382, + }, + }, + mediaTypes: { + video: { playerSize: [[240, 400]] } + }, + }]; + const request = spec.buildRequests(bidRequestData); + const requestData = request[0].data; + expect(requestData.id).to.equal('id1') + expect(requestData.imp[0].bidfloorcur).to.equal('EUR'); + expect(requestData.imp[0].bidfloor).to.equal(0.5); + expect(requestData.imp[0].video.w).to.equal(240); + expect(requestData.imp[0].video.h).to.equal(400); + expect(requestData.user.buyeruid).to.equal('1'); + }); + it('build request check url', function () { + const bidRequestData = [{ + bidder: 'viqeo', + params: { + playerOptions: { + videoId: 'ed584da454c7205ca7e4', + profileId: 1382, + }, + sspId: 42, + }, + mediaTypes: { + video: { playerSize: [[240, 400]] } + }, + }]; + const request = spec.buildRequests(bidRequestData); + expect(request[0].url).to.equal('https://ads.betweendigital.com/openrtb_bid/?sspId=42') + }); + it('response_params common case', function () { + const bidRequestData = { + bids: [{ + bidId: 'id1', + params: {}, + mediaTypes: { + video: { playerSize: [[240, 400]] } + }, + }], + }; + const serverResponse = { + body: { + id: 'id1', + cur: 'EUR', + seatbid: [{ + bid: [{ + cpm: 0.5, + ttl: 3600, + netRevenue: true, + creativeId: 'test1', + adm: '', + }], + }], + } + }; + const bids = spec.interpretResponse(serverResponse, bidRequestData); + expect(bids).to.have.lengthOf(1); + }); + it('should set flooPrice to getFloor.floor value if it is greater than params.floor', function() { + const bidRequestData = [{ + bidId: 'id1', + bidder: 'viqeo', + params: { + currency: 'EUR', + floor: 0.5, + playerOptions: { + videoId: 'ed584da454c7205ca7e4', + profileId: 1382, + }, + }, + mediaTypes: { + video: { playerSize: [[240, 400]] } + }, + getFloor: () => { + return { + currency: 'EUR', + floor: 3.32 + } + }, + }]; + const request = spec.buildRequests(bidRequestData); + const requestData = request[0].data; + expect(requestData.imp[0].bidfloor).to.equal(3.32) + }); +}); From c7da527e4d38819bd1d73dfcd0da75600f649391 Mon Sep 17 00:00:00 2001 From: SebRobert Date: Thu, 17 Nov 2022 13:14:01 +0100 Subject: [PATCH 126/367] BeOp Bid Adapter : update keywords management (#9166) * Don't know why params are in an array in that bid object. Make it work for both if it is fixed later * Update params reading method to adapt to arrays for all params * Keywords have to be an array of string (#9) * Keywords have to be an array of string * Last check if isStr * Fix linting errors * Fix tests --- modules/beopBidAdapter.js | 19 ++++++++- test/spec/modules/beopBidAdapter_spec.js | 52 ++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/modules/beopBidAdapter.js b/modules/beopBidAdapter.js index f8a53a293de..4ee5aaec5be 100644 --- a/modules/beopBidAdapter.js +++ b/modules/beopBidAdapter.js @@ -1,4 +1,4 @@ -import { deepAccess, isArray, logWarn, triggerPixel, buildUrl, logInfo, getValue, getBidIdParameter } from '../src/utils.js'; +import { deepAccess, isArray, isStr, logWarn, triggerPixel, buildUrl, logInfo, getValue, getBidIdParameter } from '../src/utils.js'; import { getRefererInfo } from '../src/refererDetection.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { config } from '../src/config.js'; @@ -40,6 +40,19 @@ export const spec = { const pageUrl = getPageUrl(bidderRequest.refererInfo, window); const gdpr = bidderRequest.gdprConsent; const firstSlot = slots[0]; + const kwdsFromRequest = firstSlot.kwds; + let keywords = []; + if (kwdsFromRequest) { + if (isArray(kwdsFromRequest)) { + keywords = kwdsFromRequest; + } else if (isStr(kwdsFromRequest)) { + if (kwdsFromRequest.indexOf(',') != -1) { + keywords = kwdsFromRequest.split(',').map((e) => { return e.trim() }); + } else { + keywords.push(kwdsFromRequest); + } + } + } const payloadObject = { at: new Date().toString(), nid: firstSlot.nid, @@ -47,12 +60,13 @@ export const spec = { pid: firstSlot.pid, url: pageUrl, lang: (window.navigator.language || window.navigator.languages[0]), - kwds: bidderRequest.ortb2?.site?.keywords || [], + kwds: keywords, dbg: false, slts: slots, is_amp: deepAccess(bidderRequest, 'referrerInfo.isAmp'), tc_string: (gdpr && gdpr.gdprApplies) ? gdpr.consentString : null, }; + const payloadString = JSON.stringify(payloadObject); return { method: 'POST', @@ -129,6 +143,7 @@ function beOpRequestSlotsMaker(bid) { sizes: isArray(bannerSizes) ? bannerSizes : bid.sizes, flr: floor, pid: getValue(bid.params, 'accountId'), + kwds: getValue(bid.params, 'keywords'), nid: getValue(bid.params, 'networkId'), nptnid: getValue(bid.params, 'networkPartnerId'), bid: getBidIdParameter('bidId', bid), diff --git a/test/spec/modules/beopBidAdapter_spec.js b/test/spec/modules/beopBidAdapter_spec.js index c6001c3ba2e..ad096fd6526 100644 --- a/test/spec/modules/beopBidAdapter_spec.js +++ b/test/spec/modules/beopBidAdapter_spec.js @@ -216,4 +216,56 @@ describe('BeOp Bid Adapter tests', () => { expect(triggerPixelStub.getCall(0).args[0]).to.exist.and.to.include('pid=5a8af500c9e77c00017e4cad'); }); }); + + describe('Ensure keywords is always array of string', function () { + let bidRequests = []; + afterEach(function () { + bidRequests = []; + }); + + it('should work with keywords as an array', function () { + let bid = Object.assign({}, validBid); + bid.params.keywords = ['a', 'b']; + bidRequests.push(bid); + config.setConfig({ + currency: { adServerCurrency: 'USD' } + }); + const request = spec.buildRequests(bidRequests, {}); + const payload = JSON.parse(request.data); + const url = request.url; + expect(payload.kwds).to.exist; + expect(payload.kwds).to.include('a'); + expect(payload.kwds).to.include('b'); + }); + + it('should work with keywords as a string', function () { + let bid = Object.assign({}, validBid); + bid.params.keywords = 'list of keywords'; + bidRequests.push(bid); + config.setConfig({ + currency: { adServerCurrency: 'USD' } + }); + const request = spec.buildRequests(bidRequests, {}); + const payload = JSON.parse(request.data); + const url = request.url; + expect(payload.kwds).to.exist; + expect(payload.kwds).to.include('list of keywords'); + }); + + it('should work with keywords as a string containing a comma', function () { + let bid = Object.assign({}, validBid); + bid.params.keywords = 'list, of, keywords'; + bidRequests.push(bid); + config.setConfig({ + currency: { adServerCurrency: 'USD' } + }); + const request = spec.buildRequests(bidRequests, {}); + const payload = JSON.parse(request.data); + const url = request.url; + expect(payload.kwds).to.exist; + expect(payload.kwds).to.include('list'); + expect(payload.kwds).to.include('of'); + expect(payload.kwds).to.include('keywords'); + }) + }) }); From c86f41b9eabef64615211cc417291a6fa76078df Mon Sep 17 00:00:00 2001 From: TheMediaGrid <44166371+TheMediaGrid@users.noreply.github.com> Date: Thu, 17 Nov 2022 15:33:40 +0300 Subject: [PATCH 127/367] TheMediaGrid: added withCriteo paramater to send criteo request with the /hbjson request (#9214) --- modules/gridBidAdapter.js | 462 +++++++++++++++++++++-- test/spec/modules/gridBidAdapter_spec.js | 290 +++++++++++++- 2 files changed, 729 insertions(+), 23 deletions(-) diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index 181ce0ebab2..3aaeaf73580 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -1,18 +1,38 @@ -import { isEmpty, deepAccess, logError, parseGPTSingleSizeArrayToRtbSize, generateUUID, mergeDeep, logWarn } from '../src/utils.js'; +import { + isEmpty, + deepAccess, + logError, + parseGPTSingleSizeArrayToRtbSize, + generateUUID, + mergeDeep, + logWarn, + parseUrl, isArray, isNumber +} 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'; import { getStorageManager } from '../src/storageManager.js'; +import { find } from '../src/polyfill.js'; const BIDDER_CODE = 'grid'; const ENDPOINT_URL = 'https://grid.bidswitch.net/hbjson'; + +const ADAPTER_VERSION_FOR_CRITEO_MODE = 34; +const CDB_ENDPOINT = 'https://bidder.criteo.com/cdb'; +const PROFILE_ID_INLINE = 207; +const SID_COOKIE_NAME = 'cto_sid'; +const IDCPY_COOKIE_NAME = 'cto_idcpy'; +const OPTOUT_COOKIE_NAME = 'cto_optout'; +const BUNDLE_COOKIE_NAME = 'cto_bundle'; + const SYNC_URL = 'https://x.bidswitch.net/sync?ssp=themediagrid'; const TIME_TO_LIVE = 360; const USER_ID_KEY = 'tmguid'; const GVLID = 686; const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; export const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE}); + const LOG_ERROR_MESS = { noAuid: 'Bid from response has no auid parameter - ', noAdm: 'Bid from response has no adm parameter - ', @@ -49,7 +69,7 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function(bid) { - return !!bid.params.uid; + return bid && Boolean(bid.params.uid || bid.params.secid); }, /** * Make a server request from the list of BidRequests. @@ -79,10 +99,20 @@ export const spec = { const imp = []; const bidsMap = {}; const requests = []; + const criteoBidsMap = {}; + const criteoBidRequests = []; const sources = []; const bidsArray = []; validBidRequests.forEach((bid) => { + const bidObject = { bid, savedPrebidBid: null }; + if (bid.params.withCriteo && criteoSpec.isBidRequestValid(bid)) { + criteoBidsMap[bid.bidId] = bidObject; + criteoBidRequests.push(bid); + } + if (!bid.params.uid && !bid.params.secid) { + return; + } if (!bidderRequestId) { bidderRequestId = bid.bidderRequestId; } @@ -100,7 +130,6 @@ export const spec = { } const { params: { uid, keywords, forceBidder, multiRequest }, mediaTypes, bidId, adUnitCode, rtd, ortb2Imp } = bid; const { pubdata, secid, pubid, source, content: bidParamsContent } = bid.params; - bidsMap[bidId] = bid; const bidFloor = _getFloor(mediaTypes || {}, bid); const jwTargeting = rtd && rtd.jwplayer && rtd.jwplayer.targeting; if (jwTargeting) { @@ -201,8 +230,9 @@ export const spec = { requests.push(request); sources.push(source); - bidsArray.push(bid); + bidsArray.push(bidObject); } else { + bidsMap[bidId] = bidObject; imp.push(impObj); } } @@ -377,6 +407,11 @@ export const spec = { } }); + const criteoRequest = criteoBidRequests.length && criteoSpec.buildRequests(criteoBidRequests, bidderRequest); + if (criteoRequest) { + criteoRequest.criteoBidsMap = criteoBidsMap; + } + return [...requests.map((req, i) => { let sp; const url = (endpoint || ENDPOINT_URL).replace(/[?&]sp=([^?&=]+)/, (i, found) => { @@ -391,14 +426,14 @@ export const spec = { method: 'POST', url: urlWithParams, data: JSON.stringify(req), - bid: bidsArray[i], + bidObject: bidsArray[i], }; }), ...(mainRequest ? [{ method: 'POST', url: endpoint || ENDPOINT_URL, data: JSON.stringify(mainRequest), bidsMap - }] : [])]; + }] : []), ...(criteoRequest ? [criteoRequest] : [])]; }, /** * Unpack the response from the server into a list of bids. @@ -409,25 +444,33 @@ export const spec = { * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: function(serverResponse, bidRequest, RendererConst = Renderer) { - serverResponse = serverResponse && serverResponse.body; - const bidResponses = []; + if (bidRequest.criteoBidsMap && bidRequest.bidRequests) { + const criteoBids = criteoSpec.interpretResponse(serverResponse, bidRequest); + return criteoBids.filter((bid) => { + const { savedPrebidBid } = bidRequest.criteoBidsMap[bid.requestId] || {}; + return canPublishResponse(bid.cpm, savedPrebidBid && savedPrebidBid.cpm); + }); + } else { + serverResponse = serverResponse && serverResponse.body; + const bidResponses = []; - let errorMessage; + let errorMessage; - if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse; - else if (serverResponse.seatbid && !serverResponse.seatbid.length) { - errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; - } + if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse; + else if (serverResponse.seatbid && !serverResponse.seatbid.length) { + errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; + } - const bidderCode = this.forceBidderName || this.code; + const bidderCode = this.forceBidderName || this.code; - if (!errorMessage && serverResponse.seatbid) { - serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidRequest, bidResponses, RendererConst, bidderCode); - }); + if (!errorMessage && serverResponse.seatbid) { + serverResponse.seatbid.forEach(respItem => { + _addBidResponse(_getBidFromResponse(respItem), bidRequest, bidResponses, RendererConst, bidderCode); + }); + } + if (errorMessage) logError(errorMessage); + return bidResponses; } - if (errorMessage) logError(errorMessage); - return bidResponses; }, getUserSyncs: function (...args) { const [syncOptions,, gdprConsent, uspConsent] = args; @@ -502,8 +545,9 @@ function _addBidResponse(serverBid, bidRequest, bidResponses, RendererConst, bid if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); if (!errorMessage && !serverBid.adm && !serverBid.nurl) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid); else { - const bid = bidRequest.bidsMap ? bidRequest.bidsMap[serverBid.impid] : bidRequest.bid; - if (bid) { + const bidObject = bidRequest.bidsMap ? bidRequest.bidsMap[serverBid.impid] : bidRequest.bidObject; + const { bid, savedPrebidBid } = bidObject || {}; + if (bid && canPublishResponse(serverBid.price, savedPrebidBid && savedPrebidBid.cpm)) { const bidResponse = { requestId: bid.bidId, // bid.bidderRequestId cpm: serverBid.price, @@ -519,6 +563,8 @@ function _addBidResponse(serverBid, bidRequest, bidResponses, RendererConst, bid dealId: serverBid.dealid }; + bidObject.savedPrebidBid = bidResponse; + if (serverBid.ext && serverBid.ext.bidder && serverBid.ext.bidder.grid && serverBid.ext.bidder.grid.demandSource) { bidResponse.adserverTargeting = { 'hb_ds': serverBid.ext.bidder.grid.demandSource }; bidResponse.meta.demandSource = serverBid.ext.bidder.grid.demandSource; @@ -664,6 +710,13 @@ function reformatKeywords(pageKeywords) { return Object.keys(formatedPageKeywords).length && formatedPageKeywords; } +function canPublishResponse(price, savedPrice) { + if (isNumber(savedPrice)) { + return price > savedPrice || (price === savedPrice && Math.random() > 0.5); + } + return true; +} + function outstreamRender (bid) { bid.renderer.push(() => { window.ANOutstreamVideo.renderAd({ @@ -697,4 +750,369 @@ export function getSyncUrl() { return SYNC_URL; } +// ================ Criteo methods ================== + +const criteoSpec = { + /** f + * @param {object} bid + * @return {boolean} + */ + isBidRequestValid: (bid) => { + // either one of zoneId or networkId should be set + if (!(bid && bid.params && (bid.params.zoneId || bid.params.networkId))) { + return false; + } + + // video media types requires some mandatory params + if (hasVideoMediaType(bid)) { + if (!hasValidVideoMediaType(bid)) { + return false; + } + } + + return true; + }, + + /** + * @param {BidRequest[]} bidRequests + * @param {*} bidderRequest + * @return {ServerRequest} + */ + buildRequests: (bidRequests, bidderRequest) => { + let url; + let data; + let fpd = bidderRequest.ortb2 || {}; + + Object.assign(bidderRequest, { + publisherExt: fpd.site?.ext, + userExt: fpd.user?.ext, + ceh: config.getConfig('criteo.ceh'), + coppa: config.getConfig('coppa') + }); + + const context = buildContext(bidRequests, bidderRequest); + url = buildCdbUrl(context); + data = buildCdbRequest(context, bidRequests, bidderRequest); + + if (data) { + return { method: 'POST', url, data, bidRequests }; + } + }, + + /** + * @param {*} response + * @param {ServerRequest} request + * @return {Bid[]} + */ + interpretResponse: (response, request) => { + const body = response.body || response; + const bids = []; + + if (body && body.slots && isArray(body.slots)) { + body.slots.forEach(slot => { + const bidRequest = find(request.bidRequests, b => b.adUnitCode === slot.impid && (!b.params.zoneId || parseInt(b.params.zoneId) === slot.zoneid)); + const bidId = bidRequest.bidId; + const bid = { + requestId: bidId, + cpm: slot.cpm, + currency: slot.currency, + netRevenue: true, + ttl: slot.ttl || 60, + creativeId: slot.creativecode, + width: slot.width, + height: slot.height, + dealId: slot.dealCode, + }; + if (body.ext?.paf?.transmission && slot.ext?.paf?.content_id) { + const pafResponseMeta = { + content_id: slot.ext.paf.content_id, + transmission: response.ext.paf.transmission + }; + bid.meta = Object.assign({}, bid.meta, { paf: pafResponseMeta }); + } + if (slot.adomain) { + bid.meta = Object.assign({}, bid.meta, { advertiserDomains: slot.adomain }); + } + if (slot.video) { + bid.vastUrl = slot.displayurl; + bid.mediaType = VIDEO; + } else { + bid.ad = slot.creative; + } + bids.push(bid); + }); + } + + return bids; + } +}; + +function readFromAllStorages(name) { + const fromCookie = storage.getCookie(name); + const fromLocalStorage = storage.getDataFromLocalStorage(name); + + return fromCookie || fromLocalStorage || undefined; +} + +/** + * @param {BidRequest[]} bidRequests + * @param bidderRequest + */ +function buildContext(bidRequests, bidderRequest) { + let referrer = ''; + if (bidderRequest && bidderRequest.refererInfo) { + referrer = bidderRequest.refererInfo.page; + } + const queryString = parseUrl(bidderRequest?.refererInfo?.topmostLocation).search; + + const context = { + url: referrer, + debug: queryString['pbt_debug'] === '1', + noLog: queryString['pbt_nolog'] === '1', + amp: false, + }; + + bidRequests.forEach(bidRequest => { + if (bidRequest.params.integrationMode === 'amp') { + context.amp = true; + } + }); + + return context; +} + +/** + * @param {CriteoContext} context + * @return {string} + */ +function buildCdbUrl(context) { + let url = CDB_ENDPOINT; + url += '?profileId=' + PROFILE_ID_INLINE; + url += '&av=' + String(ADAPTER_VERSION_FOR_CRITEO_MODE); + url += '&wv=' + encodeURIComponent('$prebid.version$'); + url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); + + if (storage.localStorageIsEnabled()) { + url += '&lsavail=1'; + } else { + url += '&lsavail=0'; + } + + if (context.amp) { + url += '&im=1'; + } + if (context.debug) { + url += '&debug=1'; + } + if (context.noLog) { + url += '&nolog=1'; + } + + const bundle = readFromAllStorages(BUNDLE_COOKIE_NAME); + if (bundle) { + url += `&bundle=${bundle}`; + } + + const optout = readFromAllStorages(OPTOUT_COOKIE_NAME); + if (optout) { + url += `&optout=1`; + } + + const sid = readFromAllStorages(SID_COOKIE_NAME); + if (sid) { + url += `&sid=${sid}`; + } + + const idcpy = readFromAllStorages(IDCPY_COOKIE_NAME); + if (idcpy) { + url += `&idcpy=${idcpy}`; + } + + return url; +} + +/** + * @param {CriteoContext} context + * @param {BidRequest[]} bidRequests + * @param bidderRequest + * @return {*} + */ +function buildCdbRequest(context, bidRequests, bidderRequest) { + let networkId; + let schain; + const request = { + publisher: { + url: context.url, + ext: bidderRequest.publisherExt, + }, + regs: { + coppa: bidderRequest.coppa === true ? 1 : (bidderRequest.coppa === false ? 0 : undefined) + }, + slots: bidRequests.map(bidRequest => { + networkId = bidRequest.params.networkId || networkId; + schain = bidRequest.schain || schain; + const slot = { + impid: bidRequest.adUnitCode, + transactionid: bidRequest.transactionId, + auctionId: bidRequest.auctionId, + }; + if (bidRequest.params.zoneId) { + slot.zoneid = bidRequest.params.zoneId; + } + if (deepAccess(bidRequest, 'ortb2Imp.ext')) { + slot.ext = bidRequest.ortb2Imp.ext; + } + if (bidRequest.params.ext) { + slot.ext = Object.assign({}, slot.ext, bidRequest.params.ext); + } + if (bidRequest.params.publisherSubId) { + slot.publishersubid = bidRequest.params.publisherSubId; + } + + if (hasBannerMediaType(bidRequest)) { + slot.sizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes'), parseSize); + } else { + slot.sizes = []; + } + + if (hasVideoMediaType(bidRequest)) { + const video = { + playersizes: parseSizes(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, + skip: bidRequest.mediaTypes.video.skip, + placement: bidRequest.mediaTypes.video.placement, + minduration: bidRequest.mediaTypes.video.minduration, + playbackmethod: bidRequest.mediaTypes.video.playbackmethod, + startdelay: bidRequest.mediaTypes.video.startdelay + }; + const paramsVideo = bidRequest.params.video; + if (paramsVideo !== undefined) { + video.skip = video.skip || paramsVideo.skip || 0; + video.placement = video.placement || paramsVideo.placement; + video.minduration = video.minduration || paramsVideo.minduration; + video.playbackmethod = video.playbackmethod || paramsVideo.playbackmethod; + video.startdelay = video.startdelay || paramsVideo.startdelay || 0; + } + + slot.video = video; + } + + enrichSlotWithFloors(slot, bidRequest); + + return slot; + }), + }; + if (networkId) { + request.publisher.networkid = networkId; + } + if (schain) { + request.source = { + ext: { + schain: schain + } + }; + } + request.user = { + ext: bidderRequest.userExt + }; + if (bidderRequest && bidderRequest.ceh) { + request.user.ceh = bidderRequest.ceh; + } + if (bidderRequest && bidderRequest.gdprConsent) { + request.gdprConsent = {}; + if (typeof bidderRequest.gdprConsent.gdprApplies !== 'undefined') { + request.gdprConsent.gdprApplies = !!(bidderRequest.gdprConsent.gdprApplies); + } + request.gdprConsent.version = bidderRequest.gdprConsent.apiVersion; + if (typeof bidderRequest.gdprConsent.consentString !== 'undefined') { + request.gdprConsent.consentData = bidderRequest.gdprConsent.consentString; + } + } + if (bidderRequest && bidderRequest.uspConsent) { + request.user.uspIab = bidderRequest.uspConsent; + } + return request; +} + +function parseSizes(sizes, parser = s => s) { + if (sizes === undefined) { + return []; + } + 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 hasVideoMediaType(bidRequest) { + return deepAccess(bidRequest, 'mediaTypes.video') !== undefined; +} + +function hasBannerMediaType(bidRequest) { + return deepAccess(bidRequest, 'mediaTypes.banner') !== undefined; +} + +function hasValidVideoMediaType(bidRequest) { + let isValid = true; + + var requiredMediaTypesParams = ['mimes', 'playerSize', 'maxduration', 'protocols', 'api', 'skip', 'placement', 'playbackmethod']; + + requiredMediaTypesParams.forEach(function (param) { + if (deepAccess(bidRequest, 'mediaTypes.video.' + param) === undefined && deepAccess(bidRequest, 'params.video.' + param) === undefined) { + isValid = false; + logError('TheMediaGrid Bid Adapter (withCriteo mode): mediaTypes.video.' + param + ' is required'); + } + }); + + if (isValid) { + const videoPlacement = bidRequest.mediaTypes.video.placement || bidRequest.params.video.placement; + // We do not support long form for now, also we have to check that context & placement are consistent + if (bidRequest.mediaTypes.video.context === 'instream' && videoPlacement === 1) { + return true; + } else if (bidRequest.mediaTypes.video.context === 'outstream' && videoPlacement !== 1) { + return true; + } + } + + return false; +} + +function enrichSlotWithFloors(slot, bidRequest) { + try { + const slotFloors = {}; + + if (bidRequest.getFloor) { + if (bidRequest.mediaTypes?.banner) { + slotFloors.banner = {}; + const bannerSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes')) + bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = bidRequest.getFloor({ size: bannerSize, mediaType: BANNER })); + } + + if (bidRequest.mediaTypes?.video) { + slotFloors.video = {}; + const videoSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize')) + videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = bidRequest.getFloor({ size: videoSize, mediaType: VIDEO })); + } + + if (Object.keys(slotFloors).length > 0) { + if (!slot.ext) { + slot.ext = {} + } + Object.assign(slot.ext, { + floors: slotFloors + }); + } + } + } catch (e) { + logError('Could not parse floors from Prebid: ' + e); + } +} + registerBidder(spec); diff --git a/test/spec/modules/gridBidAdapter_spec.js b/test/spec/modules/gridBidAdapter_spec.js index f98ca683024..4b93c287fee 100644 --- a/test/spec/modules/gridBidAdapter_spec.js +++ b/test/spec/modules/gridBidAdapter_spec.js @@ -44,8 +44,9 @@ describe('TheMediaGrid Adapter', function () { return JSON.parse(data); } const bidderRequest = { - refererInfo: {page: 'https://example.com'}, + refererInfo: { page: 'https://example.com' }, bidderRequestId: '22edbae2733bf6', + transactionId: '1239bd74-4511-4335-af21-e828852e25d7', auctionId: '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', timeout: 3000 }; @@ -67,6 +68,7 @@ describe('TheMediaGrid Adapter', function () { 'bidId': '42dbe3a7168a6a', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + transactionId: '1239bd74-4511-4335-af21-e828852e25d7', }, { 'bidder': 'grid', @@ -78,6 +80,7 @@ describe('TheMediaGrid Adapter', function () { 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + transactionId: '1239bd74-4511-4335-af21-e828852e25d7', }, { 'bidder': 'grid', @@ -95,6 +98,7 @@ describe('TheMediaGrid Adapter', function () { 'bidId': '3150ccb55da321', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + transactionId: '1239bd74-4511-4335-af21-e828852e25d7', }, { 'bidder': 'grid', @@ -115,6 +119,7 @@ describe('TheMediaGrid Adapter', function () { 'bidId': '3150ccb55da321', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + transactionId: '1239bd74-4511-4335-af21-e828852e25d7', } ]; @@ -395,6 +400,158 @@ describe('TheMediaGrid Adapter', function () { getDataFromLocalStorageStub.restore(); }); + it('should send additional request with adUnits with withCriteo parameter', function () { + const fpdUserIdVal = '0b0f84a1-1596-4165-9742-2e1a7dfac57f'; + const getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage').callsFake( + arg => arg === 'tmguid' ? fpdUserIdVal : null); + + const bidRequestsWithCriteo = bidRequests.map((bid, i) => + i % 2 ? bid : { + ...bid, + params: { + ...bid.params, + withCriteo: true, + networkId: 123 + i + }, + mediaTypes: { + ...bid.mediaTypes, + ...(bid.mediaTypes.video && { video: { + ...bid.mediaTypes.video, + context: 'instream', + protocols: [1, 2, 3], + maxduration: 30, + api: [1, 2], + skip: 1, + placement: 1, + minduration: 0, + playbackmethod: 1, + startdelay: 0 + } + }) + } + }); + + const [request, criteoRequest] = spec.buildRequests(bidRequestsWithCriteo, bidderRequest); + expect(request.data).to.be.an('string'); + expect(criteoRequest.data).to.be.an('object'); + const payload = parseRequest(request.data); + const criteoPayload = criteoRequest.data; + expect(request.url).to.equal('https://grid.bidswitch.net/hbjson'); + expect(criteoRequest.url.replace(/\?.*$/, '')) + .to.equal('https://bidder.criteo.com/cdb'); + expect(payload).to.deep.equal({ + 'id': bidderRequest.bidderRequestId, + 'site': { + 'page': referrer + }, + 'tmax': bidderRequest.timeout, + 'source': { + 'tid': bidderRequest.auctionId, + 'ext': {'wrapper': 'Prebid_js', 'wrapper_version': '$prebid.version$'} + }, + 'user': { + 'id': fpdUserIdVal + }, + 'imp': [{ + 'id': bidRequests[0].bidId, + 'tagid': bidRequests[0].params.uid, + 'ext': {'divid': bidRequests[0].adUnitCode}, + 'bidfloor': bidRequests[0].params.bidFloor, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }, { + 'id': bidRequests[1].bidId, + 'tagid': bidRequests[1].params.uid, + 'ext': {'divid': bidRequests[1].adUnitCode}, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }, { + 'id': bidRequests[2].bidId, + 'tagid': bidRequests[2].params.uid, + 'ext': {'divid': bidRequests[2].adUnitCode}, + 'video': { + 'w': 400, + 'h': 600, + 'protocols': [1, 2, 3], + 'mimes': ['video/mp4', 'video/webm', 'application/javascript', 'video/ogg'], + } + }, { + 'id': bidRequests[3].bidId, + 'tagid': bidRequests[3].params.uid, + 'ext': {'divid': bidRequests[3].adUnitCode}, + 'banner': { + 'w': 728, + 'h': 90, + 'format': [{'w': 728, 'h': 90}] + }, + 'video': { + 'w': 400, + 'h': 600, + 'protocols': [1, 2, 3] + } + }] + }); + + expect(criteoPayload).to.deep.equal({ + 'publisher': { + 'ext': undefined, + 'url': bidderRequest.refererInfo.page, + 'networkid': 125 + }, + 'regs': { + 'coppa': undefined + }, + 'slots': [{ + 'impid': bidRequests[0].adUnitCode, + 'transactionid': bidderRequest.transactionId, + 'auctionId': bidderRequest.auctionId, + 'sizes': ['300x250', '300x600'] + }, { + 'impid': bidRequests[2].adUnitCode, + 'transactionid': bidderRequest.transactionId, + 'auctionId': bidderRequest.auctionId, + 'sizes': [], + 'video': { + 'api': [ + 1, + 2 + ], + 'maxduration': 30, + 'mimes': [ + 'video/mp4', + 'video/webm', + 'application/javascript', + 'video/ogg', + ], + 'minduration': 0, + 'placement': 1, + 'playbackmethod': 1, + 'playersizes': [ + '400x600' + ], + 'protocols': [ + 1, + 2, + 3 + ], + 'skip': 1, + 'startdelay': 0 + } + }], + 'user': { + 'ext': undefined + } + }); + + getDataFromLocalStorageStub.restore(); + }); + it('if gdprConsent is present payload must have gdpr params', function () { const gdprBidderRequest = Object.assign({gdprConsent: {consentString: 'AAA', gdprApplies: true}}, bidderRequest); const [request] = spec.buildRequests(bidRequests, gdprBidderRequest); @@ -1365,6 +1522,137 @@ describe('TheMediaGrid Adapter', function () { expect(result).to.deep.equal(expectedResponse); }); + it('should add response with biggest price', function () { + const mainResponse = [ + {'bid': [{'impid': '2164be6358b9', 'price': 1.15, 'adm': '
test content 1
', 'auid': 1, 'h': 250, 'w': 300, dealid: 11}], 'seat': '1'}, + {'bid': [{'impid': '4e111f1b66e4', 'price': 0.5, 'adm': '
test content 2
', 'auid': 2, 'h': 600, 'w': 300, dealid: 12}], 'seat': '1'}, + ]; + const criteoResponse = [ + { + impid: 'adunit-code-1', + cpm: 0.15, + creative: '
test content 3
', + creativecode: 1, + bidId: '2164be6358b9', + currency: 'USD', + width: 300, + height: 250, + dealCode: 11, + zoneid: 123, + ttl: 360, + adomain: ['criteo.com'], + }, + { + impid: 'adunit-code-1', + cpm: 1, + creative: '
test content 4
', + creativecode: 2, + bidId: '4e111f1b66e4', + currency: 'USD', + width: 300, + height: 600, + dealCode: 12, + zoneid: 456, + ttl: 360, + adomain: ['criteo.com'], + } + ]; + const bidRequests = [ + { + 'bidder': 'grid', + 'params': { + 'uid': '1', + 'zoneId': 123, + 'withCriteo': true + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '2164be6358b9', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + 'transactionId': '43534f55b213ac', + }, + { + 'bidder': 'grid', + 'params': { + 'uid': '2', + 'zoneId': 456, + 'withCriteo': true + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '4e111f1b66e4', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + 'transactionId': '43534f55b213ac', + } + ]; + const bidderRequest = { + refererInfo: { page: 'https://example.com' }, + bidderRequestId: '106efe3247', + transactionId: '43534f55b213ac', + auctionId: '32a1f276cb87cb8', + timeout: 3000 + }; + const [mainRequest, criteoRequest] = spec.buildRequests(bidRequests, bidderRequest); + const expectedMainResponse = [ + { + 'requestId': '2164be6358b9', + 'cpm': 1.15, + 'creativeId': 1, + 'dealId': 11, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'currency': 'USD', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + 'meta': { + advertiserDomains: [] + }, + }, + { + 'requestId': '4e111f1b66e4', + 'cpm': 0.5, + 'creativeId': 2, + 'dealId': 12, + 'width': 300, + 'height': 600, + 'ad': '
test content 2
', + 'currency': 'USD', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + 'meta': { + advertiserDomains: [] + }, + } + ]; + const expectedCriteoResponse = [ + { + 'requestId': '4e111f1b66e4', + 'cpm': 1, + 'creativeId': 2, + 'dealId': 12, + 'width': 300, + 'height': 600, + 'ad': '
test content 4
', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + 'meta': { + advertiserDomains: ['criteo.com'] + }, + } + ]; + + const mainResult = spec.interpretResponse({'body': {'seatbid': mainResponse}}, mainRequest); + const criteoResult = spec.interpretResponse({'body': {'slots': criteoResponse}}, criteoRequest); + expect(mainResult).to.deep.equal(expectedMainResponse); + expect(criteoResult).to.deep.equal(expectedCriteoResponse); + }); + it('response with ext.bidder.grid.demandSource', function () { const bidRequests = [ { From a88c296ae95fe7c1f9a32a7fc8a23e718ba4d306 Mon Sep 17 00:00:00 2001 From: prebidtappx <77485538+prebidtappx@users.noreply.github.com> Date: Thu, 17 Nov 2022 14:59:49 +0100 Subject: [PATCH 128/367] Tappx Bid Adapter: getting correct site page (#9187) * Fix: creating host correctly when http or https are added from the beginning * Fix :: Changed double quotes for single quotes * Fix :: Getting the full page URL * Fix :: Changed order params * Fix :: Replaced quotes from double to simple * Fix :: Adapting format to lint * Remove TODO comment * Added more controls * camelcase fix * Changed test * Remove "inIframe" util Co-authored-by: Jordi Arnau Co-authored-by: ruben_tappx --- modules/tappxBidAdapter.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/modules/tappxBidAdapter.js b/modules/tappxBidAdapter.js index 11aa6c76c76..c7a54431ee9 100644 --- a/modules/tappxBidAdapter.js +++ b/modules/tappxBidAdapter.js @@ -11,7 +11,7 @@ const BIDDER_CODE = 'tappx'; const GVLID_CODE = 628; const TTL = 360; const CUR = 'USD'; -const TAPPX_BIDDER_VERSION = '0.1.1005'; +const TAPPX_BIDDER_VERSION = '0.1.2'; const TYPE_CNN = 'prebidjs'; const LOG_PREFIX = '[TAPPX]: '; const VIDEO_SUPPORT = ['instream', 'outstream']; @@ -271,12 +271,28 @@ function buildOneRequest(validBidRequests, bidderRequest) { api[0] = deepAccess(validBidRequests, 'params.api') ? deepAccess(validBidRequests, 'params.api') : [3, 5]; } else { let bundle = _extractPageUrl(validBidRequests, bidderRequest); - let site = {}; + let site = deepAccess(validBidRequests, 'params.site') || {}; site.name = bundle; + site.page = bidderRequest?.refererInfo?.page || deepAccess(validBidRequests, 'params.site.page') || bidderRequest?.refererInfo?.topmostLocation || window.location.href || bundle; site.domain = bundle; + site.ref = bidderRequest?.refererInfo?.ref || window.top.document.referrer || ''; + site.ext = {}; + site.ext.is_amp = bidderRequest?.refererInfo?.isAmp || 0; + site.ext.page_da = deepAccess(validBidRequests, 'params.site.page') || '-'; + site.ext.page_rip = bidderRequest?.refererInfo?.page || '-'; + site.ext.page_rit = bidderRequest?.refererInfo?.topmostLocation || '-'; + site.ext.page_wlh = window.location.href || '-'; publisher.name = bundle; publisher.domain = bundle; + let sitename = document.getElementsByTagName('meta')['title']; + if (sitename && sitename.content) { + site.name = sitename.content; + } tagid = `${site.name}_typeAdBanVid_${getOs()}`; + let keywords = document.getElementsByTagName('meta')['keywords']; + if (keywords && keywords.content) { + site.keywords = keywords.content; + } payload.site = site; } // < App/Site object @@ -295,9 +311,9 @@ function buildOneRequest(validBidRequests, bidderRequest) { if ( ((bannerMediaType.sizes[0].indexOf(480) >= 0) && (bannerMediaType.sizes[0].indexOf(320) >= 0)) || ((bannerMediaType.sizes[0].indexOf(768) >= 0) && (bannerMediaType.sizes[0].indexOf(1024) >= 0))) { - banner.pos = 7; + banner.pos = 0; } else { - banner.pos = 4; + banner.pos = 0; } banner.api = api; @@ -565,8 +581,7 @@ export function _checkParamDataType(key, value, datatype) { } export function _extractPageUrl(validBidRequests, bidderRequest) { - // TODO: does the fallback make sense? - let url = bidderRequest?.refererInfo?.page || bidderRequest.refererInfo?.topmostLocation; + let url = bidderRequest?.refererInfo?.page || bidderRequest?.refererInfo?.topmostLocation; return parseDomain(url, {noLeadingWww: true}); } From d0c1d741bd4828c8d6d6f8170a9b4c834d64e70c Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 17 Nov 2022 15:44:44 +0000 Subject: [PATCH 129/367] Prebid 7.26.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 462484cb962..a2bf0986f9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.26.0-pre", + "version": "7.26.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 8df1268bbd2..d86a2cccd1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.26.0-pre", + "version": "7.26.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From e680dd34486d7f1ffec6f52fe4599537a62a12a6 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 17 Nov 2022 15:44:45 +0000 Subject: [PATCH 130/367] Increment version to 7.27.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2bf0986f9d..0a3b01b972f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.26.0", + "version": "7.27.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index d86a2cccd1d..d243b650b6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.26.0", + "version": "7.27.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 974e21db74dadb6cb082b2758d77f6af614c91f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:47:25 -0700 Subject: [PATCH 131/367] Bump loader-utils from 2.0.3 to 2.0.4 (#9256) Bumps [loader-utils](https://github.com/webpack/loader-utils) from 2.0.3 to 2.0.4. - [Release notes](https://github.com/webpack/loader-utils/releases) - [Changelog](https://github.com/webpack/loader-utils/blob/v2.0.4/CHANGELOG.md) - [Commits](https://github.com/webpack/loader-utils/compare/v2.0.3...v2.0.4) --- updated-dependencies: - dependency-name: loader-utils dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0a3b01b972f..4584231d42c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.24.0-pre", + "version": "7.27.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -16304,9 +16304,9 @@ } }, "node_modules/loader-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", - "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -25260,6 +25260,7 @@ } }, "plugins/eslint": { + "name": "eslint-plugin-prebid", "version": "1.0.0", "dev": true, "license": "Apache-2.0" @@ -37926,9 +37927,9 @@ "dev": true }, "loader-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", - "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "requires": { "big.js": "^5.2.2", From 2d46b828d37e4ab063fcb7f965188da84aed45ad Mon Sep 17 00:00:00 2001 From: Tobias von Klipstein Date: Fri, 18 Nov 2022 15:14:40 +0100 Subject: [PATCH 132/367] glomex Bidder: expose glomex GVL id (#9262) --- modules/glomexBidAdapter.js | 2 ++ test/spec/modules/glomexBidAdapter_spec.js | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/modules/glomexBidAdapter.js b/modules/glomexBidAdapter.js index 32c2036a748..5c9b3c1fa28 100644 --- a/modules/glomexBidAdapter.js +++ b/modules/glomexBidAdapter.js @@ -4,9 +4,11 @@ import {BANNER} from '../src/mediaTypes.js'; const ENDPOINT = 'https://prebid.mes.glomex.cloud/request-bid' const BIDDER_CODE = 'glomex' +const GVLID = 967 export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: [BANNER], isBidRequestValid: function (bid) { diff --git a/test/spec/modules/glomexBidAdapter_spec.js b/test/spec/modules/glomexBidAdapter_spec.js index 30157da858b..8c53db8d605 100644 --- a/test/spec/modules/glomexBidAdapter_spec.js +++ b/test/spec/modules/glomexBidAdapter_spec.js @@ -49,6 +49,10 @@ const RESPONSE = { describe('glomexBidAdapter', function () { const adapter = newBidder(spec) + it('should expose gvlid', function() { + expect(spec.gvlid).to.equal(967) + }); + describe('inherited functions', function () { it('exists and is a function', function () { expect(adapter.callBids).to.exist.and.to.be.a('function') From e1661af611eb82543faedbbf4d3b95475a36191e Mon Sep 17 00:00:00 2001 From: nkloeber <100145701+nkloeber@users.noreply.github.com> Date: Fri, 18 Nov 2022 17:42:37 +0100 Subject: [PATCH 133/367] Update Floor format to floor={adslotId}:{floorPriceInCents}[, ...] and fix the size which is submitted to the Price Floors Module (#9186) --- modules/yieldlabBidAdapter.js | 14 ++-- test/spec/modules/yieldlabBidAdapter_spec.js | 69 ++++++++++++++------ 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/modules/yieldlabBidAdapter.js b/modules/yieldlabBidAdapter.js index e6758e78022..88e1494d416 100644 --- a/modules/yieldlabBidAdapter.js +++ b/modules/yieldlabBidAdapter.js @@ -41,6 +41,7 @@ export const spec = { const adslotIds = [] const adslotSizes = []; + const adslotFloors = []; const timestamp = Date.now() const query = { ts: timestamp, @@ -77,7 +78,7 @@ export const spec = { } const floor = getBidFloor(bid, sizes) if (floor) { - query.floor = floor; + adslotFloors.push(bid.params.adslotId + ':' + floor); } }) @@ -99,6 +100,11 @@ export const spec = { if (adslotSizes.length > 0) { query.sizes = adslotSizes.join(',') } + + if (adslotFloors.length > 0) { + query.floor = adslotFloors.join(',') + } + const queryString = createQueryString(query) return { @@ -463,7 +469,7 @@ function extractSizes(bid) { * * @param {Object} bid * @param {string[]} sizes - * @returns The floor CPM of a matched rule based on the rule selection process (mediaType, size and currency), + * @returns The floor CPM in cents of a matched rule based on the rule selection process (mediaType, size and currency), * using the getFloor() inputs. Multi sizes and unsupported media types will default to '*' */ function getBidFloor(bid, sizes) { @@ -475,10 +481,10 @@ function getBidFloor(bid, sizes) { const floor = bid.getFloor({ currency: CURRENCY_CODE, mediaType: mediaType !== undefined && spec.supportedMediaTypes.includes(mediaType) ? mediaType : '*', - size: sizes.length !== 1 ? '*' : extractSizes(sizes) + size: sizes.length !== 1 ? '*' : sizes[0].split(DIMENSION_SIGN) }); if (floor.currency === CURRENCY_CODE) { - return floor.floor; + return (floor.floor * 100).toFixed(0); } return undefined; } diff --git a/test/spec/modules/yieldlabBidAdapter_spec.js b/test/spec/modules/yieldlabBidAdapter_spec.js index 9155884106c..5df0e93d34e 100644 --- a/test/spec/modules/yieldlabBidAdapter_spec.js +++ b/test/spec/modules/yieldlabBidAdapter_spec.js @@ -658,36 +658,65 @@ describe('yieldlabBidAdapter', () => { }); describe('getBidFloor', function () { - let bidRequest, getFloor; - - it('should add valid bid floor', () => { - getFloor = () => { - return { - currency: 'EUR', - floor: 1.33 - }; - }; + let bidRequest, bidRequest2, currency, floor; + const getFloor = () => { + return { + currency: currency, + floor: floor + } + } + + it('should add valid bid floor in the format floor={adslotId}:{floorPriceInCents}[, ...]', () => { + bidRequest = Object.assign(DEFAULT_REQUEST(), { + getFloor: () => { + return { + currency: 'EUR', + floor: 1.33 + } + }}); + bidRequest2 = Object.assign(DEFAULT_REQUEST(), { + params: { + adslotId: 2222 + }, + getFloor: () => { + return { + currency: 'EUR', + floor: 2.99 + } + } + }); + const result = spec.buildRequests([bidRequest, bidRequest2], REQPARAMS) + expect(result).to.have.nested.property('queryParams.floor', '1111:133,2222:299') + }); + + it('should round the floor price up', () => { + currency = 'EUR'; + floor = 0.745; bidRequest = Object.assign(DEFAULT_REQUEST(), {getFloor}) const result = spec.buildRequests([bidRequest], REQPARAMS) - expect(result).to.have.nested.property('queryParams.floor', 1.33) + expect(result).to.have.nested.property('queryParams.floor', '1111:75') }); - it('should not add empty bid floor', () => { - getFloor = () => { - return {}; - }; + it('should round the floor price down', () => { + currency = 'EUR'; + floor = 0.034; bidRequest = Object.assign(DEFAULT_REQUEST(), {getFloor}) const result = spec.buildRequests([bidRequest], REQPARAMS) + expect(result).to.have.nested.property('queryParams.floor', '1111:3') + }); + + it('should not add empty bid floor', () => { + bidRequest = Object.assign(DEFAULT_REQUEST(), { + getFloor: () => { + return {}; + }}) + const result = spec.buildRequests([bidRequest], REQPARAMS) expect(result).not.to.have.nested.property('queryParams.floor') }); it('should not add bid floor when currency is not matching', () => { - getFloor = (currency, mediaType, size) => { - return { - currency: 'USD', - floor: 1.33 - }; - }; + currency = 'USD'; + floor = 1.33; bidRequest = Object.assign(DEFAULT_REQUEST(), {getFloor}) const result = spec.buildRequests([bidRequest], REQPARAMS) expect(result).not.to.have.nested.property('queryParams.floor') From a1132c103e09ac6192e80b05d8786a715c0536e5 Mon Sep 17 00:00:00 2001 From: rahulgravito <105201950+rahulgravito@users.noreply.github.com> Date: Fri, 18 Nov 2022 23:01:06 +0530 Subject: [PATCH 134/367] Gravito Id System : variable update to fix tests (#9259) * gravitompId user module for integrating gravito first party cookie with prebid js * fixed eslint issues raised by circleci * fixed trailing spaces error raised by circleci * Merge branch 'master' of https://github.com/GravitoLtd/Prebid.js * minor changes to GravitoIdSystem user module to make sure that Gravito Id is visible in bid request. * changes to Gravito User module to fix issue with Gravito Id not appearing in bid request. * fixing issue with Gravito Id not appearing in bid request. * modified test case to adapt changes made to the GravitoIdSystem user module * change to spec file to fix for test failure * changes to GravitoIdSystem spec file. * Fix for trailing space issue in Circle CI --- modules/gravitoIdSystem.js | 7 +++---- test/spec/modules/gravitoIdSystem_spec.js | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/gravitoIdSystem.js b/modules/gravitoIdSystem.js index 30fa3abd6d2..809263a1c68 100644 --- a/modules/gravitoIdSystem.js +++ b/modules/gravitoIdSystem.js @@ -39,19 +39,18 @@ export const gravitoIdSystemSubmodule = { * decode the stored id value for passing to bid requests * @function * @param { {gravitompId: string} } value - * @returns { {gravitompId: {id: string} } | undefined } + * @returns { {gravitompId: {string} } | undefined } */ decode: function(value) { if (value && typeof value === 'object') { - const result = {}; + var result = {}; if (value.gravitompId) { - result.id = value.gravitompId + result = value.gravitompId } return {gravitompId: result}; } return undefined; }, - } submodule('userId', gravitoIdSystemSubmodule); diff --git a/test/spec/modules/gravitoIdSystem_spec.js b/test/spec/modules/gravitoIdSystem_spec.js index e904355f7f1..9584f60c81d 100644 --- a/test/spec/modules/gravitoIdSystem_spec.js +++ b/test/spec/modules/gravitoIdSystem_spec.js @@ -40,7 +40,7 @@ describe('gravitompId module', function () { describe('decode()', function () { it('should return the gravitompId when it exists in cookie', function () { const decoded = gravitoIdSystemSubmodule.decode(GRAVITOID_TEST_OBJ); - expect(decoded).to.be.deep.equal({gravitompId: {id: GRAVITOID_TEST_VALUE}}); + expect(decoded).to.be.deep.equal({gravitompId: GRAVITOID_TEST_VALUE}); }); it('should return the undefined when decode id is not "string"', function () { From 1a5f5ffd04adc422d443d643f3f70bc95b4382df Mon Sep 17 00:00:00 2001 From: Fatih Kaya Date: Mon, 21 Nov 2022 18:52:59 +0300 Subject: [PATCH 135/367] AdMatic Bidder: added User-Snyc url for alias (#9261) * Admatic Bidder Adaptor * Update admaticBidAdapter.md * Update admaticBidAdapter.md * remove floor parameter * Update admaticBidAdapter.js * Admatic Bid Adapter: alias and bid floor features activated * Admatic adapter: host param control changed * Alias name changed. * Revert "Admatic adapter: host param control changed" This reverts commit de7ac85981b1ba3ad8c5d1dc95c5dadbdf5b9895. * added alias feature and host param * Revert "added alias feature and host param" This reverts commit 6ec8f4539ea6be403a0d7e08dad5c7a5228f28a1. * Revert "Alias name changed." This reverts commit 661c54f9b2397e8f25c257144d73161e13466281. * Revert "Admatic Bid Adapter: alias and bid floor features activated" This reverts commit 7a2e0e29c49e2f876b68aafe886b336fe2fe6fcb. * Revert "Update admaticBidAdapter.js" This reverts commit 7a845b7151bbb08addfb58ea9bd5b44167cc8a4e. * Revert "remove floor parameter" This reverts commit 7a23b055ccd4ea23d23e73248e82b21bc6f69d90. * Admatic adapter: host param control && Add new Bidder * Revert "Admatic adapter: host param control && Add new Bidder" This reverts commit 3c797b120c8e0fe2b851381300ac5c4b1f92c6e2. * commit new features * Update admaticBidAdapter.js * updated for coverage * sync updated * Update adloader.js * AdMatic Bidder: development of user sync url * Update admaticBidAdapter.js --- modules/admaticBidAdapter.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/admaticBidAdapter.js b/modules/admaticBidAdapter.js index ec4401b77c9..148424c0a98 100644 --- a/modules/admaticBidAdapter.js +++ b/modules/admaticBidAdapter.js @@ -1,7 +1,7 @@ import { getValue, logError, deepAccess, getBidIdParameter, isArray } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; -const SYNC_URL = 'https://cdn.serve.admatic.com.tr/showad/sync.html'; +let SYNC_URL = ''; const BIDDER_CODE = 'admatic'; export const spec = { code: BIDDER_CODE, @@ -59,6 +59,15 @@ export const spec = { }; if (payload) { + switch (bidderName) { + case 'pixad': + SYNC_URL = 'https://static.pixad.com.tr/sync.html'; + break; + default: + SYNC_URL = 'https://cdn.serve.admatic.com.tr/showad/sync.html'; + break; + } + return { method: 'POST', url: `https://${host}/pb?bidder=${bidderName}`, data: payload, options: { contentType: 'application/json' } }; } }, From f5fdcf095ee1be64b437a2ac3e4191af2aa3d44b Mon Sep 17 00:00:00 2001 From: Omer Dotan <54346241+omerBrowsi@users.noreply.github.com> Date: Mon, 21 Nov 2022 20:03:57 +0200 Subject: [PATCH 136/367] Browsi RTD Module: add pageview billable event (#9207) * real time data module, browsi sub module for real time data, new hook bidsBackCallback, fix for config unsubscribe * change timeout&primary ad server only to auctionDelay update docs * support multiple providers * change promise to callbacks configure submodule on submodules.json * bug fixes * use Prebid ajax * tests fix * browsi real time data provider improvements * real time data module, browsi sub module for real time data, new hook bidsBackCallback, fix for config unsubscribe * change timeout&primary ad server only to auctionDelay update docs * support multiple providers * change promise to callbacks configure submodule on submodules.json * bug fixes * use Prebid ajax * tests fix * browsi real time data provider improvements * fire billable event according to event listener --- modules/browsiRtdProvider.js | 10 ++++++---- test/spec/modules/browsiRtdProvider_spec.js | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/browsiRtdProvider.js b/modules/browsiRtdProvider.js index 0996fc9905b..31b2d709f35 100644 --- a/modules/browsiRtdProvider.js +++ b/modules/browsiRtdProvider.js @@ -59,10 +59,12 @@ export function addBrowsiTag(data) { export function sendPageviewEvent(eventType) { if (eventType === 'PAGEVIEW') { - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { - vendor: 'browsi', - type: 'pageview', - billingId: generateUUID() + window.addEventListener('browsi_pageview', () => { + events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + vendor: 'browsi', + type: 'pageview', + billingId: generateUUID() + }) }) } } diff --git a/test/spec/modules/browsiRtdProvider_spec.js b/test/spec/modules/browsiRtdProvider_spec.js index 19483047827..75120aa7505 100644 --- a/test/spec/modules/browsiRtdProvider_spec.js +++ b/test/spec/modules/browsiRtdProvider_spec.js @@ -252,7 +252,8 @@ describe('browsi Real time data sub module', function () { }) it('should send event if type is correct', function () { sendPageviewEvent('PAGEVIEW') - + const pageViewEvent = new CustomEvent('browsi_pageview', {}); + window.dispatchEvent(pageViewEvent); const expectedCall = { vendor: 'browsi', type: 'pageview', From d6418a04f9913ee732114f4926f490094f765c9f Mon Sep 17 00:00:00 2001 From: Piotr Jaworski <109736938+piotrj-rtbh@users.noreply.github.com> Date: Mon, 21 Nov 2022 21:10:19 +0100 Subject: [PATCH 137/367] RTB House Bid Adapter: Process FLEDGE request/response (#9215) * RTBHouse Bid Adapter: add global vendor list id * structured user agent - browsers.brands * fix lint errors * Added sda into rtbhouse adapter * spreading ortb2: user & site props * examples reverted * init version * using mergedeep * removed wrong imp array augm.; slot imp augm. with addtl check * [SUA] merging ortb2.device into request * fledge auctionConfig adapted to our bid response structure * new bidder response structure for fledge * make sure bidderRequest has proper flag turned on * fledge endpoint hardcoded; code cleanups * remove obsolete function * obsolete function removed * [RTB House] Process FLEDGE request/response (#4) * [SDA & SUA] refactor using mergedeep * [FLEDGE] fledge auctionConfig adapted to our bid response structure * [FLEDGE] new bidder response structure for fledge * [FLEDGE] make sure bidderRequest has proper flag turned on * [FLEDGE] fledge endpoint hardcoded; code cleanups * [FLEDGE] remove obsolete functions * fixed lint errors * fledge test suites; adapter: delete imp.ext.ae when no fledge (#5) Co-authored-by: Leandro Otani Co-authored-by: rtbh-lotani <83652735+rtbh-lotani@users.noreply.github.com> Co-authored-by: Tomasz Swirski --- modules/rtbhouseBidAdapter.js | 119 ++++++++++++++----- test/spec/modules/rtbhouseBidAdapter_spec.js | 79 ++++++++++++ 2 files changed, 169 insertions(+), 29 deletions(-) diff --git a/modules/rtbhouseBidAdapter.js b/modules/rtbhouseBidAdapter.js index fdf64483da7..9f498014a8e 100644 --- a/modules/rtbhouseBidAdapter.js +++ b/modules/rtbhouseBidAdapter.js @@ -1,13 +1,15 @@ -import {deepAccess, isArray, logError} from '../src/utils.js'; +import {deepAccess, mergeDeep, isArray, logError, logInfo} from '../src/utils.js'; import { getOrigin } from '../libraries/getOrigin/index.js'; import {BANNER, NATIVE} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {includes} from '../src/polyfill.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'rtbhouse'; const REGIONS = ['prebid-eu', 'prebid-us', 'prebid-asia']; const ENDPOINT_URL = 'creativecdn.com/bidder/prebid/bids'; +const FLEDGE_ENDPOINT_URL = 'creativecdn.com/bidder/prebidfledge/bids'; const DEFAULT_CURRENCY_ARR = ['USD']; // NOTE - USD is the only supported currency right now; Hardcoded for bids const SUPPORTED_MEDIA_TYPES = [BANNER, NATIVE]; const TTL = 55; @@ -50,12 +52,13 @@ export const spec = { const request = { id: validBidRequests[0].auctionId, - imp: validBidRequests.map(slot => mapImpression(slot)), + imp: validBidRequests.map(slot => mapImpression(slot, bidderRequest)), site: mapSite(validBidRequests, bidderRequest), cur: DEFAULT_CURRENCY_ARR, test: validBidRequests[0].params.test || 0, source: mapSource(validBidRequests[0]), }; + if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { const consentStr = (bidderRequest.gdprConsent.consentString) ? bidderRequest.gdprConsent.consentString.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') : ''; @@ -81,37 +84,32 @@ export const spec = { } } - const ortb2Params = bidderRequest && bidderRequest.ortb2; - if (ortb2Params?.user) { - request.user = { - ...request.user, - ...(ortb2Params.user.data && { - data: { ...request.user?.data, ...ortb2Params.user.data }, - }), - ...(ortb2Params.user.ext && { - ext: { ...request.user?.ext, ...ortb2Params.user.ext }, - }), - }; + const ortb2Params = bidderRequest?.ortb2 || {}; + if (ortb2Params.site) { + mergeDeep(request, { site: ortb2Params.site }); + } + if (ortb2Params.user) { + mergeDeep(request, { user: ortb2Params.user }); + } + if (ortb2Params.device) { + mergeDeep(request, { device: ortb2Params.device }); } - if (ortb2Params?.site) { - request.site = { - ...request.site, - ...(ortb2Params.site.content && { - content: { ...request.site?.content, ...ortb2Params.site.content }, - }), - ...(ortb2Params.site.ext && { - ext: { ...request.site?.ext, ...ortb2Params.site.ext }, - }), - }; + + let computedEndpointUrl = ENDPOINT_URL; + + const fledgeConfig = config.getConfig('fledgeConfig'); + if (bidderRequest.fledgeEnabled && fledgeConfig) { + mergeDeep(request, { ext: { fledge_config: fledgeConfig } }); + computedEndpointUrl = FLEDGE_ENDPOINT_URL; } return { method: 'POST', - url: 'https://' + validBidRequests[0].params.region + '.' + ENDPOINT_URL, + url: 'https://' + validBidRequests[0].params.region + '.' + computedEndpointUrl, data: JSON.stringify(request) }; }, - interpretResponse: function (serverResponse, originalRequest) { + interpretOrtbResponse: function (serverResponse, originalRequest) { const responseBody = serverResponse.body; if (!isArray(responseBody)) { return []; @@ -119,17 +117,72 @@ export const spec = { const bids = []; responseBody.forEach(serverBid => { - if (serverBid.price === 0) { + if (!serverBid.price) { // price may exist and is === 0 or there's no price prop at all (fledge req case) return; } + + let interpretedBid; + // try...catch would be risky cause JSON.parse throws SyntaxError if (serverBid.adm.indexOf('{') === 0) { - bids.push(interpretNativeBid(serverBid)); + interpretedBid = interpretNativeBid(serverBid); } else { - bids.push(interpretBannerBid(serverBid)); + interpretedBid = interpretBannerBid(serverBid); } + if (serverBid.ext) interpretedBid.ext = serverBid.ext; + + bids.push(interpretedBid); }); return bids; + }, + interpretResponse: function (serverResponse, originalRequest) { + let bids; + + const responseBody = serverResponse.body; + let fledgeAuctionConfigs = null; + + if (responseBody.bidid && isArray(responseBody?.ext?.igbid)) { + // we have fledge response + // mimic the original response ([{},...]) + bids = this.interpretOrtbResponse({ body: responseBody.seatbid[0]?.bid }, originalRequest); + + const seller = responseBody.ext.seller; + const decisionLogicUrl = responseBody.ext.decisionLogicUrl; + const sellerTimeout = 'sellerTimeout' in responseBody.ext ? { sellerTimeout: responseBody.ext.sellerTimeout } : {}; + responseBody.ext.igbid.forEach((igbid) => { + const perBuyerSignals = {}; + igbid.igbuyer.forEach(buyerItem => { + perBuyerSignals[buyerItem.igdomain] = buyerItem.buyersignal + }); + fledgeAuctionConfigs = fledgeAuctionConfigs || {}; + fledgeAuctionConfigs[igbid.impid] = mergeDeep( + { + seller, + decisionLogicUrl, + interestGroupBuyers: Object.keys(perBuyerSignals), + perBuyerSignals, + }, + sellerTimeout + ); + }); + } else { + bids = this.interpretOrtbResponse(serverResponse, originalRequest); + } + + if (fledgeAuctionConfigs) { + fledgeAuctionConfigs = Object.entries(fledgeAuctionConfigs).map(([bidId, cfg]) => { + return Object.assign({ + bidId, + auctionSignals: {} + }, cfg); + }); + logInfo('Response with FLEDGE:', { bids, fledgeAuctionConfigs }); + return { + bids, + fledgeAuctionConfigs, + } + } + return bids; } }; registerBidder(spec); @@ -154,7 +207,7 @@ function applyFloor(slot) { * @param {object} slot Ad Unit Params by Prebid * @returns {object} Imp by OpenRTB 2.5 §3.2.4 */ -function mapImpression(slot) { +function mapImpression(slot, bidderRequest) { const imp = { id: slot.bidId, banner: mapBanner(slot), @@ -167,6 +220,14 @@ function mapImpression(slot) { imp.bidfloor = bidfloor; } + if (bidderRequest.fledgeEnabled) { + imp.ext = imp.ext || {}; + imp.ext.ae = slot?.ortb2Imp?.ext?.ae + } else { + if (imp.ext?.ae) { + delete imp.ext.ae; + } + } return imp; } diff --git a/test/spec/modules/rtbhouseBidAdapter_spec.js b/test/spec/modules/rtbhouseBidAdapter_spec.js index f4bcb48474a..6d41df7605b 100644 --- a/test/spec/modules/rtbhouseBidAdapter_spec.js +++ b/test/spec/modules/rtbhouseBidAdapter_spec.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { OPENRTB, spec } from 'modules/rtbhouseBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; +import { config } from 'src/config.js'; describe('RTBHouseAdapter', () => { const adapter = newBidder(spec); @@ -97,6 +98,10 @@ describe('RTBHouseAdapter', () => { ]; }); + afterEach(function () { + config.resetConfig(); + }); + it('should build test param into the request', () => { let builtTestRequest = spec.buildRequests(bidRequests, bidderRequest).data; expect(JSON.parse(builtTestRequest).test).to.equal(1); @@ -263,6 +268,45 @@ describe('RTBHouseAdapter', () => { expect(data.source).to.not.have.property('ext'); }); + context('FLEDGE', function() { + afterEach(function () { + config.resetConfig(); + }); + + it('sends bid request to FLEDGE ENDPOINT via POST', function () { + let bidRequest = Object.assign([], bidRequests); + delete bidRequest[0].params.test; + config.setConfig({ fledgeConfig: true }); + const request = spec.buildRequests(bidRequest, { ...bidderRequest, fledgeEnabled: true }); + expect(request.url).to.equal('https://prebid-eu.creativecdn.com/bidder/prebidfledge/bids'); + expect(request.method).to.equal('POST'); + }); + + it('when FLEDGE is disabled, should not send imp.ext.ae', function () { + let bidRequest = Object.assign([], bidRequests); + delete bidRequest[0].params.test; + bidRequest[0].ortb2Imp = { + ext: { ae: 2 } + }; + const request = spec.buildRequests(bidRequest, { ...bidderRequest, fledgeEnabled: false }); + let data = JSON.parse(request.data); + if (data.imp[0].ext) { + expect(data.imp[0].ext).to.not.have.property('ae'); + } + }); + + it('when FLEDGE is enabled, should send whatever is set in ortb2imp.ext.ae in all bid requests', function () { + let bidRequest = Object.assign([], bidRequests); + delete bidRequest[0].params.test; + bidRequest[0].ortb2Imp = { + ext: { ae: 2 } + }; + const request = spec.buildRequests(bidRequest, { ...bidderRequest, fledgeEnabled: true }); + let data = JSON.parse(request.data); + expect(data.imp[0].ext.ae).to.equal(2); + }); + }); + describe('native imp', () => { function basicRequest(extension) { return Object.assign({ @@ -460,6 +504,29 @@ describe('RTBHouseAdapter', () => { 'h': 250 }]; + let fledgeResponse = { + 'id': 'bid-identifier', + 'ext': { + 'igbid': [{ + 'impid': 'test-bid-id', + 'igbuyer': [{ + 'igdomain': 'https://buyer-domain.com', + 'buyersignal': {} + }] + }], + 'sellerTimeout': 500, + 'seller': 'https://seller-domain.com', + 'decisionLogicUrl': 'https://seller-domain.com/decision-logic.js' + }, + 'bidid': 'bid-identifier', + 'seatbid': [{ + 'bid': [{ + 'id': 'bid-response-id', + 'impid': 'test-bid-id' + }] + }] + }; + it('should get correct bid response', function () { let expectedResponse = [ { @@ -488,6 +555,18 @@ describe('RTBHouseAdapter', () => { expect(result.length).to.equal(0); }); + context('when the response contains FLEDGE interest groups config', function () { + let bidderRequest; + let response = spec.interpretResponse({body: fledgeResponse}, {bidderRequest}); + + it('should return FLEDGE auction_configs alongside bids', function () { + expect(response).to.have.property('bids'); + expect(response).to.have.property('fledgeAuctionConfigs'); + expect(response.fledgeAuctionConfigs.length).to.equal(1); + expect(response.fledgeAuctionConfigs[0].bidId).to.equal('test-bid-id'); + }); + }); + describe('native', () => { const adm = { native: { From 3d1174bca579f6e01e7187cb82c9d91fff0cc7ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Nov 2022 04:35:05 -0700 Subject: [PATCH 138/367] Bump engine.io from 6.2.0 to 6.2.1 (#9270) Bumps [engine.io](https://github.com/socketio/engine.io) from 6.2.0 to 6.2.1. - [Release notes](https://github.com/socketio/engine.io/releases) - [Changelog](https://github.com/socketio/engine.io/blob/main/CHANGELOG.md) - [Commits](https://github.com/socketio/engine.io/compare/6.2.0...6.2.1) --- updated-dependencies: - dependency-name: engine.io dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4584231d42c..2ed7cf9067e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8885,9 +8885,9 @@ } }, "node_modules/engine.io": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", - "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", + "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", "dev": true, "dependencies": { "@types/cookie": "^0.4.1", @@ -32089,9 +32089,9 @@ } }, "engine.io": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", - "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", + "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", "dev": true, "requires": { "@types/cookie": "^0.4.1", From 616d957bacc18d4764a82061cf5e44696d62bc8b Mon Sep 17 00:00:00 2001 From: lasloche <62240785+lasloche@users.noreply.github.com> Date: Tue, 22 Nov 2022 13:43:17 +0200 Subject: [PATCH 139/367] Rise readme maintenance (#9272) --- modules/minutemediaBidAdapter.md | 6 +++--- modules/riseBidAdapter.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/minutemediaBidAdapter.md b/modules/minutemediaBidAdapter.md index 70f106a745f..66b54adaf0e 100644 --- a/modules/minutemediaBidAdapter.md +++ b/modules/minutemediaBidAdapter.md @@ -20,7 +20,7 @@ The adapter supports Video(instream) & Banner. | Name | Scope | Type | Description | Example | ---- | ----- | ---- | ----------- | ------- -| `org` | required | String | MinuteMedia publisher Id provided by your MinuteMedia representative | "56f91cd4d3e3660002000033" +| `org` | required | String | MinuteMedia publisher Id provided by your MinuteMedia representative | "1234567890abcdef12345678" | `floorPrice` | optional | Number | Minimum price in USD. Misuse of this parameter can impact revenue | 2.00 | `placementId` | optional | String | A unique placement identifier | "12345678" | `testMode` | optional | Boolean | This activates the test mode | false @@ -43,7 +43,7 @@ var adUnits = [{ bids: [{ bidder: 'minutemedia', params: { - org: '56f91cd4d3e3660002000033', // Required + org: '1234567890abcdef12345678', // Required floorPrice: 2.00, // Optional placementId: 'video-test', // Optional testMode: false // Optional @@ -65,7 +65,7 @@ var adUnits = [{ bids: [{ bidder: 'minutemedia', params: { - org: '56f91cd4d3e3660002000033', // Required + org: '1234567890abcdef12345678', // Required floorPrice: 2.00, // Optional placementId: 'banner-test', // Optional testMode: false // Optional diff --git a/modules/riseBidAdapter.md b/modules/riseBidAdapter.md index 2920fd28528..9dab3ec2a30 100644 --- a/modules/riseBidAdapter.md +++ b/modules/riseBidAdapter.md @@ -20,7 +20,7 @@ The adapter supports Video(instream). | Name | Scope | Type | Description | Example | ---- | ----- | ---- | ----------- | ------- -| `org` | required | String | Rise publisher Id provided by your Rise representative | "56f91cd4d3e3660002000033" +| `org` | required | String | Rise publisher Id provided by your Rise representative | "1234567890abcdef12345678" | `floorPrice` | optional | Number | Minimum price in USD. Misuse of this parameter can impact revenue | 2.00 | `placementId` | optional | String | A unique placement identifier | "12345678" | `testMode` | optional | Boolean | This activates the test mode | false @@ -41,10 +41,10 @@ var adUnits = [ bids: [{ bidder: 'rise', params: { - org: '56f91cd4d3e3660002000033', // Required + org: '1234567890abcdef12345678', // Required floorPrice: 2.00, // Optional placementId: '12345678', // Optional - testMode: false // Optional, + testMode: false, // Optional, rtbDomain: "www.test.com" //Optional } }] From 3e5f08635b965cfbc5384b9735f0797757cedad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9onard=20Labat?= Date: Tue, 22 Nov 2022 18:03:07 +0100 Subject: [PATCH 140/367] Criteo Bid Adapter : fix getFloor usage issue (#9243) getFloor call context is loss when we reference it as a callback ; we need to make sure that it is properly mapped as getFloor function assumes that "this" is the actual bid request object --- modules/criteoBidAdapter.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index c0251ab0165..5567103db69 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -672,18 +672,18 @@ function enrichSlotWithFloors(slot, bidRequest) { if (bidRequest.mediaTypes?.banner) { slotFloors.banner = {}; const bannerSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes')) - bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = getFloor({ size: bannerSize, mediaType: BANNER })); + bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = getFloor.call(bidRequest, { size: bannerSize, mediaType: BANNER })); } if (bidRequest.mediaTypes?.video) { slotFloors.video = {}; const videoSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize')) - videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = getFloor({ size: videoSize, mediaType: VIDEO })); + videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = getFloor.call(bidRequest, { size: videoSize, mediaType: VIDEO })); } if (bidRequest.mediaTypes?.native) { slotFloors.native = {}; - slotFloors.native['*'] = getFloor({ size: '*', mediaType: NATIVE }); + slotFloors.native['*'] = getFloor.call(bidRequest, { size: '*', mediaType: NATIVE }); } if (Object.keys(slotFloors).length > 0) { From 690c0d63f7455475cd8d0fc773dbdfa7f40fa7d1 Mon Sep 17 00:00:00 2001 From: OronW <41260031+OronW@users.noreply.github.com> Date: Tue, 22 Nov 2022 20:17:24 +0200 Subject: [PATCH 141/367] Rise Bid Adapter: add support for mimes, api, protocols in bid object (#9253) * added support to mimes, api and protocols based on bid settings * moved protocols only if object is video * updated path for protocols property * added unit test for api, mimes and protocols properties --- modules/riseBidAdapter.js | 15 +++++++++++++++ test/spec/modules/riseBidAdapter_spec.js | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/modules/riseBidAdapter.js b/modules/riseBidAdapter.js index c1360b79066..4325a699a3b 100644 --- a/modules/riseBidAdapter.js +++ b/modules/riseBidAdapter.js @@ -309,6 +309,16 @@ function generateBidParameters(bid, bidderRequest) { bidObject.placementId = placementId; } + const mimes = deepAccess(bid, `mediaTypes.${mediaType}.mimes`); + if (mimes) { + bidObject.mimes = mimes; + } + + const api = deepAccess(bid, `mediaTypes.${mediaType}.api`); + if (api) { + bidObject.api = api; + } + if (mediaType === VIDEO) { const playbackMethod = deepAccess(bid, `mediaTypes.video.playbackmethod`); let playbackMethodValue; @@ -349,6 +359,11 @@ function generateBidParameters(bid, bidderRequest) { if (linearity) { bidObject.linearity = linearity; } + + const protocols = deepAccess(bid, `mediaTypes.video.protocols`); + if (protocols) { + bidObject.protocols = protocols; + } } return bidObject; diff --git a/test/spec/modules/riseBidAdapter_spec.js b/test/spec/modules/riseBidAdapter_spec.js index 7daedb9015a..37100073407 100644 --- a/test/spec/modules/riseBidAdapter_spec.js +++ b/test/spec/modules/riseBidAdapter_spec.js @@ -106,6 +106,9 @@ describe('riseAdapter', function () { bidderCode: 'rise', } const placementId = '12345678'; + const api = [1, 2]; + const mimes = ['application/javascript', 'video/mp4', 'video/quicktime']; + const protocols = [2, 3, 5, 6]; it('sends the placementId to ENDPOINT via POST', function () { bidRequests[0].params.placementId = placementId; @@ -144,6 +147,27 @@ describe('riseAdapter', function () { expect(request.data.bids[0].bidId).to.equal('299ffc8cca0b87'); }); + it('should send the correct supported api array', function () { + bidRequests[0].mediaTypes.video.api = api; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.bids[0].api).to.be.an('array'); + expect(request.data.bids[0].api).to.eql([1, 2]); + }); + + it('should send the correct mimes array', function () { + bidRequests[1].mediaTypes.banner.mimes = mimes; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.bids[1].mimes).to.be.an('array'); + expect(request.data.bids[1].mimes).to.eql(['application/javascript', 'video/mp4', 'video/quicktime']); + }); + + it('should send the correct protocols array', function () { + bidRequests[0].mediaTypes.video.protocols = protocols; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.bids[0].protocols).to.be.an('array'); + expect(request.data.bids[0].protocols).to.eql([2, 3, 5, 6]); + }); + it('should send the correct sizes array', function () { const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data.bids[0].sizes).to.be.an('array'); From 5b0bb17d98137a2c38b7dceb8fc1bd291ef999e8 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 22 Nov 2022 12:23:20 -0700 Subject: [PATCH 142/367] Prebid core: fix CPM to always be a number (#9273) --- src/auction.js | 2 +- test/spec/auctionmanager_spec.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/auction.js b/src/auction.js index 09fb275afdb..6376457c1d6 100644 --- a/src/auction.js +++ b/src/auction.js @@ -672,7 +672,7 @@ function addCommonResponseProperties(bidResponse, adUnitCode, {index = auctionMa Object.assign(bidResponse, { responseTimestamp: bidResponse.responseTimestamp || timestamp(), requestTimestamp: bidResponse.requestTimestamp || start, - cpm: bidResponse.cpm || parseFloat(bidResponse.cpm) || 0, + cpm: parseFloat(bidResponse.cpm) || 0, bidder: bidResponse.bidder || bidResponse.bidderCode, adUnitCode }); diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index 47bdd4a3772..443147f5d20 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -1464,6 +1464,15 @@ describe('auctionmanager.js', function () { assert.equal(doneSpy.callCount, 1); }); + it('should convert cpm to number', () => { + auction.addBidReceived = sinon.spy(); + const cbs = auctionCallbacks(doneSpy, auction); + const bid = {...bids[0], cpm: '1.23'} + bidRequests = [mockBidRequest(bid)]; + cbs.addBidResponse.call(bidRequests[0], ADUNIT_CODE, bid); + sinon.assert.calledWith(auction.addBidReceived, sinon.match({cpm: 1.23})); + }) + describe('when addBidResponse hook returns promises', () => { let resolvers, callbacks, bids; @@ -1605,6 +1614,7 @@ describe('auctionmanager.js', function () { ]; cbs = auctionCallbacks(doneSpy, auction); expectedRejection = sinon.match(Object.assign({}, bid, { + cpm: parseFloat(bid.cpm), rejectionReason: REJECTION_REASON, adUnitCode: AU_CODE })); From 737646f9f77f18952fd228e1114f0ed2b6e229c2 Mon Sep 17 00:00:00 2001 From: Gabriel Chicoye Date: Thu, 24 Nov 2022 11:49:58 +0100 Subject: [PATCH 143/367] nexx360 Bid Adapter: new functionalities and endpoint update (#9229) * bidder version v1.0 * Comments removed * Test coverage improvement above 80% --- modules/nexx360BidAdapter.js | 402 ++++++++---- test/spec/modules/nexx360BidAdapter_spec.js | 662 +++++++++++++------- 2 files changed, 705 insertions(+), 359 deletions(-) diff --git a/modules/nexx360BidAdapter.js b/modules/nexx360BidAdapter.js index ed0c0c66a7a..ff4ca77aac2 100644 --- a/modules/nexx360BidAdapter.js +++ b/modules/nexx360BidAdapter.js @@ -1,176 +1,302 @@ -import {ajax} from '../src/ajax.js'; import {config} from '../src/config.js'; -import { transformBidderParamKeywords } from '../src/utils.js'; +import * as utils from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {getGlobal} from '../src/prebidGlobal.js'; +const VIDEO_TARGETING = ['startdelay', 'mimes', 'minduration', 'maxduration', 'delivery', + 'startdelay', 'skip', 'playbackmethod', 'api', 'protocol', 'boxingallowed', 'maxextended', + 'linearity', 'delivery', 'protocols', 'placement', 'minbitrate', 'maxbitrate', 'battr', 'ext']; const BIDDER_CODE = 'nexx360'; -const BIDDER_URL = 'https://fast.nexx360.io/prebid'; -const CACHE_URL = 'https://fast.nexx360.io/cache'; -const METRICS_TRACKER_URL = 'https://fast.nexx360.io/track-imp'; +const REQUEST_URL = 'https://fast.nexx360.io/booster'; + +const PAGE_VIEW_ID = utils.generateUUID(); + +const BIDDER_VERSION = '1.0'; const GVLID = 965; export const spec = { code: BIDDER_CODE, gvlid: GVLID, - aliases: ['revenuemaker'], // short code + aliases: [ + { code: 'revenuemaker' }, + { code: 'firstid-ssp' }, + ], supportedMediaTypes: [BANNER, VIDEO], - /** + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs, + // onBidWon, +}; + +registerBidder(spec); + +/** * Determines whether or not the given bid request is valid. * * @param {BidRequest} bid The bid params to validate. * @return boolean True if this is a valid bid, and false otherwise. */ - isBidRequestValid: function(bid) { - if (!!bid.params.bidfloorCurrency && !['EUR', 'USD'].includes(bid.params.bidfloorCurrency)) return false; - if (!!bid.params.bidfloor && typeof bid.params.bidfloor !== 'number') return false; - if (!!bid.params.keywords && typeof bid.params.keywords !== 'object') return false; - return !!(bid.params.account && bid.params.tagId); - }, - /** +function isBidRequestValid(bid) { + return !!bid.params.tagId || !!bid.params.videoTagId; +}; + +/** * 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 adUnits = []; - const test = config.getConfig('debug') ? 1 : 0; - let adunitValue = null; - let userEids = null; - Object.keys(validBidRequests).forEach(key => { - adunitValue = validBidRequests[key]; - const foo = { - account: adunitValue.params.account, - tagId: adunitValue.params.tagId, - videoExt: adunitValue.params.videoExt, - label: adunitValue.adUnitCode, - bidId: adunitValue.bidId, - auctionId: adunitValue.auctionId, - transactionId: adunitValue.transactionId, - mediatypes: adunitValue.mediaTypes, - bidfloor: adunitValue.params.bidfloor || 0, - bidfloorCurrency: adunitValue.params.bidfloorCurrency || 'USD', - keywords: adunitValue.params.keywords ? transformBidderParamKeywords(adunitValue.params.keywords) : [], + +function buildRequests(bids, bidderRequest) { + const data = getBaseRequest(bids[0], bidderRequest); + bids.forEach((bid) => { + const impObject = createImpObject(bid); + if (isBannerBid(bid)) impObject.banner = getBannerObject(bid); + if (isVideoBid(bid)) impObject.video = getVideoObject(bid); + data.imp.push(impObject); + }); + return { + method: 'POST', + url: REQUEST_URL, + data, + } +} + +function createImpObject(bid) { + const floor = getFloor(bid, BANNER); + const imp = { + id: bid.bidId, + tagid: bid.adUnitCode, + ext: { + divId: bid.adUnitCode, + nexx360: { + videoTagId: bid.params.videoTagId, + tagId: bid.params.tagId, + allBids: bid.params.allBids === true, } - adUnits.push(foo); - if (adunitValue.userIdAsEids) userEids = adunitValue.userIdAsEids; + } + }; + if (bid.params.customParams) { + utils.deepSetValue(imp, 'ext.customParams', bid.params.customParams); + } + enrichImp(imp, bid, floor); + return imp; +} + +function getBannerObject(bid) { + return { + format: toFormat(bid.mediaTypes.banner.sizes), + topframe: utils.inIframe() ? 0 : 1 + }; +} + +function getVideoObject(bid) { + let width, height; + const videoParams = utils.deepAccess(bid, `mediaTypes.video`); + const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize'); + const context = utils.deepAccess(bid, 'mediaTypes.video.context'); + // normalize config for video size + if (utils.isArray(bid.sizes) && bid.sizes.length === 2 && !utils.isArray(bid.sizes[0])) { + width = parseInt(bid.sizes[0], 10); + height = parseInt(bid.sizes[1], 10); + } else if (utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0]) && bid.sizes[0].length === 2) { + width = parseInt(bid.sizes[0][0], 10); + height = parseInt(bid.sizes[0][1], 10); + } else if (utils.isArray(playerSize) && playerSize.length === 2) { + width = parseInt(playerSize[0], 10); + height = parseInt(playerSize[1], 10); + } + const video = { + playerSize: [height, width], + context, + }; + + Object.keys(videoParams) + .filter(param => VIDEO_TARGETING.includes(param)) + .forEach(param => video[param] = videoParams[param]); + return video; +} + +function isVideoBid(bid) { + return utils.deepAccess(bid, 'mediaTypes.video'); +} + +function isBannerBid(bid) { + return utils.deepAccess(bid, 'mediaTypes.banner') || !isVideoBid(bid); +} + +function toFormat(sizes) { + return sizes.map((s) => { + return { w: s[0], h: s[1] }; + }); +} + +function getFloor(bid, mediaType) { + let floor = 0; + if (typeof bid.getFloor === 'function') { + const floorInfo = bid.getFloor({ + currency: 'USD', + mediaType: mediaType, + size: '*' }); - const payload = { - adUnits, - // TODO: does the fallback make sense here? - href: encodeURIComponent(bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation) - }; - if (bidderRequest) { // modules informations (gdpr, ccpa, schain, userId) - if (bidderRequest.gdprConsent) { - payload.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; - payload.gdprConsent = bidderRequest.gdprConsent.consentString; - } else { - payload.gdpr = 0; - payload.gdprConsent = ''; - } - if (bidderRequest.uspConsent) { payload.uspConsent = bidderRequest.uspConsent; } - if (bidderRequest.schain) { payload.schain = bidderRequest.schain; } - if (userEids !== null) payload.userEids = userEids; - }; - if (test) payload.test = 1; - const payloadString = JSON.stringify(payload); - return { - method: 'POST', - url: BIDDER_URL, - data: payloadString, - }; - }, - /** + + if (typeof floorInfo === 'object' && + floorInfo.currency === 'USD' && + !isNaN(parseFloat(floorInfo.floor))) { + floor = Math.max(floor, parseFloat(floorInfo.floor)); + } + } + + return floor; +} + +function enrichImp(imp, bid, floor) { + if (bid.params.customParams) { + utils.deepSetValue(imp, 'ext.customParams', bid.params.customParams); + } + if (floor > 0) { + imp.bidfloor = floor; + imp.bidfloorcur = 'USD'; + } else if (bid.params.customFloor) { + imp.bidfloor = bid.params.customFloor; + } + if (bid.ortb2Imp && bid.ortb2Imp.ext && bid.ortb2Imp.ext.data) { + imp.ext.data = bid.ortb2Imp.ext.data; + } +} + +function getBaseRequest(bid, bidderRequest) { + let req = { + id: bidderRequest.auctionId, + imp: [], + cur: [config.getConfig('currency.adServerCurrency') || 'USD'], + at: 1, + tmax: config.getConfig('bidderTimeout'), + site: { + page: bidderRequest.refererInfo.topmostLocation || bidderRequest.refererInfo.page, + domain: bidderRequest.refererInfo.domain, + }, + regs: { + coppa: (config.getConfig('coppa') === true || bid.params.coppa) ? 1 : 0, + }, + device: { + dnt: (utils.getDNT() || bid.params.doNotTrack) ? 1 : 0, + h: screen.height, + w: screen.width, + ua: window.navigator.userAgent, + language: window.navigator.language.split('-').shift() + }, + user: {}, + ext: { + source: 'prebid.js', + version: '$prebid.version$', + pageViewId: PAGE_VIEW_ID, + bidderVersion: BIDDER_VERSION, + } + }; + + if (bid.params.platform) { + utils.deepSetValue(req, 'ext.platform', bid.params.platform); + } + if (bid.params.response_template_name) { + utils.deepSetValue(req, 'ext.response_template_name', bid.params.response_template_name); + } + req.test = config.getConfig('debug') ? 1 : 0; + if (bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.gdprApplies !== undefined) { + utils.deepSetValue(req, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies === true ? 1 : 0); + } + if (bidderRequest.gdprConsent.consentString !== undefined) { + utils.deepSetValue(req, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + if (bidderRequest.gdprConsent.addtlConsent !== undefined) { + utils.deepSetValue(req, 'user.ext.ConsentedProvidersSettings.consented_providers', bidderRequest.gdprConsent.addtlConsent); + } + } + if (bidderRequest.uspConsent) { + utils.deepSetValue(req, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + if (bid.schain) { + utils.deepSetValue(req, 'source.ext.schain', bid.schain); + } + if (bid.userIdAsEids) { + utils.deepSetValue(req, 'user.ext.eids', bid.userIdAsEids); + } + const commonFpd = bidderRequest.ortb2 || {}; + if (commonFpd.site) { + utils.mergeDeep(req, {site: commonFpd.site}); + } + if (commonFpd.user) { + utils.mergeDeep(req, {user: commonFpd.user}); + } + return req; +} + +/** * Unpack the response from the server into a list of bids. * * @param {ServerResponse} serverResponse A successful response from the server. * @return {Bid[]} An array of bids which were nested inside the server. */ - interpretResponse: function(serverResponse, bidRequest) { - const serverBody = serverResponse.body; - const bidResponses = []; - let bidResponse = null; - let value = null; - if (serverBody.hasOwnProperty('responses')) { - Object.keys(serverBody['responses']).forEach(key => { - value = serverBody['responses'][key]; - const url = `${CACHE_URL}?uuid=${value['uuid']}`; - bidResponse = { - requestId: value['bidId'], - cpm: value['cpm'], - currency: value['currency'], - width: value['width'], - height: value['height'], - ttl: value['ttl'], - creativeId: value['creativeId'], - netRevenue: true, - nexx360: { - 'ssp': value['bidder'], - 'consent': value['consent'], - 'tagId': value['tagId'] - }, - /* - meta: { - 'advertiserDomains': value['adomain'] - } - */ - }; - if (value.type === 'banner') bidResponse.adUrl = url; - if (value.type === 'video') { - const params = { - type: 'prebid', - mediatype: 'video', - ssp: value.bidder, - tag_id: value.tagId, - consent: value.consent, - price: value.cpm, - }; - bidResponse.cpm = value.cpm; - bidResponse.mediaType = 'video'; - bidResponse.vastUrl = url; - bidResponse.vastImpUrl = `${METRICS_TRACKER_URL}?${new URLSearchParams(params).toString()}`; - } - bidResponses.push(bidResponse); - }); - } - return bidResponses; - }, +function interpretResponse(response, req) { + const { bidderSettings } = getGlobal(); + const allowAlternateBidderCodes = bidderSettings && bidderSettings.standard ? bidderSettings.standard.allowAlternateBidderCodes : false; + const respBody = response.body; + if (!respBody || !Array.isArray(respBody.seatbid)) { + return []; + } + + let bids = []; + respBody.seatbid.forEach(seatbid => { + bids = [...bids, ...seatbid.bid.map(bid => { + const response = { + requestId: bid.impid, + cpm: bid.price, + width: bid.w, + height: bid.h, + creativeId: bid.crid, + dealId: bid.dealid, + currency: respBody.cur || 'USD', + netRevenue: true, + ttl: 120, + bidderCode: allowAlternateBidderCodes ? `n360-${bid.ssp}` : 'nexx360', + mediaType: bid.type === 'banner' ? 'banner' : 'video', + meta: { advertiserDomains: bid.adomain }, + }; + // if (bid.dealid) response.dealid = bid.dealid; - /** + if (response.mediaType === 'banner') { + response.adUrl = bid.adUrl; + } + + if (['instream', 'outstream'].includes(bid.type)) response.vastXml = bid.vastXml; + + if (bid.ext) { + response.meta.networkId = bid.ext.dsp_id; + response.meta.advertiserId = bid.ext.buyer_id; + response.meta.brandId = bid.ext.brand_id; + } + return response; + })]; + }); + return bids; +} + +/** * Register the user sync pixels which should be dropped after the auction. * * @param {SyncOptions} syncOptions Which user syncs are allowed? * @param {ServerResponse[]} serverResponses List of server's responses. * @return {UserSync[]} The user syncs which should be dropped. */ - getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { - if (typeof serverResponses === 'object' && serverResponses != null && serverResponses.length > 0 && serverResponses[0].hasOwnProperty('body') && +function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { + if (typeof serverResponses === 'object' && serverResponses != null && serverResponses.length > 0 && serverResponses[0].hasOwnProperty('body') && serverResponses[0].body.hasOwnProperty('cookies') && typeof serverResponses[0].body.cookies === 'object') { - return serverResponses[0].body.cookies.slice(0, 5); - } else { - return []; - } - }, - - /** - * Register bidder specific code, which will execute if a bid from this bidder won the auction - * @param {Bid} The bid that won the auction - */ - onBidWon: function(bid) { - // fires a pixel to confirm a winning bid - const params = { type: 'prebid', mediatype: 'banner' }; - if (bid.hasOwnProperty('nexx360')) { - if (bid.nexx360.hasOwnProperty('ssp')) params.ssp = bid.nexx360.ssp; - if (bid.nexx360.hasOwnProperty('tagId')) params.tag_id = bid.nexx360.tagId; - if (bid.nexx360.hasOwnProperty('consent')) params.consent = bid.nexx360.consent; - }; - params.price = bid.cpm; - const url = `${METRICS_TRACKER_URL}?${new URLSearchParams(params).toString()}`; - ajax(url, null, undefined, {method: 'GET', withCredentials: true}); - return true; + return serverResponses[0].body.cookies.slice(0, 5); + } else { + return []; } - -} -registerBidder(spec); +}; diff --git a/test/spec/modules/nexx360BidAdapter_spec.js b/test/spec/modules/nexx360BidAdapter_spec.js index 1a695e5f8b3..a5da8b29fbc 100644 --- a/test/spec/modules/nexx360BidAdapter_spec.js +++ b/test/spec/modules/nexx360BidAdapter_spec.js @@ -6,70 +6,39 @@ import * as utils from 'src/utils.js'; import { requestBidsHook } from 'modules/consentManagement.js'; describe('Nexx360 bid adapter tests', function () { - const DISPLAY_BID_REQUEST = [{ - 'bidder': 'nexx360', - 'params': { - 'account': '1067', - 'tagId': 'luvxjvgn' + const DISPLAY_BID_REQUEST = { + 'id': '77b3f21a-e0df-4495-8bce-4e8a1d2309c1', + 'imp': [ + {'id': '2b4d8fc1c1c7ea', + 'tagid': 'div-1', + 'ext': {'divId': 'div-1', 'nexx360': {'account': '1067', 'tag_id': 'luvxjvgn'}}, + 'banner': {'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}], 'topframe': 1}}, {'id': '38fc428ab96638', 'tagid': 'div-2', 'ext': {'divId': 'div-2', 'nexx360': {'account': '1067', 'tag_id': 'luvxjvgn'}}, 'banner': {'format': [{'w': 728, 'h': 90}, {'w': 970, 'h': 250}], 'topframe': 1}}], + 'cur': ['USD'], + 'at': 1, + 'tmax': 3000, + 'site': {'page': 'https://test.nexx360.io/adapter/index.html?nexx360_test=1', 'domain': 'test.nexx360.io'}, + 'regs': {'coppa': 0, 'ext': {'gdpr': 1}}, + 'device': { + 'dnt': 0, + 'h': 844, + 'w': 390, + 'ua': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1', + 'language': 'fr' }, - 'userId': { - 'id5id': { - 'uid': 'ID5*hQ5WobYI9Od4u52qpaXVKHhxUa4DsOWRAlvaFajm8gINfI1oVAe3UK59416dT4TqDX1pj4MBJ5TYwir6x3JgBw1-avYHSnmvQDdRMbxmC2sNf3ggIRTbyQBdI1RjvHyeDYCsistnTXF_iKF1nutYeQ2BZ4P5d5muZTG7C2PXVFgNg-18io9dCiSjzJXx93KPDYRiuIwtsGGsp51rojlpFw2Fp_dUkjXl4CAblk58DvwNhobwQ27bnBP8F2-Pcs88DYcvKn4r6dm3Vi7ILttxDQ2IgZ2X44ClgjoWh-vRf6ANis8Z7uL16vO8q0P5C21eDYuc4v_KaZqN-p9YWEeEZQ2OpkbRL7n5NieVJExHM6ANkAlLZhVf2T-1906TAIHKDZFm_xMCa1jJfpBqZB2agw2TjfbK6wMtJeHiZaipSuUNlM_CSH0HVXtfMj9yfzjzDZZnltZQ9lvc4JhXye5AwA2X1f9Dhk8VURTvVdfEUlU', - 'ext': { - 'linkType': 2 - } - } - }, - 'userIdAsEids': [ - { - 'source': 'id5-sync.com', - 'uids': [ - { - 'id': 'ID5*hQ5WobYI9Od4u52qpaXVKHhxUa4DsOWRAlvaFajm8gINfI1oVAe3UK59416dT4TqDX1pj4MBJ5TYwir6x3JgBw1-avYHSnmvQDdRMbxmC2sNf3ggIRTbyQBdI1RjvHyeDYCsistnTXF_iKF1nutYeQ2BZ4P5d5muZTG7C2PXVFgNg-18io9dCiSjzJXx93KPDYRiuIwtsGGsp51rojlpFw2Fp_dUkjXl4CAblk58DvwNhobwQ27bnBP8F2-Pcs88DYcvKn4r6dm3Vi7ILttxDQ2IgZ2X44ClgjoWh-vRf6ANis8Z7uL16vO8q0P5C21eDYuc4v_KaZqN-p9YWEeEZQ2OpkbRL7n5NieVJExHM6ANkAlLZhVf2T-1906TAIHKDZFm_xMCa1jJfpBqZB2agw2TjfbK6wMtJeHiZaipSuUNlM_CSH0HVXtfMj9yfzjzDZZnltZQ9lvc4JhXye5AwA2X1f9Dhk8VURTvVdfEUlU', + 'user': { + 'ext': { + 'consent': 'CPgocUAPgocUAAKAsAENCkCsAP_AAH_AAAqIJDtd_H__bW9r-f5_aft0eY1P9_r37uQzDhfNk-8F3L_W_LwX52E7NF36tq4KmR4ku1LBIUNlHMHUDUmwaokVryHsak2cpzNKJ7BEknMZOydYGF9vmxtj-QKY7_5_d3bx2D-t_9v239z3z81Xn3d53-_03LCdV5_9Dfn9fR_bc9KPt_58v8v8_____3_e__3_7994JEAEmGrcQBdmWODNoGEUCIEYVhIVQKACCgGFogMAHBwU7KwCfWECABAKAIwIgQ4AowIBAAAJAEhEAEgRYIAAARAIAAQAIhEIAGBgEFgBYGAQAAgGgYohQACBIQZEBEUpgQFQJBAa2VCCUF0hphAHWWAFBIjYqABEEgIrAAEBYOAYIkBKxYIEmKN8gBGCFAKJUK1EAAAA.YAAAAAAAAAAA', + 'ConsentedProvidersSettings': {'consented_providers': '1~39.43.46.55.61.70.83.89.93.108.117.122.124.131.135.136.143.144.147.149.159.162.167.171.192.196.202.211.218.228.230.239.241.259.266.272.286.291.311.317.322.323.326.327.338.367.371.385.389.394.397.407.413.415.424.430.436.445.449.453.482.486.491.494.495.501.503.505.522.523.540.550.559.560.568.574.576.584.587.591.733.737.745.787.802.803.817.820.821.829.839.864.867.874.899.904.922.931.938.979.981.985.1003.1024.1027.1031.1033.1040.1046.1051.1053.1067.1085.1092.1095.1097.1099.1107.1127.1135.1143.1149.1152.1162.1166.1186.1188.1201.1205.1211.1215.1226.1227.1230.1252.1268.1270.1276.1284.1286.1290.1301.1307.1312.1345.1356.1364.1365.1375.1403.1415.1416.1419.1440.1442.1449.1455.1456.1465.1495.1512.1516.1525.1540.1548.1555.1558.1564.1570.1577.1579.1583.1584.1591.1603.1616.1638.1651.1653.1665.1667.1677.1678.1682.1697.1699.1703.1712.1716.1721.1725.1732.1745.1750.1765.1769.1782.1786.1800.1808.1810.1825.1827.1832.1838.1840.1842.1843.1845.1859.1866.1870.1878.1880.1889.1899.1917.1929.1942.1944.1962.1963.1964.1967.1968.1969.1978.2003.2007.2008.2027.2035.2039.2044.2047.2052.2056.2064.2068.2070.2072.2074.2088.2090.2103.2107.2109.2115.2124.2130.2133.2137.2140.2145.2147.2150.2156.2166.2177.2183.2186.2202.2205.2216.2219.2220.2222.2225.2234.2253.2264.2279.2282.2292.2299.2305.2309.2312.2316.2322.2325.2328.2331.2334.2335.2336.2337.2343.2354.2357.2358.2359.2370.2376.2377.2387.2392.2394.2400.2403.2405.2407.2411.2414.2416.2418.2425.2440.2447.2459.2461.2462.2465.2468.2472.2477.2481.2484.2486.2488.2493.2496.2497.2498.2499.2501.2510.2511.2517.2526.2527.2532.2534.2535.2542.2552.2563.2564.2567.2568.2569.2571.2572.2575.2577.2583.2584.2596.2601.2604.2605.2608.2609.2610.2612.2614.2621.2628.2629.2633.2634.2636.2642.2643.2645.2646.2647.2650.2651.2652.2656.2657.2658.2660.2661.2669.2670.2677.2681.2684.2686.2687.2690.2695.2698.2707.2713.2714.2729.2739.2767.2768.2770.2772.2784.2787.2791.2792.2798.2801.2805.2812.2813.2816.2817.2818.2821.2822.2827.2830.2831.2834.2838.2839.2840.2844.2846.2847.2849.2850.2852.2854.2856.2860.2862.2863.2865.2867.2869.2873.2874.2875.2876.2878.2880.2881.2882.2883.2884.2886.2887.2888.2889.2891.2893.2894.2895.2897.2898.2900.2901.2908.2909.2911.2912.2913.2914.2916.2917.2918.2919.2920.2922.2923.2924.2927.2929.2930.2931.2939.2940.2941.2947.2949.2950.2956.2961.2962.2963.2964.2965.2966.2968.2970.2973.2974.2975.2979.2980.2981.2983.2985.2986.2987.2991.2994.2995.2997.2999.3000.3002.3003.3005.3008.3009.3010.3012.3016.3017.3018.3019.3024.3025.3028.3034.3037.3038.3043.3045.3048.3052.3053.3055.3058.3059.3063.3065.3066.3068.3070.3072.3073.3074.3075.3076.3077.3078.3089.3090.3093.3094.3095.3097.3099.3104.3106.3109.3112.3117.3118.3119.3120.3124.3126.3127.3128.3130.3135.3136.3145.3149.3150.3151.3154.3155.3162.3163.3167.3172.3173.3180.3182.3183.3184.3185.3187.3188.3189.3190.3194.3196.3197.3209.3210.3211.3214.3215.3217.3219.3222.3223.3225.3226.3227.3228.3230.3231.3232.3234.3235.3236.3237.3238.3240.3241.3244.3245.3250.3251.3253.3257.3260.3268.3270.3272.3281.3288.3290.3292.3293.3295.3296.3300.3306.3307.3308.3314.3315.3316.3318.3324.3327.3328.3330'}, + 'eids': [{'source': 'id5-sync.com', + 'uids': [{'id': 'ID5*tdrSpYbccONIbxmulXFRLEil1aozZGGVMo9eEZgydgYoYFZQRYoae3wJyY0YtmXGKGJ7uXIQByQ6f7uzcpy9Oyhj1jGRzCf0BCoI4VkkKZIoZBubolUKUXXxOIdQOz7ZKGV0E3sqi9Zut0BbOuoJAihpLbgfNgDJ0xRmQw04rDooaxn7_TIPzEX5_L5ohNkUKG01Gnh2djvcrcPigKlk7ChwnauCwHIetHYI32yYAnAocYyqoM9XkoVOHtyOTC_UKHIR0qVBVIzJ1Nn_g7kLqyhzfosadKVvf7RQCsE6QrYodtpOJKg7i72-tnMXkzgmKHjh98aEDfTQrZOkKebmAyh6GlOHtYn_sZBFjJwtWp4oe9j2QTNbzK3G0jp1PlJqKHxiu4LawFEKJ3yi5-NFUyh-YkEalJUWyl1cDlWo5NQogAy2HM8N_w0qrVQgNbrTKIHK3KzTXztH7WzBgYrk8g', 'atype': 1, - 'ext': { - 'linkType': 2 - } - } - ] - } - ], - 'mediaTypes': { - 'banner': { - 'sizes': [[300, 250], [300, 600]] - } - }, - 'adUnitCode': 'banner-div', - 'transactionId': '9ad89d90-eb73-41b9-bf5f-7a8e2eecff27', - 'sizes': [[300, 250], [300, 600]], - 'bidId': '4d9e29504f8af6', - 'bidderRequestId': '3423b6bd1a922c', - 'auctionId': '05e0a3a1-9f57-41f6-bbcb-2ba9c9e3d2d5', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - }]; - - const DISPLAY_BID_RESPONSE = {'body': { - 'responses': [ - { - 'bidId': '4d9e29504f8af6', - 'cpm': 0.437245, - 'width': 300, - 'height': 250, - 'creativeId': '98493581', - 'currency': 'EUR', - 'netRevenue': true, - 'type': 'banner', - 'ttl': 360, - 'uuid': 'ce6d1ee3-2a05-4d7c-b97a-9e62097798ec', - 'bidder': 'appnexus', - 'consent': 1, - 'tagId': 'luvxjvgn' - } - ], - }}; + 'ext': {'linkType': 2}}]}, + {'source': 'domain.com', 'uids': [{'id': 'value read from cookie or local storage', 'atype': 1, 'ext': {'stype': 'ppuid'}}]}]}}, + 'ext': { + 'source': 'prebid.js', + 'version': '7.20.0-pre', + 'pageViewId': '5b970aba-51e9-4e0a-8299-f3f5618c695e' + }} const VIDEO_BID_REQUEST = [ { @@ -101,26 +70,6 @@ describe('Nexx360 bid adapter tests', function () { } ] - const VIDEO_BID_RESPONSE = {'body': { - 'responses': [ - { - 'bidId': '2c129e8e01859a', - 'type': 'video', - 'uuid': 'b8e7b2f0-c378-479f-aa4f-4f55d5d7d1d5', - 'cpm': 4.5421, - 'width': 1, - 'height': 1, - 'creativeId': '97517771', - 'currency': 'EUR', - 'netRevenue': true, - 'ttl': 360, - 'bidder': 'appnexus', - 'consent': 1, - 'tagId': 'yqsc1tfj' - } - ] - }}; - const DEFAULT_OPTIONS = { gdprConsent: { gdprApplies: true, @@ -147,159 +96,430 @@ describe('Nexx360 bid adapter tests', function () { }, }; - it('We verify isBidRequestValid with uncorrect bidfloorCurrency', function() { - const bid = { params: { - 'account': '1067', - 'tagId': 'luvxjvgn', - 'bidfloorCurrency': 'AAA', - }}; - expect(spec.isBidRequestValid(bid)).to.be.equal(false); - }); + describe('isBidRequestValid()', function() { + let bannerBid; + beforeEach(function () { + bannerBid = { + 'bidder': 'nexx360', + 'mediaTypes': {'banner': {'sizes': [[300, 250], [300, 600]]}}, + 'adUnitCode': 'div-1', + 'transactionId': '70bdc37e-9475-4b27-8c74-4634bdc2ee66', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '4906582fc87d0c', + 'bidderRequestId': '332fda16002dbe', + 'auctionId': '98932591-c822-42e3-850e-4b3cf748d063', + } + }); + it('We verify isBidRequestValid with uncorrect tagid', function() { + bannerBid.params = { 'tagid': 'luvxjvgn' }; + expect(spec.isBidRequestValid(bannerBid)).to.be.equal(false); + }); - it('We verify isBidRequestValid with uncorrect bidfloor', function() { - const bid = { params: { - 'account': '1067', - 'tagId': 'luvxjvgn', - 'bidfloorCurrency': 'EUR', - 'bidfloor': 'EUR', - }}; - expect(spec.isBidRequestValid(bid)).to.be.equal(false); + it('We verify isBidRequestValid with correct tagId', function() { + bannerBid.params = { 'tagId': 'luvxjvgn' }; + expect(spec.isBidRequestValid(bannerBid)).to.be.equal(true); + }); }); - it('We verify isBidRequestValid with uncorrect keywords', function() { - const bid = { params: { - 'account': '1067', - 'tagId': 'luvxjvgn', - 'bidfloorCurrency': 'EUR', - 'bidfloor': 0.8, - 'keywords': 'test', - }}; - expect(spec.isBidRequestValid(bid)).to.be.equal(false); + describe('when request is for a multiformat ad', function () { + describe('and request config uses mediaTypes video and banner', () => { + const multiformatBid = { + 'bidder': 'nexx360', + 'params': {'tagId': 'luvxjvgn'}, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + }, + 'video': { + 'playerSize': [300, 250] + } + }, + 'adUnitCode': 'div-1', + 'transactionId': '70bdc37e-9475-4b27-8c74-4634bdc2ee66', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '4906582fc87d0c', + 'bidderRequestId': '332fda16002dbe', + 'auctionId': '98932591-c822-42e3-850e-4b3cf748d063', + } + it('should return true multisize when required params found', function () { + expect(spec.isBidRequestValid(multiformatBid)).to.equal(true); + }); + }); }); - it('Verify banner build request', function () { - const request = spec.buildRequests(DISPLAY_BID_REQUEST, DEFAULT_OPTIONS); - expect(request).to.have.property('url').and.to.equal('https://fast.nexx360.io/prebid'); - expect(request).to.have.property('method').and.to.equal('POST'); - const requestContent = JSON.parse(request.data); - expect(requestContent.userEids.length).to.be.eql(1); - expect(requestContent.userEids[0]).to.have.property('source').and.to.equal('id5-sync.com'); - expect(requestContent.userEids[0]).to.have.property('uids'); - expect(requestContent.userEids[0].uids[0]).to.have.property('id').and.to.equal('ID5*hQ5WobYI9Od4u52qpaXVKHhxUa4DsOWRAlvaFajm8gINfI1oVAe3UK59416dT4TqDX1pj4MBJ5TYwir6x3JgBw1-avYHSnmvQDdRMbxmC2sNf3ggIRTbyQBdI1RjvHyeDYCsistnTXF_iKF1nutYeQ2BZ4P5d5muZTG7C2PXVFgNg-18io9dCiSjzJXx93KPDYRiuIwtsGGsp51rojlpFw2Fp_dUkjXl4CAblk58DvwNhobwQ27bnBP8F2-Pcs88DYcvKn4r6dm3Vi7ILttxDQ2IgZ2X44ClgjoWh-vRf6ANis8Z7uL16vO8q0P5C21eDYuc4v_KaZqN-p9YWEeEZQ2OpkbRL7n5NieVJExHM6ANkAlLZhVf2T-1906TAIHKDZFm_xMCa1jJfpBqZB2agw2TjfbK6wMtJeHiZaipSuUNlM_CSH0HVXtfMj9yfzjzDZZnltZQ9lvc4JhXye5AwA2X1f9Dhk8VURTvVdfEUlU'); - expect(requestContent.adUnits[0]).to.have.property('account').and.to.equal('1067'); - expect(requestContent.adUnits[0]).to.have.property('tagId').and.to.equal('luvxjvgn'); - expect(requestContent.adUnits[0]).to.have.property('label').and.to.equal('banner-div'); - expect(requestContent.adUnits[0]).to.have.property('bidId').and.to.equal('4d9e29504f8af6'); - expect(requestContent.adUnits[0]).to.have.property('auctionId').and.to.equal('05e0a3a1-9f57-41f6-bbcb-2ba9c9e3d2d5'); - expect(requestContent.adUnits[0]).to.have.property('mediatypes').exist; - expect(requestContent.adUnits[0].mediatypes).to.have.property('banner').exist; - expect(requestContent.adUnits[0]).to.have.property('bidfloor').and.to.equal(0); - expect(requestContent.adUnits[0]).to.have.property('bidfloorCurrency').and.to.equal('USD'); - expect(requestContent.adUnits[0]).to.have.property('keywords'); - expect(requestContent.adUnits[0].keywords.length).to.be.eql(0); + describe('when request is for a video ad', function () { + describe('and request config uses mediaTypes video and banner', () => { + const videoBid = { + 'bidder': 'nexx360', + 'params': {'tagId': 'luvxjvgn'}, + 'mediaTypes': { + 'video': { + 'playerSize': [300, 250] + } + }, + 'adUnitCode': 'div-1', + 'transactionId': '70bdc37e-9475-4b27-8c74-4634bdc2ee66', + 'bidId': '4906582fc87d0c', + 'bidderRequestId': '332fda16002dbe', + 'auctionId': '98932591-c822-42e3-850e-4b3cf748d063', + } + it('should return true multisize when required params found', function () { + expect(spec.isBidRequestValid(videoBid)).to.equal(true); + }); + }); }); - it('We add bidfloor and keywords', function() { - const DISPLAY_BID_REQUEST_2 = [ ...DISPLAY_BID_REQUEST ]; - DISPLAY_BID_REQUEST_2[0].params.keywords = { interest: 'cars' }; - DISPLAY_BID_REQUEST_2[0].params.bidfloor = 2.1; - const request = spec.buildRequests(DISPLAY_BID_REQUEST, DEFAULT_OPTIONS); - const requestContent = JSON.parse(request.data); - expect(requestContent.adUnits[0]).to.have.property('bidfloor').and.to.equal(2.1); - expect(requestContent.adUnits[0]).to.have.property('bidfloorCurrency').and.to.equal('USD'); - expect(requestContent.adUnits[0]).to.have.property('keywords'); - expect(requestContent.adUnits[0].keywords.length).to.be.eql(1); - expect(requestContent.adUnits[0].keywords[0].key).to.be.eql('interest'); - expect(requestContent.adUnits[0].keywords[0].value[0]).to.be.eql('cars'); - }); + describe('buildRequests()', function() { + describe('We test with a multiple display bids', function() { + const sampleBids = [ + { + bidder: 'nexx360', + params: { + tagId: 'luvxjvgn' + }, + adUnitCode: 'div-1', + transactionId: '469a570d-f187-488d-b1cb-48c1a2009be9', + sizes: [[300, 250], [300, 600]], + bidId: '44a2706ac3574', + bidderRequestId: '359bf8a3c06b2e', + auctionId: '2e684815-b44e-4e04-b812-56da54adbe74', + userIdAsEids: [ + { + source: 'id5-sync.com', + uids: [ + { + id: 'ID5*xe3R0Pbrc5Y4WBrb5UZSWTiS1t9DU2LgQrhdZOgFdXMoglhqmjs_SfBbyHfSYGZKKIT4Gf-XOQ_anA3iqi0hJSiFyD3aICGHDJFxNS8LO84ohwTQ0EiwOexZAbBlH0chKIhbvdGBfuouNuVF_YHCoyiLQJDp3WQiH96lE9MH2T0ojRqoyR623gxAWlBCBPh7KI4bYtZlet3Vtr-gH5_xqCiSEd7aYV37wHxUTSN38Isok_0qDCHg4pKXCcVM2h6FKJSGmvw-xPm9HkfkIcbh1CiVVG4nREP142XrBecdzhQomNlcalmwdzGHsuHPjTP-KJraa15yvvZDceq-f_YfECicDllYBLEsg24oPRM-ibMonWtT9qOm5dSfWS5G_r09KJ4HMB6REICq1wleDD1mwSigXkM_nxIKa4TxRaRqEekoooWRwuKA5-euHN3xxNfIKKP19EtGhuNTs0YdCSe8_w', + atype: 1, + ext: { + linkType: 2 + } + } + ] + }, + { + source: 'domain.com', + uids: [ + { + id: 'value read from cookie or local storage', + atype: 1, + ext: { + stype: 'ppuid' + } + } + ] + } + ], + }, + { + bidder: 'nexx360', + params: { + tagId: 'luvxjvgn', + allBids: true, + }, + mediaTypes: { + banner: { + sizes: [[728, 90], [970, 250]] + } + }, + adUnitCode: 'div-2', + transactionId: '6196885d-4e76-40dc-a09c-906ed232626b', + sizes: [[728, 90], [970, 250]], + bidId: '5ba94555219a03', + bidderRequestId: '359bf8a3c06b2e', + auctionId: '2e684815-b44e-4e04-b812-56da54adbe74', + } + ] + const bidderRequest = { + bidderCode: 'nexx360', + auctionId: '2e684815-b44e-4e04-b812-56da54adbe74', + bidderRequestId: '359bf8a3c06b2e', + refererInfo: { + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: [ + 'https://test.nexx360.io/adapter/index.html' + ], + topmostLocation: 'https://test.nexx360.io/adapter/index.html', + location: 'https://test.nexx360.io/adapter/index.html', + canonicalUrl: null, + page: 'https://test.nexx360.io/adapter/index.html', + domain: 'test.nexx360.io', + ref: null, + legacy: { + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: [ + 'https://test.nexx360.io/adapter/index.html' + ], + referer: 'https://test.nexx360.io/adapter/index.html', + canonicalUrl: null + }, + }, + gdprConsent: { + gdprApplies: true, + consentString: 'CPhdLUAPhdLUAAKAsAENCmCsAP_AAE7AAAqIJFNd_H__bW9r-f5_aft0eY1P9_r37uQzDhfNk-8F3L_W_LwX52E7NF36tq4KmR4ku1LBIUNlHMHUDUmwaokVryHsak2cpzNKJ7BEknMZOydYGF9vmxtj-QKY7_5_d3bx2D-t_9v239z3z81Xn3d53-_03LCdV5_9Dfn9fR_bc9KPt_58v8v8_____3_e__3_7997BIiAaADgAJYBnwEeAJXAXmAwQBj4DtgHcgPBAeKBIgAA.YAAAAAAAAAAA', + } + }; + it('We perform a test with 2 display adunits', function() { + const displayBids = [...sampleBids]; + displayBids[0].mediaTypes = { + banner: { + sizes: [[300, 250], [300, 600]] + } + }; + const request = spec.buildRequests(displayBids, bidderRequest); + const requestContent = request.data; + expect(request).to.have.property('method').and.to.equal('POST'); + expect(requestContent.id).to.be.eql('2e684815-b44e-4e04-b812-56da54adbe74'); + expect(requestContent.cur[0]).to.be.eql('USD'); + expect(requestContent.imp.length).to.be.eql(2); + expect(requestContent.imp[0].id).to.be.eql('44a2706ac3574'); + expect(requestContent.imp[0].tagid).to.be.eql('div-1'); + expect(requestContent.imp[0].ext.divId).to.be.eql('div-1'); + expect(requestContent.imp[0].ext.nexx360.tagId).to.be.eql('luvxjvgn'); + expect(requestContent.imp[0].ext.nexx360.allBids).to.be.eql(false); + expect(requestContent.imp[0].banner.format.length).to.be.eql(2); + expect(requestContent.imp[0].banner.format[0].w).to.be.eql(300); + expect(requestContent.imp[0].banner.format[0].h).to.be.eql(250); + expect(requestContent.imp[1].ext.nexx360.allBids).to.be.eql(true); + expect(requestContent.regs.ext.gdpr).to.be.eql(1); + expect(requestContent.user.ext.consent).to.be.eql(bidderRequest.gdprConsent.consentString); + expect(requestContent.user.ext.eids.length).to.be.eql(2); + }); - it('Verify banner parse response', function () { - const request = spec.buildRequests(DISPLAY_BID_REQUEST, DEFAULT_OPTIONS); - const response = spec.interpretResponse(DISPLAY_BID_RESPONSE, request); - expect(response).to.have.lengthOf(1); - const bid = response[0]; - expect(bid.cpm).to.equal(0.437245); - expect(bid.adUrl).to.equal('https://fast.nexx360.io/cache?uuid=ce6d1ee3-2a05-4d7c-b97a-9e62097798ec'); - expect(bid.width).to.equal(300); - expect(bid.height).to.equal(250); - expect(bid.creativeId).to.equal('98493581'); - expect(bid.currency).to.equal('EUR'); - expect(bid.netRevenue).to.equal(true); - expect(bid.ttl).to.equal(360); - expect(bid.requestId).to.equal('4d9e29504f8af6'); - expect(bid.nexx360).to.exist; - expect(bid.nexx360.ssp).to.equal('appnexus'); - }); + it('We perform a test with a multiformat adunit', function() { + const multiformatBids = [...sampleBids]; + multiformatBids[0].mediaTypes = { + banner: { + sizes: [[300, 250], [300, 600]] + }, + video: { + context: 'outstream', + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [2], + skip: 1, + playback_method: ['auto_play_sound_off'] + } + }; + const request = spec.buildRequests(multiformatBids, bidderRequest); + const requestContent = request.data; + expect(requestContent.imp[0].video.context).to.be.eql('outstream'); + expect(requestContent.imp[0].video.playbackmethod[0]).to.be.eql(2); + }); - it('Verify video build request', function () { - const request = spec.buildRequests(VIDEO_BID_REQUEST, DEFAULT_OPTIONS); - expect(request).to.have.property('url').and.to.equal('https://fast.nexx360.io/prebid'); - expect(request).to.have.property('method').and.to.equal('POST'); - const requestContent = JSON.parse(request.data); - expect(requestContent.adUnits[0]).to.have.property('account').and.to.equal('1067'); - expect(requestContent.adUnits[0]).to.have.property('tagId').and.to.equal('yqsc1tfj'); - expect(requestContent.adUnits[0]).to.have.property('label').and.to.equal('video1'); - expect(requestContent.adUnits[0]).to.have.property('bidId').and.to.equal('22f90541e576a3'); - expect(requestContent.adUnits[0]).to.have.property('auctionId').and.to.equal('ed21b528-bcab-47e2-8605-ec9b71000c89'); - expect(requestContent.adUnits[0]).to.have.property('mediatypes').exist; - expect(requestContent.adUnits[0].mediatypes).to.have.property('video').exist; + it('We perform a test with a video adunit', function() { + const videoBids = [sampleBids[0]]; + videoBids[0].mediaTypes = { + video: { + context: 'instream', + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6], + playbackmethod: [2], + skip: 1 + } + }; + const request = spec.buildRequests(videoBids, bidderRequest); + const requestContent = request.data; + expect(request).to.have.property('method').and.to.equal('POST'); + expect(requestContent.imp[0].video.context).to.be.eql('instream'); + expect(requestContent.imp[0].video.playbackmethod[0]).to.be.eql(2); + }) + }); }); - it('Verify video parse response', function () { - const request = spec.buildRequests(VIDEO_BID_REQUEST, DEFAULT_OPTIONS); - const response = spec.interpretResponse(VIDEO_BID_RESPONSE, request); - expect(response).to.have.lengthOf(1); - const bid = response[0]; - expect(bid.cpm).to.equal(4.5421); - expect(bid.vastUrl).to.equal('https://fast.nexx360.io/cache?uuid=b8e7b2f0-c378-479f-aa4f-4f55d5d7d1d5'); - expect(bid.vastImpUrl).to.equal('https://fast.nexx360.io/track-imp?type=prebid&mediatype=video&ssp=appnexus&tag_id=yqsc1tfj&consent=1&price=4.5421'); - expect(bid.width).to.equal(1); - expect(bid.height).to.equal(1); - expect(bid.creativeId).to.equal('97517771'); - expect(bid.currency).to.equal('EUR'); - expect(bid.netRevenue).to.equal(true); - expect(bid.ttl).to.equal(360); - expect(bid.requestId).to.equal('2c129e8e01859a'); - expect(bid.nexx360).to.exist; - expect(bid.nexx360.ssp).to.equal('appnexus'); + describe('interpretResponse()', function() { + it('banner responses', function() { + const response = { + body: { + 'id': 'a8d3a675-a4ba-4d26-807f-c8f2fad821e0', + 'cur': 'USD', + 'seatbid': [ + { + 'bid': [ + { + 'id': '4427551302944024629', + 'impid': '226175918ebeda', + 'price': 1.5, + 'type': 'banner', + 'adomain': [ + 'http://prebid.org' + ], + 'crid': '98493581', + 'ssp': 'appnexus', + 'h': 600, + 'w': 300, + 'cat': [ + 'IAB3-1' + ], + 'creativeuuid': 'fdddcebc-1edf-489d-880d-1418d8bdc493', + 'adUrl': 'https://fast.nexx360.io/cache?uuid=fdddcebc-1edf-489d-880d-1418d8bdc493', + 'ext': { + 'dsp_id': 'ssp1', + 'buyer_id': 'foo', + 'brand_id': 'bar' + } + } + ], + 'seat': 'appnexus' + } + ], + 'cookies': [] + } + }; + const output = spec.interpretResponse(response); + expect(output[0].bidderCode).to.be.eql('nexx360'); + expect(output[0].adUrl).to.be.eql(response.body.seatbid[0].bid[0].adUrl); + expect(output[0].mediaType).to.be.eql(response.body.seatbid[0].bid[0].type); + expect(output[0].currency).to.be.eql(response.body.cur); + expect(output[0].cpm).to.be.eql(response.body.seatbid[0].bid[0].price); + expect(output[0].meta.networkId).to.be.eql(response.body.seatbid[0].bid[0].ext.dsp_id); + expect(output[0].meta.advertiserId).to.be.eql(response.body.seatbid[0].bid[0].ext.buyer_id); + expect(output[0].meta.brandId).to.be.eql(response.body.seatbid[0].bid[0].ext.brand_id); + }); + it('video responses', function() { + const response = { + body: { + 'id': '33894759-0ea2-41f1-84b3-75132eefedb6', + 'cur': 'USD', + 'seatbid': [ + { + 'bid': [ + { + 'id': '294478680080716675', + 'impid': '2c835a6039e65f', + 'price': 5, + 'type': 'instream', + 'adomain': [ + '' + ], + 'crid': '97517771', + 'ssp': 'appnexus', + 'h': 1, + 'w': 1, + 'vastXml': '\n \n \n prebid.org wrapper\n \n \n \n \n \n ' + } + ], + 'seat': 'appnexus' + } + ], + 'cookies': [] + } + }; + const output = spec.interpretResponse(response); + expect(output[0].bidderCode).to.be.eql('nexx360'); + expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].vastXml); + expect(output[0].mediaType).to.be.eql('video'); + expect(output[0].currency).to.be.eql(response.body.cur); + expect(output[0].cpm).to.be.eql(response.body.seatbid[0].bid[0].price); + }); }); - it('Verifies bidder code', function () { - expect(spec.code).to.equal('nexx360'); + describe('interpretResponse()', function() { + it('banner responses', function() { + const response = { + body: { + 'id': 'a8d3a675-a4ba-4d26-807f-c8f2fad821e0', + 'cur': 'USD', + 'seatbid': [ + { + 'bid': [ + { + 'id': '4427551302944024629', + 'impid': '226175918ebeda', + 'price': 1.5, + 'type': 'banner', + 'adomain': [ + 'http://prebid.org' + ], + 'crid': '98493581', + 'ssp': 'appnexus', + 'h': 600, + 'w': 300, + 'cat': [ + 'IAB3-1' + ], + 'creativeuuid': 'fdddcebc-1edf-489d-880d-1418d8bdc493', + 'adUrl': 'https://fast.nexx360.io/cache?uuid=fdddcebc-1edf-489d-880d-1418d8bdc493' + } + ], + 'seat': 'appnexus' + } + ], + 'cookies': [] + } + }; + const output = spec.interpretResponse(response); + expect(output[0].bidderCode).to.be.eql('nexx360'); + expect(output[0].adUrl).to.be.eql(response.body.seatbid[0].bid[0].adUrl); + expect(output[0].mediaType).to.be.eql(response.body.seatbid[0].bid[0].type); + expect(output[0].currency).to.be.eql(response.body.cur); + expect(output[0].cpm).to.be.eql(response.body.seatbid[0].bid[0].price); + }); + it('video responses', function() { + const response = { + body: { + 'id': '33894759-0ea2-41f1-84b3-75132eefedb6', + 'cur': 'USD', + 'seatbid': [ + { + 'bid': [ + { + 'id': '294478680080716675', + 'impid': '2c835a6039e65f', + 'price': 5, + 'type': 'instream', + 'adomain': [ + '' + ], + 'crid': '97517771', + 'ssp': 'appnexus', + 'h': 1, + 'w': 1, + 'vastXml': '\n \n \n prebid.org wrapper\n \n \n \n \n \n ' + } + ], + 'seat': 'appnexus' + } + ], + 'cookies': [] + } + }; + const output = spec.interpretResponse(response); + expect(output[0].bidderCode).to.be.eql('nexx360'); + expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].vastXml); + expect(output[0].mediaType).to.be.eql('video'); + expect(output[0].currency).to.be.eql(response.body.cur); + expect(output[0].cpm).to.be.eql(response.body.seatbid[0].bid[0].price); + }); }); - it('Verifies bidder aliases', function () { - expect(spec.aliases).to.have.lengthOf(1); - expect(spec.aliases[0]).to.equal('revenuemaker'); - }); - it('Verifies if bid request valid', function () { - expect(spec.isBidRequestValid(DISPLAY_BID_REQUEST[0])).to.equal(true); - }); - it('Verifies bid won', function () { - const request = spec.buildRequests(DISPLAY_BID_REQUEST, DEFAULT_OPTIONS); - const response = spec.interpretResponse(DISPLAY_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({}, [DISPLAY_BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); - expect(syncs).to.have.lengthOf(0); - }); - it('Verifies user sync with cookies in bid response', function () { - DISPLAY_BID_RESPONSE.body.cookies = [{'type': 'image', 'url': 'http://www.cookie.sync.org/'}]; - var syncs = spec.getUserSyncs({}, [DISPLAY_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/'); - }); - it('Verifies user sync with no bid response', function() { - var syncs = spec.getUserSyncs({}, null, DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); - expect(syncs).to.have.lengthOf(0); - }); - it('Verifies user sync with no bid body response', function() { - var syncs = spec.getUserSyncs({}, [], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); - expect(syncs).to.have.lengthOf(0); - var syncs = spec.getUserSyncs({}, [{}], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); - expect(syncs).to.have.lengthOf(0); + describe('getUserSyncs()', function() { + const response = { body: { cookies: [] } }; + it('Verifies user sync without cookie in bid response', function () { + var syncs = spec.getUserSyncs({}, [response], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); + expect(syncs).to.have.lengthOf(0); + }); + it('Verifies user sync with cookies in bid response', function () { + response.body.cookies = [{'type': 'image', 'url': 'http://www.cookie.sync.org/'}]; + var syncs = spec.getUserSyncs({}, [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/'); + }); + it('Verifies user sync with no bid response', function() { + var syncs = spec.getUserSyncs({}, null, DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); + expect(syncs).to.have.lengthOf(0); + }); + it('Verifies user sync with no bid body response', function() { + var syncs = spec.getUserSyncs({}, [], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); + expect(syncs).to.have.lengthOf(0); + var syncs = spec.getUserSyncs({}, [{}], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); + expect(syncs).to.have.lengthOf(0); + }); }); }); From e32be9098829fa6f7a7d6f8dcbe3d8f10e05099c Mon Sep 17 00:00:00 2001 From: fndigrazia Date: Sun, 27 Nov 2022 01:56:49 -0300 Subject: [PATCH 144/367] ePlanning Bid Adapter : fix support for video auction (#9283) * Fix ad vast * fix lint spaces in tests * fix lint spaces in tests * fix lint spaces in tests --- modules/eplanningBidAdapter.js | 8 ++------ test/spec/modules/eplanningBidAdapter_spec.js | 8 ++++---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/modules/eplanningBidAdapter.js b/modules/eplanningBidAdapter.js index b60c3571d47..e230858487f 100644 --- a/modules/eplanningBidAdapter.js +++ b/modules/eplanningBidAdapter.js @@ -128,9 +128,9 @@ export const spec = { advertiserDomains: ad.adom }; } - if (isVastResponse(ad)) { + if (request && request.data && request.data.vv) { bidResponse.vastXml = ad.adm; - bidResponse.mediaTypes = VIDEO; + bidResponse.mediaType = VIDEO; } else { bidResponse.ad = ad.adm; } @@ -504,8 +504,4 @@ function registerAuction(storageID) { return true; } -function isVastResponse(bid) { - return bid.adm.match(/^( Date: Mon, 28 Nov 2022 16:04:09 +0200 Subject: [PATCH 145/367] add smn alias (#9290) --- modules/admixerBidAdapter.js | 2 +- modules/smnBidAdapter.md | 52 ++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 modules/smnBidAdapter.md diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js index 8fcee60f9f9..90031ed7f5d 100644 --- a/modules/admixerBidAdapter.js +++ b/modules/admixerBidAdapter.js @@ -5,7 +5,7 @@ import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; const BIDDER_CODE = 'admixer'; -const ALIASES = ['go2net', 'adblender', 'adsyield', 'futureads']; +const ALIASES = ['go2net', 'adblender', 'adsyield', 'futureads', 'smn']; const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.2.aspx'; export const spec = { code: BIDDER_CODE, diff --git a/modules/smnBidAdapter.md b/modules/smnBidAdapter.md new file mode 100644 index 00000000000..c9cb777e743 --- /dev/null +++ b/modules/smnBidAdapter.md @@ -0,0 +1,52 @@ +# Overview + +Module Name: SMN Bidder Adapter +Module Type: Bidder Adapter +Maintainer: smnoffice.belgrade@gmail.com + +# Description + +Connects to SMN demand source to fetch bids. +Banner and Video formats are supported. +Please use ```smn``` as the bidder code. + +# Test Parameters +``` + var adUnits = [ + { + code: 'desktop-banner-ad-div', + sizes: [[300, 250]], // a display size + bids: [ + { + bidder: "smn", + params: { + zone: '2eb6bd58-865c-47ce-af7f-a918108c3fd2' + } + } + ] + },{ + code: 'mobile-banner-ad-div', + sizes: [[300, 50]], // a mobile size + bids: [ + { + bidder: "smn", + params: { + zone: '62211486-c50b-4356-9f0f-411778d31fcc' + } + } + ] + },{ + code: 'video-ad', + sizes: [[300, 50]], + mediaType: 'video', + bids: [ + { + bidder: "smn", + params: { + zone: 'ebeb1e79-8cb4-4473-b2d0-2e24b7ff47fd' + } + } + ] + }, + ]; +``` From 4ba48bb0d8b594959290934cbf1a2c4256f0f297 Mon Sep 17 00:00:00 2001 From: Gino <53079123+Skylinar@users.noreply.github.com> Date: Mon, 28 Nov 2022 15:36:50 +0100 Subject: [PATCH 146/367] Smartx Bid Adapter: update custom header (#9291) * Add smartclipBidAdapter * smartxBidAdapter.js - removed unused variables, removed debug, added window before the outstream related functions * - made outstream player configurable * remove wrong named files * camelcase * fix * Out-Stream render update to SmartPlay 5.2 * ESlint fix * ESlint fix * ESlint fix * adjust tests, fixes * ESlint * adjusted desired bitrate examples * added bid.meta.advertiserDomains support * bug fix for numeric elementID outstream render * fix renderer url * support for floors module * bugfixes to be openRTB 2.5 compliant * update internal renderer usage * remove unused outstream_function logic * bugfix outstream options for default outstream renderer configuration * [PREB-10] fix empty title not configurable * add pbjs version * testing with outstream 5.3.0 * pbjs version into content.ext * made visibilityThreshold configurable * adjust position of pbjs version * Merge branch 'master' of https://github.com/prebid/Prebid.js into HEAD * update smartclip outstream player version to support outstream 6 release along with necessary config changes * Add support for schain * vacuuming * update custom header x-openrtb-version to 2.5 Co-authored-by: smartclip AdTechnology Co-authored-by: Gino Cirlini Co-authored-by: smartclip-adtech <65160328+smartclip-adtech@users.noreply.github.com> --- modules/smartxBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/smartxBidAdapter.js b/modules/smartxBidAdapter.js index f8438a35000..452aaafb09b 100644 --- a/modules/smartxBidAdapter.js +++ b/modules/smartxBidAdapter.js @@ -245,7 +245,7 @@ export const spec = { options: { contentType: 'application/json', customHeaders: { - 'x-openrtb-version': '2.3' + 'x-openrtb-version': '2.5' } } }; From 2ac1e70863ba170eb862d06a428bf858fba2515c Mon Sep 17 00:00:00 2001 From: Alexander Pykhteyev Date: Mon, 28 Nov 2022 22:55:58 +0700 Subject: [PATCH 147/367] LimeLight Bid Adapter : add IionAds alias (#9285) * User sync improvements * User sync improvements * Code review fixes * Pass supply chain to limelightDigitalBidAdapter.js * Add alias for iionads Co-authored-by: apykhteyev Co-authored-by: EngineeringProjectLimeLight <45598299+EngineeringProjectLimeLight@users.noreply.github.com> --- modules/limelightDigitalBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/limelightDigitalBidAdapter.js b/modules/limelightDigitalBidAdapter.js index c39fd36e597..87cf6e4fe21 100644 --- a/modules/limelightDigitalBidAdapter.js +++ b/modules/limelightDigitalBidAdapter.js @@ -26,7 +26,7 @@ function isBidResponseValid(bid) { export const spec = { code: BIDDER_CODE, - aliases: ['pll'], + aliases: ['pll', 'iionads'], supportedMediaTypes: [BANNER, VIDEO], /** From a833997b7da47fff9259fcef7b5be760f659c4fc Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Mon, 28 Nov 2022 09:20:10 -0700 Subject: [PATCH 148/367] Generic Analytics Adapter: initial release (#9134) * New module: generic analytics adapter * Use special gvlid value instead of `isVendorless` flag for vendorless consent checks * Mark generic analytics as vendorless for gdpr enforcement * Allow analytics adapters to define dynamic gvlids * Add gvlid option * Gdpr enforcement softVendorExceptions --- modules/gdprEnforcement.js | 50 +-- modules/genericAnalyticsAdapter.js | 157 ++++++++++ modules/pubCommonId.js | 3 +- modules/pubProvidedIdSystem.js | 2 + modules/sharedIdSystem.js | 4 +- src/consentHandler.js | 8 + src/storageManager.js | 9 +- test/spec/modules/gdprEnforcement_spec.js | 183 ++++++----- .../modules/genericAnalyticsAdapter_spec.js | 284 ++++++++++++++++++ test/spec/unit/core/storageManager_spec.js | 3 +- 10 files changed, 605 insertions(+), 98 deletions(-) create mode 100644 modules/genericAnalyticsAdapter.js create mode 100644 test/spec/modules/genericAnalyticsAdapter_spec.js diff --git a/modules/gdprEnforcement.js b/modules/gdprEnforcement.js index b7035c509b6..9553ad0586a 100644 --- a/modules/gdprEnforcement.js +++ b/modules/gdprEnforcement.js @@ -2,7 +2,7 @@ * This module gives publishers extra set of features to enforce individual purposes of TCF v2 */ -import {deepAccess, hasDeviceAccess, isArray, logWarn} from '../src/utils.js'; +import {deepAccess, hasDeviceAccess, isArray, logError, logWarn} from '../src/utils.js'; import {config} from '../src/config.js'; import adapterManager, {gdprDataHandler} from '../src/adapterManager.js'; import {find, includes} from '../src/polyfill.js'; @@ -11,13 +11,7 @@ import {getHook} from '../src/hook.js'; import {validateStorageEnforcement} from '../src/storageManager.js'; import * as events from '../src/events.js'; import CONSTANTS from '../src/constants.json'; - -// modules for which vendor consent is not needed (see https://github.com/prebid/Prebid.js/issues/8161) -const VENDORLESS_MODULES = new Set([ - 'sharedId', - 'pubCommonId', - 'pubProvidedId', -]); +import {VENDORLESS_GVLID} from '../src/consentHandler.js'; export const STRICT_STORAGE_ENFORCEMENT = 'strictStorageEnforcement'; @@ -71,7 +65,7 @@ export const internal = { * @param {{string|Object}} - module * @return {number} - GVL ID */ -export function getGvlid(module) { +export function getGvlid(module, ...args) { let gvlid = null; if (module) { // Check user defined GVL Mapping in pbjs.setConfig() @@ -86,7 +80,7 @@ export function getGvlid(module) { return gvlid; } - gvlid = internal.getGvlidForBidAdapter(moduleCode) || internal.getGvlidForUserIdModule(module) || internal.getGvlidForAnalyticsAdapter(moduleCode); + gvlid = internal.getGvlidForBidAdapter(moduleCode) || internal.getGvlidForUserIdModule(module) || internal.getGvlidForAnalyticsAdapter(moduleCode, ...args); } return gvlid; } @@ -120,10 +114,19 @@ function getGvlidForUserIdModule(userIdModule) { /** * Returns GVL ID for an analytics adapter. If an analytics adapter does not have an associated GVL ID, it returns 'null'. * @param {string} code - 'provider' property on the analytics adapter config + * @param {{}} config - analytics configuration object * @return {number} GVL ID */ -function getGvlidForAnalyticsAdapter(code) { - return adapterManager.getAnalyticsAdapter(code) && (adapterManager.getAnalyticsAdapter(code).gvlid || null); +function getGvlidForAnalyticsAdapter(code, config) { + const adapter = adapterManager.getAnalyticsAdapter(code); + return adapter?.gvlid || ((gvlid) => { + if (typeof gvlid !== 'function') return gvlid; + try { + return gvlid.call(adapter.adapter, config); + } catch (e) { + logError(`Error invoking ${code} adapter.gvlid()`, e) + } + })(adapter?.adapter?.gvlid) } export function shouldEnforce(consentData, purpose, name) { @@ -145,20 +148,20 @@ export function shouldEnforce(consentData, purpose, name) { * @param {Object} consentData - gdpr consent data * @param {string=} currentModule - Bidder code of the current module * @param {number=} gvlId - GVL ID for the module - * @param vendorlessModule a predicate function that takes a module name, and returns true if the module does not need vendor consent * @returns {boolean} */ -export function validateRules(rule, consentData, currentModule, gvlId, vendorlessModule = VENDORLESS_MODULES.has.bind(VENDORLESS_MODULES)) { +export function validateRules(rule, consentData, currentModule, gvlId) { const purposeId = TCF2[Object.keys(TCF2).filter(purposeName => TCF2[purposeName].name === rule.purpose)[0]].id; // return 'true' if vendor present in 'vendorExceptions' - if (includes(rule.vendorExceptions || [], currentModule)) { + if ((rule.vendorExceptions || []).includes(currentModule)) { return true; } + const vendorConsentRequred = !((gvlId === VENDORLESS_GVLID || (rule.softVendorExceptions || []).includes(currentModule))) // get data from the consent string const purposeConsent = deepAccess(consentData, `vendorData.purpose.consents.${purposeId}`); - const vendorConsent = deepAccess(consentData, `vendorData.vendor.consents.${gvlId}`); + const vendorConsent = vendorConsentRequred ? deepAccess(consentData, `vendorData.vendor.consents.${gvlId}`) : true; const liTransparency = deepAccess(consentData, `vendorData.purpose.legitimateInterests.${purposeId}`); /* @@ -166,7 +169,7 @@ export function validateRules(rule, consentData, currentModule, gvlId, vendorles or the user has consented. Similar with vendors. */ const purposeAllowed = rule.enforcePurpose === false || purposeConsent === true; - const vendorAllowed = vendorlessModule(currentModule) || rule.enforceVendor === false || vendorConsent === true; + const vendorAllowed = rule.enforceVendor === false || vendorConsent === true; /* Few if any vendors should be declaring Legitimate Interest for Device Access (Purpose 1), but some are claiming @@ -183,19 +186,18 @@ export function validateRules(rule, consentData, currentModule, gvlId, vendorles /** * 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 isVendorless if true, do not require vendor consent (for e.g. core modules) * @param {Number=} gvlid gvlid of the module * @param {string=} moduleName name of the module * @param result */ -export function deviceAccessHook(fn, isVendorless, gvlid, moduleName, result, {validate = validateRules} = {}) { +export function deviceAccessHook(fn, gvlid, moduleName, result, {validate = validateRules} = {}) { result = Object.assign({}, { hasEnforcementHook: true }); if (!hasDeviceAccess()) { logWarn('Device access is disabled by Publisher'); result.valid = false; - } else if (isVendorless && !strictStorageEnforcement) { + } else if (gvlid === VENDORLESS_GVLID && !strictStorageEnforcement) { // for vendorless (core) storage, do not enforce rules unless strictStorageEnforcement is set result.valid = true; } else { @@ -203,13 +205,13 @@ export function deviceAccessHook(fn, isVendorless, gvlid, moduleName, result, {v if (shouldEnforce(consentData, 1, moduleName)) { const curBidder = config.getCurrentBidder(); // Bidders have a copy of storage object with bidder code binded. Aliases will also pass the same bidder code when invoking storage functions and hence if alias tries to access device we will try to grab the gvl id for alias instead of original bidder - if (curBidder && (curBidder != moduleName) && adapterManager.aliasRegistry[curBidder] === moduleName) { + if (curBidder && (curBidder !== moduleName) && adapterManager.aliasRegistry[curBidder] === moduleName) { gvlid = getGvlid(curBidder); } else { gvlid = getGvlid(moduleName) || gvlid; } const curModule = moduleName || curBidder; - let isAllowed = validate(purpose1Rule, consentData, curModule, gvlid, isVendorless ? () => true : undefined); + let isAllowed = validate(purpose1Rule, consentData, curModule, gvlid,); if (isAllowed) { result.valid = true; } else { @@ -221,7 +223,7 @@ export function deviceAccessHook(fn, isVendorless, gvlid, moduleName, result, {v result.valid = true; } } - fn.call(this, isVendorless, gvlid, moduleName, result); + fn.call(this, gvlid, moduleName, result); } /** @@ -314,7 +316,7 @@ export function enableAnalyticsHook(fn, config) { } config = config.filter(conf => { const analyticsAdapterCode = conf.provider; - const gvlid = getGvlid(analyticsAdapterCode); + const gvlid = getGvlid(analyticsAdapterCode, conf); const isAllowed = !!validateRules(purpose7Rule, consentData, analyticsAdapterCode, gvlid); if (!isAllowed) { analyticsBlocked.push(analyticsAdapterCode); diff --git a/modules/genericAnalyticsAdapter.js b/modules/genericAnalyticsAdapter.js new file mode 100644 index 00000000000..4909745e72b --- /dev/null +++ b/modules/genericAnalyticsAdapter.js @@ -0,0 +1,157 @@ +import AnalyticsAdapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import {prefixLog, isPlainObject} from '../src/utils.js'; +import * as CONSTANTS from '../src/constants.json'; +import adapterManager from '../src/adapterManager.js'; +import {ajaxBuilder} from '../src/ajax.js'; + +const DEFAULTS = { + batchSize: 1, + batchDelay: 100, + method: 'POST' +} + +const TYPES = { + handler: 'function', + batchSize: 'number', + batchDelay: 'number', + gvlid: 'number', +} + +const MAX_CALL_DEPTH = 20; + +export function GenericAnalytics() { + const parent = AnalyticsAdapter({analyticsType: 'endpoint'}); + const {logError, logWarn} = prefixLog('Generic analytics:'); + let batch = []; + let callDepth = 0; + let options, handler, timer, translate; + + function optionsAreValid(options) { + if (!options.url && !options.handler) { + logError('options must specify either `url` or `handler`') + return false; + } + if (options.hasOwnProperty('method') && !['GET', 'POST'].includes(options.method)) { + logError('options.method must be GET or POST'); + return false; + } + for (const [field, type] of Object.entries(TYPES)) { + // eslint-disable-next-line valid-typeof + if (options.hasOwnProperty(field) && typeof options[field] !== type) { + logError(`options.${field} must be a ${type}`); + return false; + } + } + if (options.hasOwnProperty('events')) { + if (!isPlainObject(options.events)) { + logError('options.events must be an object'); + return false; + } + for (const [event, handler] of Object.entries(options.events)) { + if (!CONSTANTS.EVENTS.hasOwnProperty(event)) { + logWarn(`options.events.${event} does not match any known Prebid event`); + if (typeof handler !== 'function') { + logError(`options.events.${event} must be a function`); + return false; + } + } + } + } + return true; + } + + function processBatch() { + const currentBatch = batch; + batch = []; + callDepth++; + try { + // the pub-provided handler may inadvertently cause an infinite chain of events; + // even just logging an exception from it may cause an AUCTION_DEBUG event, that + // gets back to the handler, that throws another exception etc. + // to avoid the issue, put a cap on recursion + if (callDepth === MAX_CALL_DEPTH) { + logError('detected probable infinite recursion, discarding events', currentBatch); + } + if (callDepth >= MAX_CALL_DEPTH) { + return; + } + try { + handler(currentBatch); + } catch (e) { + logError('error executing options.handler', e); + } + } finally { + callDepth--; + } + } + + function translator(eventHandlers) { + if (!eventHandlers) { + return (data) => data; + } + return function ({eventType, args}) { + if (eventHandlers.hasOwnProperty(eventType)) { + try { + return eventHandlers[eventType](args); + } catch (e) { + logError(`error executing options.events.${eventType}`, e); + } + } + } + } + + return Object.assign( + Object.create(parent), + { + gvlid(config) { + return config?.options?.gvlid + }, + enableAnalytics(config) { + if (optionsAreValid(config?.options || {})) { + options = Object.assign({}, DEFAULTS, config.options); + handler = options.handler || defaultHandler(options); + translate = translator(options.events); + parent.enableAnalytics.call(this, config); + } + }, + track(event) { + if (event.eventType === CONSTANTS.EVENTS.AUCTION_INIT && event.args.hasOwnProperty('config')) { + // clean up auctionInit event + // TODO: remove this special case in v8 + delete event.args.config; + } + const datum = translate(event); + if (datum != null) { + batch.push(datum); + if (timer != null) { + clearTimeout(timer); + timer = null; + } + if (batch.length >= options.batchSize) { + processBatch(); + } else { + timer = setTimeout(processBatch, options.batchDelay); + } + } + } + } + ) +} + +export function defaultHandler({url, method, batchSize, ajax = ajaxBuilder()}) { + const callbacks = { + success() {}, + error() {} + } + const extract = batchSize > 1 ? (events) => events : (events) => events[0]; + const serialize = method === 'GET' ? (data) => ({data: JSON.stringify(data)}) : (data) => JSON.stringify(data); + + return function (events) { + ajax(url, callbacks, serialize(extract(events)), {method}) + } +} + +adapterManager.registerAnalyticsAdapter({ + adapter: GenericAnalytics(), + code: 'generic', +}); diff --git a/modules/pubCommonId.js b/modules/pubCommonId.js index 5cadd522af2..1fde8f8db5b 100644 --- a/modules/pubCommonId.js +++ b/modules/pubCommonId.js @@ -9,8 +9,9 @@ import * as events from '../src/events.js'; import CONSTANTS from '../src/constants.json'; import { getStorageManager } from '../src/storageManager.js'; import {timedAuctionHook} from '../src/utils/perfMetrics.js'; +import {VENDORLESS_GVLID} from '../src/consentHandler.js'; -const storage = getStorageManager({moduleName: 'pubCommonId'}); +const storage = getStorageManager({moduleName: 'pubCommonId', gvlid: VENDORLESS_GVLID}); const ID_NAME = '_pubcid'; const OPTOUT_NAME = '_pubcid_optout'; diff --git a/modules/pubProvidedIdSystem.js b/modules/pubProvidedIdSystem.js index 669d223c57f..baffd997443 100644 --- a/modules/pubProvidedIdSystem.js +++ b/modules/pubProvidedIdSystem.js @@ -7,6 +7,7 @@ import {submodule} from '../src/hook.js'; import { logInfo, isArray } from '../src/utils.js'; +import {VENDORLESS_GVLID} from '../src/consentHandler.js'; const MODULE_NAME = 'pubProvidedId'; @@ -18,6 +19,7 @@ export const pubProvidedIdSubmodule = { * @type {string} */ name: MODULE_NAME, + gvlid: VENDORLESS_GVLID, /** * decode the stored id value for passing to bid request diff --git a/modules/sharedIdSystem.js b/modules/sharedIdSystem.js index 99a34ae17f4..7562b472047 100644 --- a/modules/sharedIdSystem.js +++ b/modules/sharedIdSystem.js @@ -9,8 +9,9 @@ import { parseUrl, buildUrl, triggerPixel, logInfo, hasDeviceAccess, generateUUI import {submodule} from '../src/hook.js'; import { coppaDataHandler } from '../src/adapterManager.js'; import {getStorageManager} from '../src/storageManager.js'; +import {VENDORLESS_GVLID} from '../src/consentHandler.js'; -export const storage = getStorageManager({moduleName: 'pubCommonId'}); +export const storage = getStorageManager({moduleName: 'pubCommonId', gvlid: VENDORLESS_GVLID}); const COOKIE = 'cookie'; const LOCAL_STORAGE = 'html5'; const OPTOUT_NAME = '_pubcid_optout'; @@ -73,6 +74,7 @@ export const sharedIdSystemSubmodule = { */ name: 'sharedId', aliasName: 'pubCommonId', + gvlid: VENDORLESS_GVLID, /** * decode the stored id value for passing to bid requests diff --git a/src/consentHandler.js b/src/consentHandler.js index 861a9894a2c..01470a4b38c 100644 --- a/src/consentHandler.js +++ b/src/consentHandler.js @@ -1,6 +1,14 @@ import {isStr, timestamp} from './utils.js'; import {defer, GreedyPromise} from './utils/promise.js'; +/** + * Placeholder gvlid for when vendor consent is not required. When this value is used as gvlid, the gdpr + * enforcement module will take it to mean "vendor consent was given". + * + * see https://github.com/prebid/Prebid.js/issues/8161 + */ +export const VENDORLESS_GVLID = Object.freeze({}); + export class ConsentHandler { #enabled; #data; diff --git a/src/storageManager.js b/src/storageManager.js index 4ab224f8d9b..eaf35603c60 100644 --- a/src/storageManager.js +++ b/src/storageManager.js @@ -1,6 +1,7 @@ import {hook} from './hook.js'; import {hasDeviceAccess, checkCookieSupport, logError, logInfo, isPlainObject} from './utils.js'; import {bidderSettings as defaultBidderSettings} from './bidderSettings.js'; +import {VENDORLESS_GVLID} from './consentHandler.js'; const moduleTypeWhiteList = ['core', 'prebid-module']; @@ -33,7 +34,9 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} = return storageAllowed == null ? false : storageAllowed; } - const isVendorless = moduleTypeWhiteList.includes(moduleType); + if (moduleTypeWhiteList.includes(moduleType)) { + gvlid = gvlid || VENDORLESS_GVLID; + } function isValid(cb) { if (!isBidderAllowed()) { @@ -45,7 +48,7 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} = let hookDetails = { hasEnforcementHook: false } - validateStorageEnforcement(isVendorless, gvlid, bidderCode || moduleName, hookDetails, function(result) { + validateStorageEnforcement(gvlid, bidderCode || moduleName, hookDetails, function(result) { if (result && result.hasEnforcementHook) { value = cb(result); } else { @@ -296,7 +299,7 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} = /** * This hook validates the storage enforcement if gdprEnforcement module is included */ -export const validateStorageEnforcement = hook('async', function(isVendorless, gvlid, moduleName, hookDetails, callback) { +export const validateStorageEnforcement = hook('async', function(gvlid, moduleName, hookDetails, callback) { callback(hookDetails); }, 'validateStorageEnforcement'); diff --git a/test/spec/modules/gdprEnforcement_spec.js b/test/spec/modules/gdprEnforcement_spec.js index ddd522decab..8d58990bb66 100644 --- a/test/spec/modules/gdprEnforcement_spec.js +++ b/test/spec/modules/gdprEnforcement_spec.js @@ -20,6 +20,7 @@ import * as events from 'src/events.js'; import 'modules/appnexusBidAdapter.js'; // some tests expect this to be in the adapter registry import 'src/prebid.js' import {hook} from '../../../src/hook.js'; +import {VENDORLESS_GVLID} from '../../../src/consentHandler.js'; describe('gdpr enforcement', function () { let nextFnSpy; @@ -150,13 +151,13 @@ describe('gdpr enforcement', function () { } }); - deviceAccessHook(nextFnSpy, false); + deviceAccessHook(nextFnSpy); expect(nextFnSpy.calledOnce).to.equal(true); let result = { hasEnforcementHook: true, valid: false } - sinon.assert.calledWith(nextFnSpy, false, undefined, undefined, result); + sinon.assert.calledWith(nextFnSpy, undefined, undefined, result); }); it('should only check for consent for vendor exceptions when enforcePurpose and enforceVendor are false', function () { @@ -178,8 +179,8 @@ describe('gdpr enforcement', function () { consentData.apiVersion = 2; gdprDataHandlerStub.returns(consentData); - deviceAccessHook(nextFnSpy, false, 1, 'appnexus'); - deviceAccessHook(nextFnSpy, false, 5, 'rubicon'); + deviceAccessHook(nextFnSpy, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 5, 'rubicon'); expect(logWarnSpy.callCount).to.equal(0); }); @@ -201,8 +202,8 @@ describe('gdpr enforcement', function () { consentData.apiVersion = 2; gdprDataHandlerStub.returns(consentData); - deviceAccessHook(nextFnSpy, false, 1, 'appnexus'); - deviceAccessHook(nextFnSpy, false, 3, 'rubicon'); + deviceAccessHook(nextFnSpy, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 3, 'rubicon'); expect(logWarnSpy.callCount).to.equal(1); }); @@ -224,13 +225,13 @@ describe('gdpr enforcement', function () { consentData.apiVersion = 2; gdprDataHandlerStub.returns(consentData); - deviceAccessHook(nextFnSpy, false, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 1, 'appnexus'); expect(nextFnSpy.calledOnce).to.equal(true); let result = { hasEnforcementHook: true, valid: true } - sinon.assert.calledWith(nextFnSpy, false, 1, 'appnexus', result); + sinon.assert.calledWith(nextFnSpy, 1, 'appnexus', result); }); it('should use gvlMapping set by publisher', function() { @@ -255,13 +256,13 @@ describe('gdpr enforcement', function () { consentData.apiVersion = 2; gdprDataHandlerStub.returns(consentData); - deviceAccessHook(nextFnSpy, false, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 1, 'appnexus'); expect(nextFnSpy.calledOnce).to.equal(true); let result = { hasEnforcementHook: true, valid: true } - sinon.assert.calledWith(nextFnSpy, false, 4, 'appnexus', result); + sinon.assert.calledWith(nextFnSpy, 4, 'appnexus', result); config.resetConfig(); }); @@ -290,31 +291,17 @@ describe('gdpr enforcement', function () { consentData.apiVersion = 2; gdprDataHandlerStub.returns(consentData); - deviceAccessHook(nextFnSpy, false, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 1, 'appnexus'); expect(nextFnSpy.calledOnce).to.equal(true); let result = { hasEnforcementHook: true, valid: true } - sinon.assert.calledWith(nextFnSpy, false, 4, 'appnexus', result); + sinon.assert.calledWith(nextFnSpy, 4, 'appnexus', result); config.resetConfig(); curBidderStub.restore(); }); - it(`should mark module as vendorless for rule validation when isVendorless = true and ${STRICT_STORAGE_ENFORCEMENT} is set`, () => { - setEnforcementConfig({ - [STRICT_STORAGE_ENFORCEMENT]: true - }); - let consentData = { - vendorData: staticConfig.consentData.getTCData, - gdprApplies: true - } - gdprDataHandlerStub.returns(consentData); - const validate = sinon.stub().callsFake(() => true); - deviceAccessHook(nextFnSpy, true, 123, 'mockModule', undefined, {validate}); - expect(validate.args[0][4]('mockModule')).to.be.true; - }); - it(`should not enforce consent for vendorless modules if ${STRICT_STORAGE_ENFORCEMENT} is not set`, () => { setEnforcementConfig({}); let consentData = { @@ -323,9 +310,9 @@ describe('gdpr enforcement', function () { } gdprDataHandlerStub.returns(consentData); const validate = sinon.stub().callsFake(() => false); - deviceAccessHook(nextFnSpy, true, 123, 'mockModule', undefined, {validate}); + deviceAccessHook(nextFnSpy, VENDORLESS_GVLID, 'mockModule', undefined, {validate}); sinon.assert.callCount(validate, 0); - sinon.assert.calledWith(nextFnSpy, true, 123, 'mockModule', {hasEnforcementHook: true, valid: true}); + sinon.assert.calledWith(nextFnSpy, VENDORLESS_GVLID, 'mockModule', {hasEnforcementHook: true, valid: true}); }) }); @@ -804,11 +791,12 @@ describe('gdpr enforcement', function () { }); describe('validateRules', function () { - const createGdprRule = (purposeName = 'storage', enforcePurpose = true, enforceVendor = true, vendorExceptions = []) => ({ + const createGdprRule = (purposeName = 'storage', enforcePurpose = true, enforceVendor = true, vendorExceptions = [], softVendorExceptions = []) => ({ purpose: purposeName, - enforcePurpose: enforcePurpose, - enforceVendor: enforceVendor, - vendorExceptions: vendorExceptions + enforcePurpose, + enforceVendor, + vendorExceptions, + softVendorExceptions, }); const consentData = { @@ -922,6 +910,19 @@ describe('gdpr enforcement', function () { expect(isAllowed).to.equal(true); }); + describe('when the vendor has a softVendorException', () => { + const gdprRule = createGdprRule('storage', true, true, [], [vendorBlockedModule]); + + it('should return false if general consent was not given', () => { + const isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.be.false; + }) + it('should return true if general consent was given', () => { + const isAllowed = validateRules(gdprRule, consentData, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.be.true; + }) + }) + describe('when module does not need vendor consent', () => { Object.entries({ 'storage': 1, @@ -937,11 +938,9 @@ describe('gdpr enforcement', function () { it(`should be ${t} when purpose is ${t}`, () => { const consent = utils.deepClone(consentData); consent.vendorData.purpose.consents[purposeNo] = consentGiven; - // vendor consent (and gvlid) should be ignored - consent.vendorData.vendor.consents[123] = !consentGiven; // take legitimate interest out of the picture for this test consent.vendorData.purpose.legitimateInterests = {}; - const actual = validateRules(rule, consent, 'mockModule', 123, () => true); + const actual = validateRules(rule, consent, 'mockModule', VENDORLESS_GVLID); expect(actual).to.equal(consentGiven); }) }) @@ -1131,56 +1130,104 @@ describe('gdpr enforcement', function () { }) }); - describe('getGvlid', function() { + describe('gvlid resolution', () => { let sandbox; - let getGvlidForBidAdapterStub; - let getGvlidForUserIdModuleStub; - let getGvlidForAnalyticsAdapterStub; beforeEach(function() { sandbox = sinon.createSandbox(); - getGvlidForBidAdapterStub = sandbox.stub(internal, 'getGvlidForBidAdapter'); - getGvlidForUserIdModuleStub = sandbox.stub(internal, 'getGvlidForUserIdModule'); - getGvlidForAnalyticsAdapterStub = sandbox.stub(internal, 'getGvlidForAnalyticsAdapter'); }); + afterEach(function() { sandbox.restore(); config.resetConfig(); }); - it('should return "null" if called without passing any argument', function() { - const gvlid = getGvlid(); - expect(gvlid).to.equal(null); - }); + describe('getGvlid', function() { + let getGvlidForBidAdapterStub; + let getGvlidForUserIdModuleStub; + let getGvlidForAnalyticsAdapterStub; + beforeEach(function() { + getGvlidForBidAdapterStub = sandbox.stub(internal, 'getGvlidForBidAdapter'); + getGvlidForUserIdModuleStub = sandbox.stub(internal, 'getGvlidForUserIdModule'); + getGvlidForAnalyticsAdapterStub = sandbox.stub(internal, 'getGvlidForAnalyticsAdapter'); + }); - it('should return "null" if GVL ID is not defined for any of these modules: Bid adapter, UserId submodule and Analytics adapter', function() { - getGvlidForBidAdapterStub.withArgs('moduleA').returns(null); - getGvlidForUserIdModuleStub.withArgs('moduleA').returns(null); - getGvlidForAnalyticsAdapterStub.withArgs('moduleA').returns(null); + it('should return "null" if called without passing any argument', function() { + const gvlid = getGvlid(); + expect(gvlid).to.equal(null); + }); - const gvlid = getGvlid('moduleA'); - expect(gvlid).to.equal(null); - }); + it('should return "null" if GVL ID is not defined for any of these modules: Bid adapter, UserId submodule and Analytics adapter', function() { + getGvlidForBidAdapterStub.withArgs('moduleA').returns(null); + getGvlidForUserIdModuleStub.withArgs('moduleA').returns(null); + getGvlidForAnalyticsAdapterStub.withArgs('moduleA').returns(null); - it('should return the GVL ID from gvlMapping if it is defined in setConfig', function() { - config.setConfig({ - gvlMapping: { - moduleA: 1 - } + const gvlid = getGvlid('moduleA'); + expect(gvlid).to.equal(null); + }); + + it('should return the GVL ID from gvlMapping if it is defined in setConfig', function() { + config.setConfig({ + gvlMapping: { + moduleA: 1 + } + }); + + // Actual GVL ID for moduleA is 2, as defined on its the bidAdapter.js file. + getGvlidForBidAdapterStub.withArgs('moduleA').returns(2); + + const gvlid = getGvlid('moduleA'); + expect(gvlid).to.equal(1); }); - // Actual GVL ID for moduleA is 2, as defined on its the bidAdapter.js file. - getGvlidForBidAdapterStub.withArgs('moduleA').returns(2); + it('should return the GVL ID by calling getGvlidForBidAdapter -> getGvlidForUserIdModule -> getGvlidForAnalyticsAdapter in sequence', function() { + getGvlidForBidAdapterStub.withArgs('moduleA').returns(null); + getGvlidForUserIdModuleStub.withArgs('moduleA').returns(null); + getGvlidForAnalyticsAdapterStub.withArgs('moduleA').returns(7); + + expect(getGvlid('moduleA')).to.equal(7); + }); - const gvlid = getGvlid('moduleA'); - expect(gvlid).to.equal(1); + it('should pass extra arguments to analytics\' getGvlid', () => { + getGvlidForAnalyticsAdapterStub.withArgs('analytics').returns(321); + const cfg = {some: 'args'}; + getGvlid('analytics', cfg); + sinon.assert.calledWith(getGvlidForAnalyticsAdapterStub, 'analytics', cfg); + }); }); - it('should return the GVL ID by calling getGvlidForBidAdapter -> getGvlidForUserIdModule -> getGvlidForAnalyticsAdapter in sequence', function() { - getGvlidForBidAdapterStub.withArgs('moduleA').returns(null); - getGvlidForUserIdModuleStub.withArgs('moduleA').returns(null); - getGvlidForAnalyticsAdapterStub.withArgs('moduleA').returns(7); + describe('getGvlidForAnalyticsAdapter', () => { + let getAnalyticsAdapter, adapter, adapterEntry; + + beforeEach(() => { + adapter = {}; + adapterEntry = { + adapter + }; + getAnalyticsAdapter = sandbox.stub(adapterManager, 'getAnalyticsAdapter'); + getAnalyticsAdapter.withArgs('analytics').returns(adapterEntry); + }); + + it('should return gvlid from adapterManager if defined', () => { + adapterEntry.gvlid = 123; + adapter.gvlid = 321 + expect(internal.getGvlidForAnalyticsAdapter('analytics')).to.equal(123); + }); + + it('should return gvlid from adapter if defined', () => { + adapter.gvlid = 321; + expect(internal.getGvlidForAnalyticsAdapter('analytics')).to.equal(321); + }); - expect(getGvlid('moduleA')).to.equal(7); + it('should invoke adapter.gvlid if it\'s a function', () => { + adapter.gvlid = (cfg) => cfg.k + const cfg = {k: 231}; + expect(internal.getGvlidForAnalyticsAdapter('analytics', cfg)).to.eql(231); + }); + + it('should not choke if adapter gvlid fn throws', () => { + adapter.gvlid = () => { throw new Error(); }; + expect(internal.getGvlidForAnalyticsAdapter('analytics')).to.not.be.ok; + }); }); - }); + }) }); diff --git a/test/spec/modules/genericAnalyticsAdapter_spec.js b/test/spec/modules/genericAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..a5a6074c425 --- /dev/null +++ b/test/spec/modules/genericAnalyticsAdapter_spec.js @@ -0,0 +1,284 @@ +import {defaultHandler, GenericAnalytics} from '../../../modules/genericAnalyticsAdapter.js'; +import * as events from 'src/events.js'; +import * as CONSTANTS from 'src/constants.json'; + +const {AUCTION_INIT, BID_RESPONSE} = CONSTANTS.EVENTS; + +describe('Generic analytics', () => { + describe('adapter', () => { + let adapter, sandbox, clock; + beforeEach(() => { + sandbox = sinon.sandbox.create(); + sandbox.stub(events, 'getEvents').returns([]); + clock = sandbox.useFakeTimers(); + adapter = new GenericAnalytics(); + }); + + afterEach(() => { + adapter.disableAnalytics(); + sandbox.restore(); + }); + + describe('configuration', () => { + it('should be accepted if valid', () => { + adapter.enableAnalytics({ + options: { + url: 'mock', + method: 'GET', + batchSize: 123, + batchDelay: 321 + } + }); + expect(adapter.enabled).to.be.true; + }); + + describe('should not work if', () => { + afterEach(function() { + expect(adapter.enabled).to.equal(false, this.currentTest.title); + }); + + it('neither handler nor url are specified', () => { + adapter.enableAnalytics({}); + }); + + ['batchSize', 'batchDelay', 'handler'].forEach(option => { + it(`${option} is not valid`, () => { + adapter.enableAnalytics({ + options: { + url: 'mock', + [option]: false + } + }); + }); + }); + + it('method is not GET or POST', () => { + adapter.enableAnalytics({ + options: { + url: 'mock', + method: 'PATCH' + } + }); + }); + + it('events is not an object', () => { + adapter.enableAnalytics({ + options: { + url: 'mock', + events: null + } + }); + }); + + it('events\' properties are not functions', () => { + adapter.enableAnalytics({ + options: { + url: 'mock', + events: { + bidResponse: null + } + } + }); + }); + }); + }); + + describe('when handler is specified', () => { + let handler; + beforeEach(() => { + handler = sinon.stub(); + }); + + it('should collect events in batches, and call handler', () => { + adapter.enableAnalytics({ + options: { + handler, + batchSize: 2 + } + }); + events.emit(AUCTION_INIT, {i: 0}); + sinon.assert.notCalled(handler); + events.emit(BID_RESPONSE, {i: 0}); + sinon.assert.calledWith(handler, sinon.match((arg) => { + return sinon.match({eventType: AUCTION_INIT, args: {i: 0}}).test(arg[0]) && + sinon.match({eventType: BID_RESPONSE, args: {i: 0}}).test(arg[1]); + })); + }); + + it('should not choke if handler throws', () => { + adapter.enableAnalytics({ + options: { + handler, + batchSize: 1 + } + }); + handler.throws(new Error()); + events.emit(AUCTION_INIT, {i: 0}); + let recv; + handler.reset(); + handler.callsFake((arg) => { + recv = arg; + }); + events.emit(BID_RESPONSE, {i: 1}); + expect(recv).to.eql([{eventType: BID_RESPONSE, args: {i: 1}}]); + }); + + it('should not cause infinite recursion, if handler triggers more events', () => { + let i = 0; + handler.callsFake(() => { + if (i <= 100) { + i++; + events.emit(BID_RESPONSE, {}); + } + }); + adapter.enableAnalytics({ + options: { + handler, + } + }); + events.emit(AUCTION_INIT, {}); + expect(i >= 100).to.be.false; + }); + + it('should send incomplete batch after batchDelay', () => { + adapter.enableAnalytics({ + options: { + batchDelay: 100, + batchSize: 2, + handler + } + }); + [0, 1, 2].forEach(i => events.emit(BID_RESPONSE, {i})); + sinon.assert.calledOnce(handler); + clock.tick(100); + sinon.assert.calledTwice(handler); + }); + + it('does not send empty batches', () => { + adapter.enableAnalytics({ + options: { + batchDelay: 100, + batchSize: 2, + handler + } + }); + [0, 1, 2].forEach(i => events.emit(BID_RESPONSE, {i})); + sinon.assert.calledOnce(handler); + clock.tick(50); + events.emit(BID_RESPONSE, {i: 3}); + sinon.assert.calledTwice(handler); + clock.tick(100); + sinon.assert.calledTwice(handler); + }); + + describe('and options.events is specified', () => { + it('filters out other events', () => { + adapter.enableAnalytics({ + options: { + handler, + events: { + bidResponse(bid) { + return bid; + } + } + } + }); + events.emit(AUCTION_INIT, {}); + sinon.assert.notCalled(handler); + }); + + it('transforms event data', () => { + adapter.enableAnalytics({ + options: { + handler, + events: { + bidResponse(bid) { + return { + extra: 'data', + prop: bid.prop + } + } + } + } + }); + events.emit(BID_RESPONSE, {prop: 'value', i: 0}); + sinon.assert.calledWith(handler, sinon.match(data => sinon.match({extra: 'data', prop: 'value'}).test(data[0]))); + }); + + it('does not choke if an event handler throws', () => { + adapter.enableAnalytics({ + options: { + handler, + events: { + bidResponse(bid) { + return bid; + }, + auctionInit(auction) { + throw new Error(); + } + } + } + }); + events.emit(AUCTION_INIT, {}); + events.emit(BID_RESPONSE, {i: 0}); + sinon.assert.calledOnce(handler); + sinon.assert.calledWith(handler, sinon.match(data => sinon.match({i: 0}).test(data[0]))); + }); + + it('filters out events when their handler returns undefined', () => { + adapter.enableAnalytics({ + options: { + handler, + events: { + auctionInit(auction) { + return auction; + }, + bidResponse(bid) {} + } + } + }); + events.emit(AUCTION_INIT, {i: 0}); + events.emit(BID_RESPONSE, {i: 1}); + sinon.assert.calledOnce(handler); + sinon.assert.calledWith(handler, sinon.match(data => sinon.match({i: 0}).test(data[0]))); + }); + }); + }); + }); + + describe('default handler', () => { + const url = 'mock-url'; + + let ajax; + beforeEach(() => { + ajax = sinon.stub(); + }); + + Object.entries({ + 'GET': (data) => JSON.parse(data.data), + 'POST': (data) => JSON.parse(data) + }).forEach(([method, parse]) => { + describe(`when HTTP method is ${method}`, () => { + it('should send single event when batchSize is 1', () => { + const handler = defaultHandler({url, method, batchSize: 1, ajax}); + const payload = {i: 0}; + handler([payload, {}]); + sinon.assert.calledWith(ajax, url, sinon.match.any, + sinon.match(data => sinon.match(payload).test(parse(data))), + {method} + ); + }); + + it('should send multiple events when batchSize is greater than 1', () => { + const handler = defaultHandler({url, method, batchSize: 10, ajax}); + const payload = [{i: 0}, {i: 1}]; + handler(payload); + sinon.assert.calledWith(ajax, url, sinon.match.any, + sinon.match(data => sinon.match(payload).test(parse(data))), + {method} + ); + }); + }); + }); + }); +}); diff --git a/test/spec/unit/core/storageManager_spec.js b/test/spec/unit/core/storageManager_spec.js index cb38aed9e47..58bf8c9eb25 100644 --- a/test/spec/unit/core/storageManager_spec.js +++ b/test/spec/unit/core/storageManager_spec.js @@ -8,6 +8,7 @@ import { import { config } from 'src/config.js'; import * as utils from 'src/utils.js'; import {hook} from '../../../../src/hook.js'; +import {VENDORLESS_GVLID} from '../../../../src/consentHandler.js'; describe('storage manager', function() { before(() => { @@ -73,7 +74,7 @@ describe('storage manager', function() { it('should respect (vendorless) consent enforcement', () => { storage.localStorageIsEnabled(); - expect(validateHook.args[0][1]).to.eql(true); // isVendorless should be set to true + expect(validateHook.args[0][1]).to.equal(VENDORLESS_GVLID); // gvlid should be set to VENDORLESS_GVLID }); it('should respect the deviceAccess flag', () => { From b0413b2225801317d0eb20040fc57c1cc25c9eaa Mon Sep 17 00:00:00 2001 From: southern-growthcode <79725079+southern-growthcode@users.noreply.github.com> Date: Mon, 28 Nov 2022 11:22:00 -0500 Subject: [PATCH 149/367] GrowthCode Analytics Adaptor Module: initial module release (#9021) * Initial check-in ofthe GrowthCode Adaptor * Growthcode ID System * Working on test module * Tests for the growthCode Id System * Clean up tests for GrowthCode * Fixed the default values for shareID * New Analyics package * Growthcode Analyics Adapter * Backout growthcode User ID module --- integrationExamples/gpt/growthcode.html | 134 +++++++++++++ modules/growthCodeAnalyticsAdapter.js | 176 ++++++++++++++++++ modules/growthCodeAnalyticsAdapter.md | 41 ++++ .../growthCodeAnalyticsAdapter_spec.js | 70 +++++++ 4 files changed, 421 insertions(+) create mode 100644 integrationExamples/gpt/growthcode.html create mode 100644 modules/growthCodeAnalyticsAdapter.js create mode 100644 modules/growthCodeAnalyticsAdapter.md create mode 100644 test/spec/modules/growthCodeAnalyticsAdapter_spec.js diff --git a/integrationExamples/gpt/growthcode.html b/integrationExamples/gpt/growthcode.html new file mode 100644 index 00000000000..ede51d2d869 --- /dev/null +++ b/integrationExamples/gpt/growthcode.html @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+
+ +
+ + diff --git a/modules/growthCodeAnalyticsAdapter.js b/modules/growthCodeAnalyticsAdapter.js new file mode 100644 index 00000000000..1f11b891139 --- /dev/null +++ b/modules/growthCodeAnalyticsAdapter.js @@ -0,0 +1,176 @@ +/** + * growthCodeAnalyticsAdapter.js - GrowthCode Analytics Adapter + */ +import { ajax } from '../src/ajax.js'; +import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; +import CONSTANTS from '../src/constants.json'; +import { getStorageManager } from '../src/storageManager.js'; +import {getRefererInfo} from '../src/refererDetection.js'; +import {logError, logInfo} from '../src/utils.js'; + +const MODULE_NAME = 'growthCodeAnalytics'; +const DEFAULT_PID = 'INVALID_PID' +const ENDPOINT_URL = 'https://p2.gcprivacy.com/v1/pb/analytics' + +export const storage = getStorageManager(); + +let sessionId = utils.generateUUID(); + +let trackEvents = []; +let pid = DEFAULT_PID; +let url = ENDPOINT_URL; + +let eventQueue = []; + +let startAuction = 0; +let bidRequestTimeout = 0; +let analyticsType = 'endpoint'; + +let growthCodeAnalyticsAdapter = Object.assign(adapter({url: url, analyticsType}), { + track({eventType, eventData}) { + eventData = eventData ? JSON.parse(JSON.stringify(eventData)) : {}; + let data = {}; + if (!trackEvents.includes(eventType)) return; + switch (eventType) { + case CONSTANTS.EVENTS.AUCTION_INIT: { + data = eventData; + startAuction = data.timestamp; + bidRequestTimeout = data.timeout; + break; + } + + case CONSTANTS.EVENTS.AUCTION_END: { + data = eventData; + data.start = startAuction; + data.end = Date.now(); + break; + } + + case CONSTANTS.EVENTS.BID_ADJUSTMENT: { + data.bidders = eventData; + break; + } + + case CONSTANTS.EVENTS.BID_TIMEOUT: { + data.bidders = eventData; + data.duration = bidRequestTimeout; + break; + } + + case CONSTANTS.EVENTS.BID_REQUESTED: { + data = eventData; + break; + } + + case CONSTANTS.EVENTS.BID_RESPONSE: { + data = eventData; + delete data.ad; + break; + } + + case CONSTANTS.EVENTS.BID_WON: { + data = eventData; + delete data.ad; + delete data.adUrl; + break; + } + + case CONSTANTS.EVENTS.BIDDER_DONE: { + data = eventData; + break; + } + + case CONSTANTS.EVENTS.SET_TARGETING: { + data.targetings = eventData; + break; + } + + case CONSTANTS.EVENTS.REQUEST_BIDS: { + data = eventData; + break; + } + + case CONSTANTS.EVENTS.ADD_AD_UNITS: { + data = eventData; + break; + } + + default: + return; + } + + data.eventType = eventType; + data.timestamp = data.timestamp || Date.now(); + + sendEvent(data); + } +}); + +growthCodeAnalyticsAdapter.originEnableAnalytics = growthCodeAnalyticsAdapter.enableAnalytics; + +growthCodeAnalyticsAdapter.enableAnalytics = function(conf = {}) { + if (typeof conf.options === 'object') { + if (conf.options.pid) { + pid = conf.options.pid; + url = conf.options.url ? conf.options.url : ENDPOINT_URL; + } else { + logError(MODULE_NAME + ' Not a valid PartnerID') + return + } + if (conf.options.trackEvents) { + trackEvents = conf.options.trackEvents; + } + } else { + logError(MODULE_NAME + ' Invalid configuration'); + return; + } + + growthCodeAnalyticsAdapter.originEnableAnalytics(conf); +}; + +function logToServer() { + if (pid === DEFAULT_PID) return; + if (eventQueue.length > 1) { + let data = { + session: sessionId, + pid: pid, + timestamp: Date.now(), + timezoneoffset: new Date().getTimezoneOffset(), + url: getRefererInfo().page, + referer: document.referrer, + events: eventQueue + }; + + ajax(url, { + success: response => { + logInfo(MODULE_NAME + ' Send Data to Server') + }, + error: error => { + logInfo(MODULE_NAME + ' Problem Send Data to Server: ' + error) + } + }, JSON.stringify(data), {method: 'POST', withCredentials: true}) + + eventQueue = [ + ]; + } +} + +function sendEvent(event) { + eventQueue.push(event); + logInfo(MODULE_NAME + 'Analytics Event: ' + event); + + if (event.eventType === CONSTANTS.EVENTS.AUCTION_END) { + logToServer(); + } +} + +adapterManager.registerAnalyticsAdapter({ + adapter: growthCodeAnalyticsAdapter, + code: 'growthCodeAnalytics' +}); + +growthCodeAnalyticsAdapter.logToServer = logToServer; + +export default growthCodeAnalyticsAdapter; diff --git a/modules/growthCodeAnalyticsAdapter.md b/modules/growthCodeAnalyticsAdapter.md new file mode 100644 index 00000000000..e45cb2e9c62 --- /dev/null +++ b/modules/growthCodeAnalyticsAdapter.md @@ -0,0 +1,41 @@ +## GrowthCode Analytics Adapter + +[GrowthCode](https://growthcode.io) offers scaled infrastructure-as-a-service to +empower independent publishers to harness data and take control of identity and +audience while rapidly aligning to industry changes and margin pressure. + +## Building Prebid with GrowthCode Support + +First, make sure to add the GrowthCode submodule to your Prebid.js package with: + +``` +gulp build --modules=growthCodeIdSystem,growthCodeAnalyticsAdapter,userId +``` + +The following configuration parameters are available: + +```javascript +pbjs.enableAnalytics({ + provider: 'growthCodeAnalytics', + options: { + pid: '', + trackEvents: [ + 'auctionEnd', + 'bidAdjustment', + 'bidTimeout', + 'bidRequested', + 'bidResponse', + 'noBid', + 'bidWon', + 'bidderDone'] + } +}); +``` + +| Param enableAnalytics | Scope | Type | Description | Example | +|-----------------------|----------|--------|-------------------------------------------------------------|--------------------------| +| provider | Required | String | The name of this Adapter. | `"growthCodeAnalytics"` | +| params | Required | Object | Details of module params. | | +| params.pid | Required | String | This is the Customer ID value obtained via Intimate Merger. | `""` | +| params.url | Optional | String | Custom URL for server | | +| params.trackEvents | Required | String | Name if the variable that holds your publisher ID | | diff --git a/test/spec/modules/growthCodeAnalyticsAdapter_spec.js b/test/spec/modules/growthCodeAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..e542a2641e8 --- /dev/null +++ b/test/spec/modules/growthCodeAnalyticsAdapter_spec.js @@ -0,0 +1,70 @@ +import adapterManager from '../../../src/adapterManager.js'; +import growthCodeAnalyticsAdapter from '../../../modules/growthCodeAnalyticsAdapter.js'; +import { expect } from 'chai'; +import * as events from '../../../src/events.js'; +import constants from '../../../src/constants.json'; +import { generateUUID } from '../../../src/utils.js'; +import { server } from 'test/mocks/xhr.js'; + +describe('growthCode analytics adapter', () => { + beforeEach(() => { + growthCodeAnalyticsAdapter.enableAnalytics({ + provider: 'growthCodeAnalytics', + options: { + pid: 'TEST01', + trackEvents: [ + 'auctionInit', + 'auctionEnd', + 'bidAdjustment', + 'bidTimeout', + 'bidTimeout', + 'bidRequested', + 'bidResponse', + 'setTargeting', + 'requestBids', + 'addAdUnits', + 'noBid', + 'bidWon', + 'bidderDone'] + } + }); + }); + + afterEach(() => { + growthCodeAnalyticsAdapter.disableAnalytics(); + }); + + it('registers itself with the adapter manager', () => { + const adapter = adapterManager.getAnalyticsAdapter('growthCodeAnalytics'); + expect(adapter).to.exist; + expect(adapter.adapter).to.equal(growthCodeAnalyticsAdapter); + }); + + it('tolerates undefined or empty config', () => { + growthCodeAnalyticsAdapter.enableAnalytics(undefined); + growthCodeAnalyticsAdapter.enableAnalytics({}); + }); + + it('sends auction end events to the backend', () => { + const auction = { + auctionId: generateUUID(), + adUnits: [{ + code: 'usr1234', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600], [728, 90]] + } + }, + adUnitCodes: ['usr1234'] + }], + }; + events.emit(constants.EVENTS.AUCTION_END, auction); + assert(server.requests.length > 0) + const body = JSON.parse(server.requests[0].requestBody); + var eventTypes = []; + body.events.forEach(e => eventTypes.push(e.eventType)); + assert(eventTypes.length > 0) + assert(eventTypes.indexOf(constants.EVENTS.AUCTION_END) > -1); + growthCodeAnalyticsAdapter.disableAnalytics(); + }); +}); From b87ebac3d855c08312f579e53180069fe2469695 Mon Sep 17 00:00:00 2001 From: yieldlift <61510052+yieldlift@users.noreply.github.com> Date: Mon, 28 Nov 2022 17:49:00 +0100 Subject: [PATCH 150/367] Yieldlift Bid Adapter: update ttl (#9232) * Updating TTL, changing endpoint * Test fixed Co-authored-by: Danijel Predarski --- modules/yieldliftBidAdapter.js | 6 +++--- test/spec/modules/yieldliftBidAdapter_spec.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/yieldliftBidAdapter.js b/modules/yieldliftBidAdapter.js index 160d7e9a009..6e4bce15187 100644 --- a/modules/yieldliftBidAdapter.js +++ b/modules/yieldliftBidAdapter.js @@ -2,9 +2,9 @@ import {deepSetValue, logInfo, deepAccess} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER} from '../src/mediaTypes.js'; -const ENDPOINT_URL = 'https://x.yieldlift.com/auction'; +const ENDPOINT_URL = 'https://x.yieldlift.com/pbjs'; -const DEFAULT_BID_TTL = 30; +const DEFAULT_BID_TTL = 300; const DEFAULT_CURRENCY = 'USD'; const DEFAULT_NET_REVENUE = true; @@ -98,7 +98,7 @@ export const spec = { width: bid.w, height: bid.h, ad: bid.adm, - ttl: DEFAULT_BID_TTL, + ttl: typeof bid.exp === 'number' ? bid.exp : DEFAULT_BID_TTL, creativeId: bid.crid, netRevenue: DEFAULT_NET_REVENUE, currency: DEFAULT_CURRENCY, diff --git a/test/spec/modules/yieldliftBidAdapter_spec.js b/test/spec/modules/yieldliftBidAdapter_spec.js index c2379ed7778..0cabdb594fe 100644 --- a/test/spec/modules/yieldliftBidAdapter_spec.js +++ b/test/spec/modules/yieldliftBidAdapter_spec.js @@ -229,7 +229,7 @@ describe('YieldLift', function () { 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).to.have.property('advertiserDomains', RESPONSE.body.seatbid[0].bid[index].advertiserDomains); - expect(bids[index]).to.have.property('ttl', 30); + expect(bids[index]).to.have.property('ttl', 300); expect(bids[index]).to.have.property('netRevenue', true); } }); From 638691fe83a354631f0ec866095e8df02a89ab8a Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Mon, 28 Nov 2022 09:52:31 -0700 Subject: [PATCH 151/367] Multiple analytics modules: allow pub-defined event filters; do not block auction for analytics (#9113) * Multiple analytics modules: allow pub-defined event filters for analytics * AnalyticsAdapter: make event handling non-blocking * Fix infinite recursion on nested events * Exclude AUCTION_DEBUG by default * Use a default whitelist intead of default blacklist * Try to detect and break out of infinite loops caused by events triggering other events --- .../analyticsAdapter/AnalyticsAdapter.js | 197 +++++++-------- src/events.js | 4 + test/helpers/analytics.js | 34 +++ test/mocks/analyticsStub.js | 4 +- test/spec/AnalyticsAdapter_spec.js | 235 +++++++++--------- .../modules/adWMGAnalyticsAdapter_spec.js | 18 +- .../modules/adagioAnalyticsAdapter_spec.js | 43 ++-- .../modules/bidwatchAnalyticsAdapter_spec.js | 2 - .../modules/concertAnalyticsAdapter_spec.js | 6 +- .../modules/eplanningAnalyticsAdapter_spec.js | 3 - .../modules/invisiblyAnalyticsAdapter_spec.js | 44 ++-- .../modules/konduitAnalyticsAdapter_spec.js | 2 - .../liveIntentAnalyticsAdapter_spec.js | 9 +- .../modules/medianetAnalyticsAdapter_spec.js | 8 +- .../modules/optimonAnalyticsAdapter_spec.js | 14 +- .../modules/pianoDmpAnalyticsAdapter_spec.js | 15 +- .../prebidmanagerAnalyticsAdapter_spec.js | 15 +- .../modules/pubperfAnalyticsAdapter_spec.js | 25 +- .../modules/pubstackAnalyticsAdapter_spec.js | 20 +- .../modules/pubwiseAnalyticsAdapter_spec.js | 32 +-- .../modules/sigmoidAnalyticsAdapter_spec.js | 12 +- .../modules/sovrnAnalyticsAdapter_spec.js | 24 +- .../modules/yieldoneAnalyticsAdapter_spec.js | 7 +- 23 files changed, 359 insertions(+), 414 deletions(-) create mode 100644 test/helpers/analytics.js diff --git a/libraries/analyticsAdapter/AnalyticsAdapter.js b/libraries/analyticsAdapter/AnalyticsAdapter.js index 277a1455a75..b6e270b3c3c 100644 --- a/libraries/analyticsAdapter/AnalyticsAdapter.js +++ b/libraries/analyticsAdapter/AnalyticsAdapter.js @@ -1,47 +1,68 @@ import CONSTANTS from '../../src/constants.json'; -import { ajax } from '../../src/ajax.js'; -import { logMessage, _each } from '../../src/utils.js'; -import * as events from '../../src/events.js' +import {ajax} from '../../src/ajax.js'; +import {logError, logMessage} from '../../src/utils.js'; +import * as events from '../../src/events.js'; export const _internal = { ajax }; - -const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - REQUEST_BIDS, - BID_REQUESTED, - BID_TIMEOUT, - BID_RESPONSE, - NO_BID, - BID_WON, - BID_ADJUSTMENT, - BIDDER_DONE, - SET_TARGETING, - AD_RENDER_FAILED, - AD_RENDER_SUCCEEDED, - AUCTION_DEBUG, - ADD_AD_UNITS, - BILLABLE_EVENT - } -} = CONSTANTS; - const ENDPOINT = 'endpoint'; const BUNDLE = 'bundle'; +export const DEFAULT_INCLUDE_EVENTS = Object.values(CONSTANTS.EVENTS) + .filter(ev => ev !== CONSTANTS.EVENTS.AUCTION_DEBUG); + +let debounceDelay = 100; + +export function setDebounceDelay(delay) { + debounceDelay = delay; +} + export default function AnalyticsAdapter({ url, analyticsType, global, handler }) { - const _queue = []; - let _eventCount = 0; - let _enableCheck = true; - let _handlers; - let _enabled = false; - let _sampled = true; - - if (analyticsType === ENDPOINT || BUNDLE) { - _emptyQueue(); - } + const queue = []; + let handlers; + let enabled = false; + let sampled = true; + let provider; + + const emptyQueue = (() => { + let running = false; + let timer; + const clearQueue = () => { + if (!running) { + running = true; // needed to avoid recursive re-processing when analytics event handlers trigger other events + try { + let i = 0; + let notDecreasing = 0; + while (queue.length > 0) { + i++; + const len = queue.length; + queue.shift()(); + if (queue.length >= len) { + notDecreasing++; + } else { + notDecreasing = 0 + } + if (notDecreasing >= 10) { + logError('Detected probable infinite loop, discarding events', queue) + queue.length = 0; + return; + } + } + logMessage(`${provider} analytics: processed ${i} events`); + } finally { + running = false; + } + } + }; + return function () { + if (timer != null) { + clearTimeout(timer); + timer = null; + } + debounceDelay === 0 ? clearQueue() : timer = setTimeout(clearQueue, debounceDelay); + } + })(); return Object.defineProperties({ track: _track, @@ -54,7 +75,7 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } getUrl: () => url }, { enabled: { - get: () => _enabled + get: () => enabled } }); @@ -72,69 +93,58 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } _internal.ajax(url, callback, JSON.stringify({ eventType, args })); } - function _enqueue({ eventType, args }) { - const _this = this; - - if (global && window[global] && eventType && args) { - this.track({ eventType, args }); - } else { - _queue.push(function () { - _eventCount++; - _this.track({ eventType, args }); - }); - } + function _enqueue({eventType, args}) { + queue.push(() => { + this.track({eventType, args}); + }); + emptyQueue(); } function _enable(config) { + provider = config?.provider; var _this = this; if (typeof config === 'object' && typeof config.options === 'object') { - _sampled = typeof config.options.sampling === 'undefined' || Math.random() < parseFloat(config.options.sampling); + sampled = typeof config.options.sampling === 'undefined' || Math.random() < parseFloat(config.options.sampling); } else { - _sampled = true; + sampled = true; } - if (_sampled) { + if (sampled) { + const trackedEvents = (() => { + const {includeEvents = DEFAULT_INCLUDE_EVENTS, excludeEvents = []} = (config || {}); + return new Set( + Object.values(CONSTANTS.EVENTS) + .filter(ev => includeEvents.includes(ev)) + .filter(ev => !excludeEvents.includes(ev)) + ); + })(); + // first send all events fired before enableAnalytics called events.getEvents().forEach(event => { - if (!event) { + if (!event || !trackedEvents.has(event.eventType)) { return; } const { eventType, args } = event; - - if (eventType !== BID_TIMEOUT) { - _enqueue.call(_this, { eventType, args }); - } + _enqueue.call(_this, { eventType, args }); }); // Next register event listeners to send data immediately - - _handlers = { - [REQUEST_BIDS]: args => this.enqueue({ eventType: REQUEST_BIDS, args }), - [BID_REQUESTED]: args => this.enqueue({ eventType: BID_REQUESTED, args }), - [BID_RESPONSE]: args => this.enqueue({ eventType: BID_RESPONSE, args }), - [NO_BID]: args => this.enqueue({ eventType: NO_BID, args }), - [BID_TIMEOUT]: args => this.enqueue({ eventType: BID_TIMEOUT, args }), - [BID_WON]: args => this.enqueue({ eventType: BID_WON, args }), - [BID_ADJUSTMENT]: args => this.enqueue({ eventType: BID_ADJUSTMENT, args }), - [BIDDER_DONE]: args => this.enqueue({ eventType: BIDDER_DONE, args }), - [SET_TARGETING]: args => this.enqueue({ eventType: SET_TARGETING, args }), - [AUCTION_END]: args => this.enqueue({ eventType: AUCTION_END, args }), - [AD_RENDER_FAILED]: args => this.enqueue({ eventType: AD_RENDER_FAILED, args }), - [AD_RENDER_SUCCEEDED]: args => this.enqueue({ eventType: AD_RENDER_SUCCEEDED, args }), - [AUCTION_DEBUG]: args => this.enqueue({ eventType: AUCTION_DEBUG, args }), - [ADD_AD_UNITS]: args => this.enqueue({ eventType: ADD_AD_UNITS, args }), - [BILLABLE_EVENT]: args => this.enqueue({ eventType: BILLABLE_EVENT, args }), - [AUCTION_INIT]: args => { - args.config = typeof config === 'object' ? config.options || {} : {}; // enableAnaltyics configuration object - this.enqueue({ eventType: AUCTION_INIT, args }); - } - }; - - _each(_handlers, (handler, event) => { - events.on(event, handler); - }); + handlers = Object.fromEntries( + Array.from(trackedEvents) + .map((ev) => { + const handler = ev === CONSTANTS.EVENTS.AUCTION_INIT + ? (args) => { + // TODO: remove this special case in v8 + args.config = typeof config === 'object' ? config.options || {} : {}; + this.enqueue({eventType: ev, args}); + } + : (args) => this.enqueue({eventType: ev, args}); + events.on(ev, handler); + return [ev, handler]; + }) + ) } else { logMessage(`Analytics adapter for "${global}" disabled by sampling`); } @@ -144,31 +154,14 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } this.enableAnalytics = function _enable() { return logMessage(`Analytics adapter for "${global}" already enabled, unnecessary call to \`enableAnalytics\`.`); }; - _enabled = true; + enabled = true; } function _disable() { - _each(_handlers, (handler, event) => { + Object.entries(handlers || {}).forEach(([event, handler]) => { events.off(event, handler); - }); + }) this.enableAnalytics = this._oldEnable ? this._oldEnable : _enable; - _enabled = false; - } - - function _emptyQueue() { - if (_enableCheck) { - for (var i = 0; i < _queue.length; i++) { - _queue[i](); - } - - // override push to execute the command immediately from now on - _queue.push = function (fn) { - fn(); - }; - - _enableCheck = false; - } - - logMessage(`event count sent to ${global}: ${_eventCount}`); + enabled = false; } } diff --git a/src/events.js b/src/events.js index 8e6117c3abf..62f8c070deb 100644 --- a/src/events.js +++ b/src/events.js @@ -157,3 +157,7 @@ const _public = (function () { utils._setEventEmitter(_public.emit.bind(_public)); export const {on, off, get, getEvents, emit, addEvents} = _public; + +export function clearEvents() { + eventsFired.length = 0; +} diff --git a/test/helpers/analytics.js b/test/helpers/analytics.js new file mode 100644 index 00000000000..b376118dc6f --- /dev/null +++ b/test/helpers/analytics.js @@ -0,0 +1,34 @@ +import * as pbEvents from 'src/events.js'; +import constants from '../../src/constants.json'; + +export function fireEvents(events = [ + constants.EVENTS.AUCTION_INIT, + constants.EVENTS.AUCTION_END, + constants.EVENTS.BID_REQUESTED, + constants.EVENTS.BID_RESPONSE, + constants.EVENTS.BID_WON +]) { + return events.map((ev, i) => { + ev = Array.isArray(ev) ? ev : [ev, {i: i}]; + pbEvents.emit.apply(null, ev) + return ev; + }); +} + +export function expectEvents(events) { + events = fireEvents(events); + return { + to: { + beTrackedBy(trackFn) { + events.forEach(([eventType, args]) => { + sinon.assert.calledWithMatch(trackFn, sinon.match({eventType, args})); + }); + }, + beBundledTo(bundleFn) { + events.forEach(([eventType, args]) => { + sinon.assert.calledWithMatch(bundleFn, sinon.match.any, eventType, sinon.match(args)) + }); + }, + }, + }; +} diff --git a/test/mocks/analyticsStub.js b/test/mocks/analyticsStub.js index 8507c5a6275..98e0f56688f 100644 --- a/test/mocks/analyticsStub.js +++ b/test/mocks/analyticsStub.js @@ -1,8 +1,10 @@ -import {_internal} from '../../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import {_internal, setDebounceDelay} from '../../libraries/analyticsAdapter/AnalyticsAdapter.js'; before(() => { // stub out analytics networking to avoid random events polluting the global xhr mock disableAjaxForAnalytics(); + // make analytics event handling synchronous + setDebounceDelay(0); }) export function disableAjaxForAnalytics() { diff --git a/test/spec/AnalyticsAdapter_spec.js b/test/spec/AnalyticsAdapter_spec.js index 06ab8838985..62c00e04403 100644 --- a/test/spec/AnalyticsAdapter_spec.js +++ b/test/spec/AnalyticsAdapter_spec.js @@ -1,18 +1,17 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import * as events from 'src/events.js'; import CONSTANTS from 'src/constants.json'; -import { server } from 'test/mocks/xhr.js'; +import {server} from 'test/mocks/xhr.js'; import {disableAjaxForAnalytics, enableAjaxForAnalytics} from '../mocks/analyticsStub.js'; +import {clearEvents} from 'src/events.js'; +import { + DEFAULT_EXCLUDE_EVENTS, + DEFAULT_INCLUDE_EVENTS, + setDebounceDelay +} from '../../libraries/analyticsAdapter/AnalyticsAdapter.js'; -const REQUEST_BIDS = CONSTANTS.EVENTS.REQUEST_BIDS; -const BID_REQUESTED = CONSTANTS.EVENTS.BID_REQUESTED; -const BID_RESPONSE = CONSTANTS.EVENTS.BID_RESPONSE; const BID_WON = CONSTANTS.EVENTS.BID_WON; -const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; -const AD_RENDER_FAILED = CONSTANTS.EVENTS.AD_RENDER_FAILED; -const AD_RENDER_SUCCEEDED = CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED; -const AUCTION_DEBUG = CONSTANTS.EVENTS.AUCTION_DEBUG; -const ADD_AD_UNITS = CONSTANTS.EVENTS.ADD_AD_UNITS; +const NO_BID = CONSTANTS.EVENTS.NO_BID; const AnalyticsAdapter = require('libraries/analyticsAdapter/AnalyticsAdapter.js').default; const config = { @@ -35,6 +34,7 @@ FEATURE: Analytics Adapters API afterEach(function () { adapter.disableAnalytics(); + clearEvents(); }); it('should track enable status in `enabled`', () => { @@ -43,21 +43,21 @@ FEATURE: Analytics Adapters API expect(adapter.enabled).to.equal(true); adapter.disableAnalytics(); expect(adapter.enabled).to.equal(false); - }) + }); it(`SHOULD call the endpoint WHEN an event occurs that is to be tracked`, function () { - const eventType = BID_REQUESTED; - const args = { some: 'data' }; + const eventType = BID_WON; + const args = {some: 'data'}; - adapter.track({ eventType, args }); + adapter.track({eventType, args}); let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {some: 'data'}, eventType: 'bidRequested'}); + expect(result).to.deep.equal({args: {some: 'data'}, eventType}); }); it(`SHOULD queue the event first and then track it WHEN an event occurs before tracking library is available`, function () { - const eventType = BID_RESPONSE; - const args = { wat: 'wot' }; + const eventType = BID_WON; + const args = {wat: 'wot'}; events.emit(eventType, args); adapter.enableAnalytics(); @@ -65,9 +65,58 @@ FEATURE: Analytics Adapters API // As now AUCTION_DEBUG is triggered for WARNINGS too, the BID_RESPONSE goes last in the array const index = server.requests.length - 1; let result = JSON.parse(server.requests[index].requestBody); - expect(result).to.deep.equal({eventType: 'bidResponse', args: {wat: 'wot'}}); + expect(result).to.deep.equal({eventType, args: {wat: 'wot'}}); }); + describe('event filters', () => { + function fireEvents() { + events.emit(BID_WON, {}); + events.emit(NO_BID, {}); + } + function getEvents(ev) { + return server.requests + .map(r => JSON.parse(r.requestBody)) + .filter(r => r.eventType === ev) + } + + Object.entries({ + 'whitelist includeEvents': { + includeEvents: [BID_WON] + }, + 'blacklist excludeEvents': { + excludeEvents: [NO_BID] + }, + 'give precedence to exclude over include': { + includeEvents: [BID_WON, NO_BID], + excludeEvents: [NO_BID] + } + }).forEach(([t, config]) => { + it(`should ${t}`, () => { + fireEvents(); + adapter.enableAnalytics(config); + expect(getEvents(BID_WON).length).to.eql(1); + expect(getEvents(NO_BID).length).to.eql(0); + fireEvents(); + expect(getEvents(BID_WON).length).to.eql(2); + expect(getEvents(NO_BID).length).to.eql(0); + }) + }) + }) + + it('should prevent infinite loops when track triggers other events', () => { + let i = 0; + adapter.track = ((orig) => { + return function (event) { + i++; + orig.call(this, event); + events.emit(BID_WON, {}) + } + })(adapter.track); + adapter.enableAnalytics(config); + events.emit(BID_WON, {}); + expect(i >= 100).to.eql(false); + }) + describe(`WHEN an event occurs after enable analytics\n`, function () { beforeEach(function () { sinon.stub(events, 'getEvents').returns([]); // these tests shouldn't be affected by previous tests @@ -77,108 +126,26 @@ FEATURE: Analytics Adapters API events.getEvents.restore(); }); - it('SHOULD call global when a bidWon event occurs', function () { - const eventType = BID_WON; - const args = { more: 'info' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {more: 'info'}, eventType: 'bidWon'}); - }); - - it('SHOULD call global when a adRenderFailed event occurs', function () { - const eventType = AD_RENDER_FAILED; - const args = { call: 'adRenderFailed' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'adRenderFailed'}, eventType: 'adRenderFailed'}); - }); - - it('SHOULD call global when a adRenderSucceeded event occurs', function () { - const eventType = AD_RENDER_SUCCEEDED; - const args = { call: 'adRenderSucceeded' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'adRenderSucceeded'}, eventType: 'adRenderSucceeded'}); - }); - - it('SHOULD call global when an auction debug event occurs', function () { - const eventType = AUCTION_DEBUG; - const args = { call: 'auctionDebug' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'auctionDebug'}, eventType: 'auctionDebug'}); - }); - - it('SHOULD call global when an addAdUnits event occurs', function () { - const eventType = ADD_AD_UNITS; - const args = { call: 'addAdUnits' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'addAdUnits'}, eventType: 'addAdUnits'}); - }); - - it('SHOULD call global when a requestBids event occurs', function () { - const eventType = REQUEST_BIDS; - const args = { call: 'request' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'request'}, eventType: 'requestBids'}); - }); - - it('SHOULD call global when a bidRequest event occurs', function () { - const eventType = BID_REQUESTED; - const args = { call: 'request' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'request'}, eventType: 'bidRequested'}); - }); - - it('SHOULD call global when a bidResponse event occurs', function () { - const eventType = BID_RESPONSE; - const args = { call: 'response' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'response'}, eventType: 'bidResponse'}); - }); - - it('SHOULD call global when a bidTimeout event occurs', function () { - const eventType = BID_TIMEOUT; - const args = { call: 'timeout' }; + Object.values(DEFAULT_INCLUDE_EVENTS).forEach(eventType => { + it(`SHOULD call global when a ${eventType} event occurs`, () => { + const args = {more: 'info'}; - adapter.enableAnalytics(); - events.emit(eventType, args); + adapter.enableAnalytics(); + events.emit(eventType, args); - let result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({args: {call: 'timeout'}, eventType: 'bidTimeout'}); + let result = JSON.parse(server.requests[server.requests.length - 1].requestBody); + sinon.assert.match(result, { + eventType, + args: { + more: 'info' + }, + }); + }); }); it('SHOULD NOT call global again when adapter.enableAnalytics is called with previous timeout', function () { - const eventType = BID_TIMEOUT; - const args = { call: 'timeout' }; + const eventType = BID_WON; + const args = {call: 'timeout'}; events.emit(eventType, args); adapter.enableAnalytics(); @@ -189,7 +156,7 @@ FEATURE: Analytics Adapters API describe(`AND sampling is enabled\n`, function () { const eventType = BID_WON; - const args = { more: 'info' }; + const args = {more: 'info'}; beforeEach(function () { sinon.stub(Math, 'random').returns(0.5); @@ -225,3 +192,39 @@ FEATURE: Analytics Adapters API }); }); }); + +describe('Analytics asynchronous event tracking', () => { + before(() => { + setDebounceDelay(100); + }); + after(() => { + setDebounceDelay(0); + }); + + let adapter, clock; + + beforeEach(() => { + clock = sinon.useFakeTimers(); + adapter = new AnalyticsAdapter(config); + adapter.track = sinon.stub(); + adapter.enableAnalytics({}); + }); + + afterEach(() => { + clock.restore(); + }) + + it('does not call track as long as events are coming', () => { + events.emit(BID_WON, {i: 0}); + sinon.assert.notCalled(adapter.track); + clock.tick(10); + events.emit(BID_WON, {i: 1}); + sinon.assert.notCalled(adapter.track); + clock.tick(10); + sinon.assert.notCalled(adapter.track); + clock.tick(100); + sinon.assert.calledTwice(adapter.track); + sinon.assert.calledWith(adapter.track.firstCall, {eventType: BID_WON, args: {i: 0}}); + sinon.assert.calledWith(adapter.track.secondCall, {eventType: BID_WON, args: {i: 1}}); + }); +}) diff --git a/test/spec/modules/adWMGAnalyticsAdapter_spec.js b/test/spec/modules/adWMGAnalyticsAdapter_spec.js index ab8336c7126..1e0da1bb3c8 100644 --- a/test/spec/modules/adWMGAnalyticsAdapter_spec.js +++ b/test/spec/modules/adWMGAnalyticsAdapter_spec.js @@ -1,6 +1,7 @@ import adWMGAnalyticsAdapter from 'modules/adWMGAnalyticsAdapter.js'; import { expect } from 'chai'; import { server } from 'test/mocks/xhr.js'; +import {expectEvents} from '../../helpers/analytics.js'; let adapterManager = require('src/adapterManager').default; let events = require('src/events'); let constants = require('src/constants.json'); @@ -140,14 +141,15 @@ describe('adWMG Analytics', function () { } }); - 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); + expectEvents([ + [constants.EVENTS.AUCTION_INIT, {timestamp, auctionId, timeout, adUnits}], + [constants.EVENTS.BID_REQUESTED, {}], + [constants.EVENTS.BID_RESPONSE, bidResponse], + [constants.EVENTS.NO_BID, {}], + [constants.EVENTS.BID_TIMEOUT, bidTimeoutArgs], + [constants.EVENTS.AUCTION_END, {}], + [constants.EVENTS.BID_WON, wonRequest], + ]).to.beTrackedBy(adWMGAnalyticsAdapter.track); }); it('should be two xhr requests', function () { diff --git a/test/spec/modules/adagioAnalyticsAdapter_spec.js b/test/spec/modules/adagioAnalyticsAdapter_spec.js index aee85412104..581f3cb1b87 100644 --- a/test/spec/modules/adagioAnalyticsAdapter_spec.js +++ b/test/spec/modules/adagioAnalyticsAdapter_spec.js @@ -83,34 +83,27 @@ describe('adagio analytics adapter', () => { timeToRespond: 132, }; - // Step 1: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, bidRequest); + const testEvents = { + [constants.EVENTS.BID_REQUESTED]: bidRequest, + [constants.EVENTS.BID_RESPONSE]: bidResponse, + [constants.EVENTS.AUCTION_END]: {} + }; - // Step 2: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + // Step 1-3: Send events + Object.entries(testEvents).forEach(([ev, payload]) => events.emit(ev, payload)); - // Step 3: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, {}); + function eventItem(eventName, args) { + return sinon.match({ + action: 'pb-analytics-event', + ts: sinon.match((val) => val !== undefined), + data: { + eventName, + args + } + }) + } - sandbox.assert.callCount(adagioQueuePushSpy, 3); - - const call0 = adagioQueuePushSpy.getCall(0); - expect(call0.args[0].action).to.equal('pb-analytics-event'); - expect(call0.args[0].ts).to.not.be.undefined; - expect(call0.args[0].data).to.not.be.undefined; - expect(call0.args[0].data).to.deep.equal({eventName: constants.EVENTS.BID_REQUESTED, args: bidRequest}); - - const call1 = adagioQueuePushSpy.getCall(1); - expect(call1.args[0].action).to.equal('pb-analytics-event'); - expect(call1.args[0].ts).to.not.be.undefined; - expect(call1.args[0].data).to.not.be.undefined; - expect(call1.args[0].data).to.deep.equal({eventName: constants.EVENTS.BID_RESPONSE, args: bidResponse}); - - const call2 = adagioQueuePushSpy.getCall(2); - expect(call2.args[0].action).to.equal('pb-analytics-event'); - expect(call2.args[0].ts).to.not.be.undefined; - expect(call2.args[0].data).to.not.be.undefined; - expect(call2.args[0].data).to.deep.equal({eventName: constants.EVENTS.AUCTION_END, args: {}}); + Object.entries(testEvents).forEach(([ev, payload]) => sinon.assert.calledWith(adagioQueuePushSpy, eventItem(ev, payload))); }); }); diff --git a/test/spec/modules/bidwatchAnalyticsAdapter_spec.js b/test/spec/modules/bidwatchAnalyticsAdapter_spec.js index 9e9d7dbe156..a72bb012fa1 100644 --- a/test/spec/modules/bidwatchAnalyticsAdapter_spec.js +++ b/test/spec/modules/bidwatchAnalyticsAdapter_spec.js @@ -297,7 +297,6 @@ describe('BidWatch Analytics', function () { expect(message.auctionEnd[0]).to.have.property('bidderRequests').and.to.have.lengthOf(1); expect(message.auctionEnd[0].bidderRequests[0]).to.have.property('gdprConsent'); expect(message.auctionEnd[0].bidderRequests[0].gdprConsent).not.to.have.property('vendorData'); - sinon.assert.callCount(bidwatchAnalytics.track, 4); }); it('test bidWon', function() { @@ -318,7 +317,6 @@ describe('BidWatch Analytics', function () { expect(message).not.to.have.property('ad'); expect(message).to.have.property('adId') expect(message).to.have.property('cpmIncrement').and.to.equal(27.4276); - sinon.assert.callCount(bidwatchAnalytics.track, 1); }); }); }); diff --git a/test/spec/modules/concertAnalyticsAdapter_spec.js b/test/spec/modules/concertAnalyticsAdapter_spec.js index d130aea6043..1df73ae04fe 100644 --- a/test/spec/modules/concertAnalyticsAdapter_spec.js +++ b/test/spec/modules/concertAnalyticsAdapter_spec.js @@ -1,5 +1,6 @@ import concertAnalytics from 'modules/concertAnalyticsAdapter.js'; import { expect } from 'chai'; +import {expectEvents} from '../../helpers/analytics.js'; const sinon = require('sinon'); let adapterManager = require('src/adapterManager').default; let events = require('src/events'); @@ -46,10 +47,7 @@ describe('ConcertAnalyticsAdapter', function() { it('should catch all events', function() { sandbox.spy(concertAnalytics, 'track'); - - fireBidEvents(events); - // 5 Concert events + 1 Clean.io event - sandbox.assert.callCount(concertAnalytics.track, 6); + expectEvents().to.beTrackedBy(concertAnalytics.track); }); it('should report data for BID_RESPONSE, BID_WON events', function() { diff --git a/test/spec/modules/eplanningAnalyticsAdapter_spec.js b/test/spec/modules/eplanningAnalyticsAdapter_spec.js index bb9e6c4fb86..419181de983 100644 --- a/test/spec/modules/eplanningAnalyticsAdapter_spec.js +++ b/test/spec/modules/eplanningAnalyticsAdapter_spec.js @@ -152,9 +152,6 @@ describe('eplanning analytics adapter', function () { // Step 10 check that the host to send the ajax request is configurable via options expect(eplAnalyticsAdapter.context.host).to.equal(initOptions.host); - - // Step 11 verify that we received 7 events (6 E-Planning events + 1 Clean.io event) - sinon.assert.callCount(eplAnalyticsAdapter.track, 7); }); }); }); diff --git a/test/spec/modules/invisiblyAnalyticsAdapter_spec.js b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js index d97b0925713..3b3542d43b0 100644 --- a/test/spec/modules/invisiblyAnalyticsAdapter_spec.js +++ b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js @@ -1,5 +1,6 @@ import invisiblyAdapter from 'modules/invisiblyAnalyticsAdapter.js'; import { expect } from 'chai'; +import {expectEvents} from '../../helpers/analytics.js'; let events = require('src/events'); let constants = require('src/constants.json'); @@ -197,14 +198,8 @@ describe('Invisibly Analytics Adapter test suite', function () { 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); - // 5 Invisibly events + 1 Clean.io event - sinon.assert.callCount(invisiblyAdapter.track, 6); + expectEvents().to.beTrackedBy(invisiblyAdapter.track); }); it('should not catch events triggered without invisibly account config', function () { @@ -382,9 +377,6 @@ describe('Invisibly Analytics Adapter test suite', function () { expect(invisiblyEvents.event_data.pageViewId).to.exist; expect(invisiblyEvents.event_data.ver).to.equal(1); expect(invisiblyEvents.event_type).to.equal('PREBID_bidWon'); - - // 1 Invisibly event + 1 Clean.io event - sinon.assert.callCount(invisiblyAdapter.track, 2); }); // spec for bidder done event @@ -522,7 +514,6 @@ describe('Invisibly Analytics Adapter test suite', function () { expect(invisiblyEvents.event_data.auctionId).to.equal( MOCK.AUCTION_END.auctionId ); - sinon.assert.callCount(invisiblyAdapter.track, 1); }); // should not call sendEvent for events not supported by the adapter @@ -541,22 +532,21 @@ describe('Invisibly Analytics Adapter test suite', function () { 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); - - // 13 Invisibly events + 1 Clean.io event - sinon.assert.callCount(invisiblyAdapter.track, 14); + expectEvents([ + constants.EVENTS.AUCTION_INIT, + constants.EVENTS.AUCTION_END, + constants.EVENTS.BID_ADJUSTMENT, + constants.EVENTS.BID_TIMEOUT, + constants.EVENTS.BID_REQUESTED, + constants.EVENTS.BID_RESPONSE, + constants.EVENTS.NO_BID, + constants.EVENTS.BID_WON, + constants.EVENTS.BIDDER_DONE, + constants.EVENTS.SET_TARGETING, + constants.EVENTS.REQUEST_BIDS, + constants.EVENTS.ADD_AD_UNITS, + constants.EVENTS.AD_RENDER_FAILED + ]).to.beTrackedBy(invisiblyAdapter.track); }); }); diff --git a/test/spec/modules/konduitAnalyticsAdapter_spec.js b/test/spec/modules/konduitAnalyticsAdapter_spec.js index 1612138cde4..e79ae2feeeb 100644 --- a/test/spec/modules/konduitAnalyticsAdapter_spec.js +++ b/test/spec/modules/konduitAnalyticsAdapter_spec.js @@ -121,7 +121,5 @@ describe(`Konduit Analytics Adapter`, () => { expect(requestBody.konduitId).to.be.equal(konduitId); expect(requestBody.prebidVersion).to.be.equal('$prebid.version$'); expect(requestBody.environment).to.be.an('object'); - // 6 Konduit events + 1 Clean.io event - sinon.assert.callCount(konduitAnalyticsAdapter.track, 7); }); }); diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index b3a452e5ece..fa4c5cd8cad 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -2,6 +2,7 @@ import liAnalytics from 'modules/liveIntentAnalyticsAdapter'; import { expect } from 'chai'; import { server } from 'test/mocks/xhr.js'; import { auctionManager } from 'src/auctionManager.js'; +import {expectEvents} from '../../helpers/analytics.js'; let utils = require('src/utils'); let refererDetection = require('src/refererDetection'); @@ -286,12 +287,8 @@ describe('LiveIntent Analytics Adapter ', () => { }); it('track is called', () => { - liAnalytics.enableAnalytics(config); sandbox.stub(liAnalytics, 'track'); - events.emit(constants.EVENTS.AUCTION_END, args); - events.emit(constants.EVENTS.AUCTION_END, args); - events.emit(constants.EVENTS.AUCTION_END, args); - clock.tick(6000); - sinon.assert.callCount(liAnalytics.track, 3) + liAnalytics.enableAnalytics(config); + expectEvents().to.beTrackedBy(liAnalytics.track); }) }); diff --git a/test/spec/modules/medianetAnalyticsAdapter_spec.js b/test/spec/modules/medianetAnalyticsAdapter_spec.js index b75437f2ccd..c408f23c4f4 100644 --- a/test/spec/modules/medianetAnalyticsAdapter_spec.js +++ b/test/spec/modules/medianetAnalyticsAdapter_spec.js @@ -3,6 +3,7 @@ import medianetAnalytics from 'modules/medianetAnalyticsAdapter.js'; import * as utils from 'src/utils.js'; import CONSTANTS from 'src/constants.json'; import * as events from 'src/events.js'; +import {clearEvents} from 'src/events.js'; const { EVENTS: { AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, NO_BID, BID_TIMEOUT, AUCTION_END, SET_TARGETING, BID_WON } @@ -127,7 +128,12 @@ describe('Media.net Analytics Adapter', function() { options: { cid: CUSTOMER_ID } - }; + } + + before(() => { + clearEvents(); + }); + beforeEach(function () { sandbox = sinon.sandbox.create(); }); diff --git a/test/spec/modules/optimonAnalyticsAdapter_spec.js b/test/spec/modules/optimonAnalyticsAdapter_spec.js index 406e9cb75c4..f1aa00334b5 100644 --- a/test/spec/modules/optimonAnalyticsAdapter_spec.js +++ b/test/spec/modules/optimonAnalyticsAdapter_spec.js @@ -4,6 +4,7 @@ import optimonAnalyticsAdapter from '../../../modules/optimonAnalyticsAdapter.js import adapterManager from 'src/adapterManager'; import * as events from 'src/events'; import constants from 'src/constants.json' +import {expectEvents} from '../../helpers/analytics.js'; const AD_UNIT_CODE = 'demo-adunit-1'; const PUBLISHER_CONFIG = { @@ -14,14 +15,12 @@ const PUBLISHER_CONFIG = { describe('Optimon Analytics Adapter', () => { const optmn_currentWindow = utils.getWindowSelf(); - let optmn_queue = []; beforeEach(() => { - optmn_currentWindow.OptimonAnalyticsAdapter = (...optmn_args) => optmn_queue.push(optmn_args); + optmn_currentWindow.OptimonAnalyticsAdapter = sinon.stub() adapterManager.enableAnalytics({ provider: 'optimon' }); - optmn_queue = [] }); afterEach(() => { @@ -29,13 +28,6 @@ describe('Optimon Analytics Adapter', () => { }); it('should forward all events to the queue', () => { - const optmn_arguments = [AD_UNIT_CODE, PUBLISHER_CONFIG]; - - events.emit(constants.EVENTS.AUCTION_END, optmn_arguments) - events.emit(constants.EVENTS.BID_TIMEOUT, optmn_arguments) - events.emit(constants.EVENTS.BID_WON, optmn_arguments) - - // 3 Optimon events + 1 Clean.io event - expect(optmn_queue.length).to.eql(4); + expectEvents().to.beBundledTo(optmn_currentWindow.OptimonAnalyticsAdapter); }); }); diff --git a/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js b/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js index 49b048f1fe6..0c4949264a7 100644 --- a/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js +++ b/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js @@ -52,19 +52,12 @@ describe('Piano DMP Analytics Adapter', () => { // Then const callQueue = (window.cX || {}).callQueue; - const billableEventIndex = callQueue.findIndex(([, params]) => params.eventType === constants.EVENTS.BILLABLE_EVENT); - if (billableEventIndex > -1) { - callQueue.splice(billableEventIndex, 1); - } - expect(callQueue).to.be.an('array'); - expect(callQueue.length).to.equal(testEvents.length); - - callQueue.forEach(([method, params], index) => { + testEvents.forEach(({event, args}) => { + const [method, params] = callQueue.filter(item => item[1].eventType === event)[0]; expect(method).to.equal('prebid'); - expect(params.eventType).to.equal(testEvents[index].event); - expect(params.params).to.deep.equal(testEvents[index].args); - }); + expect(params.params).to.deep.equal(args); + }) }); }); }); diff --git a/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js b/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js index 2e1bf4df062..522a78627d7 100644 --- a/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js +++ b/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js @@ -1,9 +1,8 @@ -import prebidmanagerAnalytics, { - storage -} from 'modules/prebidmanagerAnalyticsAdapter.js'; +import prebidmanagerAnalytics, {storage} from 'modules/prebidmanagerAnalyticsAdapter.js'; import {expect} from 'chai'; import {server} from 'test/mocks/xhr.js'; import * as utils from 'src/utils.js'; +import {expectEvents} from '../../helpers/analytics.js'; let events = require('src/events'); let constants = require('src/constants.json'); @@ -95,15 +94,7 @@ describe('Prebid Manager Analytics Adapter', function () { } }); - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_TIMEOUT, {}); - - // 6 Prebid Manager events + 1 Clean.io event - sinon.assert.callCount(prebidmanagerAnalytics.track, 7); + expectEvents().to.beTrackedBy(prebidmanagerAnalytics.track); }); }); diff --git a/test/spec/modules/pubperfAnalyticsAdapter_spec.js b/test/spec/modules/pubperfAnalyticsAdapter_spec.js index 160529125d3..9949d87a2bc 100644 --- a/test/spec/modules/pubperfAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubperfAnalyticsAdapter_spec.js @@ -1,9 +1,10 @@ import pubperfAnalytics from 'modules/pubperfAnalyticsAdapter.js'; -import { expect } from 'chai'; -import { server } from 'test/mocks/xhr.js'; +import {expect} from 'chai'; +import {server} from 'test/mocks/xhr.js'; +import {expectEvents, fireEvents} from '../../helpers/analytics.js'; + let events = require('src/events'); let utils = require('src/utils.js'); -let constants = require('src/constants.json'); describe('Pubperf Analytics Adapter', function() { describe('Prebid Manager Analytic tests', function() { @@ -22,13 +23,7 @@ describe('Pubperf Analytics Adapter', function() { provider: 'pubperf' }); - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_TIMEOUT, {}); - + fireEvents(); expect(server.requests.length).to.equal(0); expect(utils.logError.called).to.equal(true); }); @@ -42,15 +37,7 @@ describe('Pubperf Analytics Adapter', function() { provider: 'pubperf' }); - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_TIMEOUT, {}); - - // 6 Pubperf events + 1 Clean.io event - sinon.assert.callCount(pubperfAnalytics.track, 7); + expectEvents().to.beTrackedBy(pubperfAnalytics.track); }); }); }); diff --git a/test/spec/modules/pubstackAnalyticsAdapter_spec.js b/test/spec/modules/pubstackAnalyticsAdapter_spec.js index 3d01a0bb506..fe7441e91e5 100644 --- a/test/spec/modules/pubstackAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubstackAnalyticsAdapter_spec.js @@ -3,17 +3,16 @@ import pubstackAnalytics from '../../../modules/pubstackAnalyticsAdapter.js'; import adapterManager from 'src/adapterManager'; import * as events from 'src/events'; import constants from 'src/constants.json' +import {expectEvents} from '../../helpers/analytics.js'; describe('Pubstack Analytics Adapter', () => { const scope = utils.getWindowSelf(); - let queue = []; beforeEach(() => { - scope.PubstackAnalytics = (...args) => queue.push(args); + scope.PubstackAnalytics = sinon.stub(); adapterManager.enableAnalytics({ provider: 'pubstack' }); - queue = [] }); afterEach(() => { @@ -21,19 +20,6 @@ describe('Pubstack Analytics Adapter', () => { }); 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 - // 6 Pubstack events + 1 Clean.io event - expect(queue.length).to.eql(7); + expectEvents().to.beBundledTo(scope.PubstackAnalytics); }); }); diff --git a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js index dd5c223b767..e14582edc39 100644 --- a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js @@ -1,6 +1,7 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import pubwiseAnalytics from 'modules/pubwiseAnalyticsAdapter.js'; -import {server} from 'test/mocks/xhr.js'; +import {expectEvents} from '../../helpers/analytics.js'; + let events = require('src/events'); let adapterManager = require('src/adapterManager').default; let constants = require('src/constants.json'); @@ -58,23 +59,16 @@ describe('PubWise Prebid Analytics', function () { sandbox.spy(pubwiseAnalytics, 'track'); - // sent - events.emit(constants.EVENTS.AUCTION_INIT, mock.AUCTION_INIT); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - events.emit(constants.EVENTS.AD_RENDER_FAILED, {}); - events.emit(constants.EVENTS.TCF2_ENFORCEMENT, {}); - events.emit(constants.EVENTS.BID_TIMEOUT, {}); - - // forces flush - events.emit(constants.EVENTS.AUCTION_END, {}); - - // eslint-disable-next-line - //console.log(requests); - - /* testing for 6 calls, including the 2 we're not currently tracking */ - sandbox.assert.callCount(pubwiseAnalytics.track, 8); + expectEvents([ + constants.EVENTS.AUCTION_INIT, + constants.EVENTS.BID_REQUESTED, + constants.EVENTS.BID_RESPONSE, + constants.EVENTS.BID_WON, + constants.EVENTS.AD_RENDER_FAILED, + constants.EVENTS.TCF2_ENFORCEMENT, + constants.EVENTS.BID_TIMEOUT, + constants.EVENTS.AUCTION_END, + ]).to.beTrackedBy(pubwiseAnalytics.track); }); it('should initialize the auction properly', function () { diff --git a/test/spec/modules/sigmoidAnalyticsAdapter_spec.js b/test/spec/modules/sigmoidAnalyticsAdapter_spec.js index 6d772de02eb..6cdc3c448b9 100644 --- a/test/spec/modules/sigmoidAnalyticsAdapter_spec.js +++ b/test/spec/modules/sigmoidAnalyticsAdapter_spec.js @@ -1,5 +1,7 @@ import sigmoidAnalytic from 'modules/sigmoidAnalyticsAdapter.js'; -import { expect } from 'chai'; +import {expect} from 'chai'; +import {expectEvents} from '../../helpers/analytics.js'; + let events = require('src/events'); let adapterManager = require('src/adapterManager').default; let constants = require('src/constants.json'); @@ -32,13 +34,7 @@ describe('sigmoid Prebid Analytic', function () { } }); - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - - sinon.assert.callCount(sigmoidAnalytic.track, 8); + expectEvents().to.beTrackedBy(sigmoidAnalytic.track); }); }); describe('build utm tag data', function () { diff --git a/test/spec/modules/sovrnAnalyticsAdapter_spec.js b/test/spec/modules/sovrnAnalyticsAdapter_spec.js index 8284bb54e9b..68552eb3d8a 100644 --- a/test/spec/modules/sovrnAnalyticsAdapter_spec.js +++ b/test/spec/modules/sovrnAnalyticsAdapter_spec.js @@ -1,8 +1,10 @@ import sovrnAnalyticsAdapter from '../../../modules/sovrnAnalyticsAdapter.js'; -import { expect } from 'chai'; +import {expect} from 'chai'; import {config} from 'src/config.js'; import adaptermanager from 'src/adapterManager.js'; -import { server } from 'test/mocks/xhr.js'; +import {server} from 'test/mocks/xhr.js'; +import {expectEvents, fireEvents} from '../../helpers/analytics.js'; + var assert = require('assert'); let events = require('src/events'); @@ -195,15 +197,7 @@ describe('Sovrn Analytics Adapter', function () { sovrnId: 123 } }); - - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - - // 5 SovrnAnalytics events + 1 Clean.io event - sinon.assert.callCount(sovrnAnalyticsAdapter.track, 6); + expectEvents().to.beTrackedBy(sovrnAnalyticsAdapter.track); }); it('should catch no events if no affiliate id', function () { @@ -212,13 +206,7 @@ describe('Sovrn Analytics Adapter', function () { options: { } }); - - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); - + fireEvents(); sinon.assert.callCount(sovrnAnalyticsAdapter.track, 0); }); }); diff --git a/test/spec/modules/yieldoneAnalyticsAdapter_spec.js b/test/spec/modules/yieldoneAnalyticsAdapter_spec.js index f55577913a5..ea52f89773e 100644 --- a/test/spec/modules/yieldoneAnalyticsAdapter_spec.js +++ b/test/spec/modules/yieldoneAnalyticsAdapter_spec.js @@ -1,6 +1,7 @@ import yieldoneAnalytics from 'modules/yieldoneAnalyticsAdapter.js'; import { targeting } from 'src/targeting.js'; import { expect } from 'chai'; +import _ from 'lodash'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; let constants = require('src/constants.json'); @@ -225,7 +226,9 @@ describe('Yieldone Prebid Analytic', function () { pubId: initOptions.pubId, page: {url: testReferrer}, wrapper_version: '$prebid.version$', - events: expectedEvents + events: sinon.match(evs => { + return !expectedEvents.some((expectedEvent) => evs.find(ev => _.isEqual(ev, expectedEvent)) === -1) + }) }; const preparedWinnerParams = Object.assign({adServerTargeting: fakeTargeting}, winner); @@ -262,7 +265,7 @@ describe('Yieldone Prebid Analytic', function () { events.emit(constants.EVENTS.AUCTION_END, auctionEnd); - expect(yieldoneAnalytics.eventsStorage[auctionId]).to.deep.equal(expectedResult); + sinon.assert.match(yieldoneAnalytics.eventsStorage[auctionId], expectedResult); delete yieldoneAnalytics.eventsStorage[auctionId]; From 54d225674f26446fddee1a85103e179fd98e4bc4 Mon Sep 17 00:00:00 2001 From: Karim Mourra Date: Mon, 28 Nov 2022 11:53:43 -0500 Subject: [PATCH 152/367] JW Player RTD Module: prefer segment.id to segment.value (#9153) * removes id * updates docs * Revert "updates docs" This reverts commit 926a06dd9581868e6fd9e682e68b48592aebbd3e. * Revert "removes id" This reverts commit c3a1be70e7274451b6b60381c036385b579eb23b. * drop segment.value --- modules/gridBidAdapter.js | 2 +- modules/gridNMBidAdapter.js | 2 +- modules/jwplayerRtdProvider.js | 3 +-- test/spec/modules/jwplayerRtdProvider_spec.js | 6 +++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index 3aaeaf73580..b300c5c58c0 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -652,7 +652,7 @@ function getUserIdFromFPDStorage() { function segmentProcessing(segment, forceSegName) { return segment .map((seg) => { - const value = seg && (seg.value || seg.id || seg); + const value = seg && (seg.id || seg); if (typeof value === 'string' || typeof value === 'number') { return { value: value.toString(), diff --git a/modules/gridNMBidAdapter.js b/modules/gridNMBidAdapter.js index 6f8eaba43d3..c49b7619c07 100644 --- a/modules/gridNMBidAdapter.js +++ b/modules/gridNMBidAdapter.js @@ -432,7 +432,7 @@ export function getSyncUrl() { function segmentProcessing(segment, forceSegName) { return segment .map((seg) => { - const value = seg && (seg.value || seg.id || seg); + const value = seg && (seg.id || seg); if (typeof value === 'string' || typeof value === 'number') { return { value: value.toString(), diff --git a/modules/jwplayerRtdProvider.js b/modules/jwplayerRtdProvider.js index 342531ba26e..b79843dccfd 100644 --- a/modules/jwplayerRtdProvider.js +++ b/modules/jwplayerRtdProvider.js @@ -274,8 +274,7 @@ export function getContentSegments(segments) { const formattedSegments = segments.reduce((convertedSegments, rawSegment) => { convertedSegments.push({ - id: rawSegment, - value: rawSegment + id: rawSegment }); return convertedSegments; }, []); diff --git a/test/spec/modules/jwplayerRtdProvider_spec.js b/test/spec/modules/jwplayerRtdProvider_spec.js index 77c8ce58442..5a38a971e09 100644 --- a/test/spec/modules/jwplayerRtdProvider_spec.js +++ b/test/spec/modules/jwplayerRtdProvider_spec.js @@ -659,9 +659,9 @@ describe('jwplayerRtdProvider', function() { const segment2 = 'segment2'; const segment3 = 'segment3'; const contentSegments = getContentSegments([segment1, segment2, segment3]); - expect(contentSegments[0]).to.deep.equal({ id: segment1, value: segment1 }); - expect(contentSegments[1]).to.deep.equal({ id: segment2, value: segment2 }); - expect(contentSegments[2]).to.deep.equal({ id: segment3, value: segment3 }); + expect(contentSegments[0]).to.deep.equal({ id: segment1 }); + expect(contentSegments[1]).to.deep.equal({ id: segment2 }); + expect(contentSegments[2]).to.deep.equal({ id: segment3 }); }); }); From 4f21a5bc9e2e4ace066a4d26ca1c9c637c46a477 Mon Sep 17 00:00:00 2001 From: AcuityAdsIntegrations <72594990+AcuityAdsIntegrations@users.noreply.github.com> Date: Mon, 28 Nov 2022 18:56:39 +0200 Subject: [PATCH 153/367] AcuityAds adapter: fix issue with download (#9164) * add prebid.js adapter * changes * changes * changes * changes * fix downolad --- modules/{acuityAdsBidAdapter.js => acuityadsBidAdapter.js} | 0 modules/{acuityAdsBidAdapter.md => acuityadsBidAdapter.md} | 0 ...{acuityAdsBidAdapter_spec.js => acuityadsBidAdapter_spec.js} | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename modules/{acuityAdsBidAdapter.js => acuityadsBidAdapter.js} (100%) rename modules/{acuityAdsBidAdapter.md => acuityadsBidAdapter.md} (100%) rename test/spec/modules/{acuityAdsBidAdapter_spec.js => acuityadsBidAdapter_spec.js} (99%) diff --git a/modules/acuityAdsBidAdapter.js b/modules/acuityadsBidAdapter.js similarity index 100% rename from modules/acuityAdsBidAdapter.js rename to modules/acuityadsBidAdapter.js diff --git a/modules/acuityAdsBidAdapter.md b/modules/acuityadsBidAdapter.md similarity index 100% rename from modules/acuityAdsBidAdapter.md rename to modules/acuityadsBidAdapter.md diff --git a/test/spec/modules/acuityAdsBidAdapter_spec.js b/test/spec/modules/acuityadsBidAdapter_spec.js similarity index 99% rename from test/spec/modules/acuityAdsBidAdapter_spec.js rename to test/spec/modules/acuityadsBidAdapter_spec.js index 18ea574c1ce..2497b435a19 100644 --- a/test/spec/modules/acuityAdsBidAdapter_spec.js +++ b/test/spec/modules/acuityadsBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from '../../../modules/acuityAdsBidAdapter'; +import { spec } from '../../../modules/acuityadsBidAdapter'; import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js'; import { getUniqueIdentifierStr } from '../../../src/utils.js'; From ebf6272f175160688fbccb5213a0fad98324723c Mon Sep 17 00:00:00 2001 From: Giovanni Sollazzo Date: Mon, 28 Nov 2022 18:00:59 +0100 Subject: [PATCH 154/367] AIDEM Bid Adapter: initial adapter release (#9222) * AIDEM Bid Adapter * Added _spec.js * update * Fix Navigator in _spec.js * Removed timeout handler. * Added publisherId as required bidder params * moved publisherId into site publisher object Co-authored-by: darkstar --- modules/aidemBidAdapter.js | 492 ++++++++++++++++ modules/aidemBidAdapter.md | 187 ++++++ test/spec/modules/aidemBidAdapter_spec.js | 664 ++++++++++++++++++++++ 3 files changed, 1343 insertions(+) create mode 100644 modules/aidemBidAdapter.js create mode 100644 modules/aidemBidAdapter.md create mode 100644 test/spec/modules/aidemBidAdapter_spec.js diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js new file mode 100644 index 00000000000..41bf680db1c --- /dev/null +++ b/modules/aidemBidAdapter.js @@ -0,0 +1,492 @@ +import {_each, contains, deepAccess, deepSetValue, getDNT, isBoolean, isStr, logError, logInfo} from '../src/utils.js'; +import {config} from '../src/config.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {getRefererInfo} from '../src/refererDetection.js'; +import {ajax} from '../src/ajax.js'; + +const BIDDER_CODE = 'aidem'; +const BASE_URL = 'https://zero.aidemsrv.com'; +const LOCAL_BASE_URL = 'http://127.0.0.1:8787'; + +const AVAILABLE_CURRENCIES = ['USD']; +const DEFAULT_CURRENCY = ['USD']; // NOTE - USD is the only supported currency right now; Hardcoded for bids +const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO]; +const REQUIRED_VIDEO_PARAMS = [ 'mimes', 'protocols', 'context' ]; + +export const ERROR_CODES = { + BID_SIZE_INVALID_FORMAT: 1, + BID_SIZE_NOT_INCLUDED: 2, + PROPERTY_NOT_INCLUDED: 3, + SITE_ID_INVALID_VALUE: 4, + MEDIA_TYPE_NOT_SUPPORTED: 5, + PUBLISHER_ID_INVALID_VALUE: 6, +}; + +const endpoints = { + request: `${BASE_URL}/bid/request`, + notice: { + win: `${BASE_URL}/notice/win`, + timeout: `${BASE_URL}/notice/timeout`, + error: `${BASE_URL}/notice/error`, + } +} + +export function setEndPoints(env = null, path = '', mediaType = BANNER) { + switch (env) { + case 'local': + endpoints.request = mediaType === BANNER ? `${LOCAL_BASE_URL}${path}/bid/request` : `${LOCAL_BASE_URL}${path}/bid/videorequest` + endpoints.notice.win = `${LOCAL_BASE_URL}${path}/notice/win` + endpoints.notice.error = `${LOCAL_BASE_URL}${path}/notice/error` + endpoints.notice.timeout = `${LOCAL_BASE_URL}${path}/notice/timeout` + break; + case 'main': + endpoints.request = mediaType === BANNER ? `${BASE_URL}${path}/bid/request` : `${BASE_URL}${path}/bid/videorequest` + endpoints.notice.win = `${BASE_URL}${path}/notice/win` + endpoints.notice.error = `${BASE_URL}${path}/notice/error` + endpoints.notice.timeout = `${BASE_URL}${path}/notice/timeout` + break; + } + return endpoints +} + +config.getConfig('aidem', function (config) { + if (config.aidem.env) { setEndPoints(config.aidem.env, config.aidem.path, config.aidem.mediaType) } +}) + +// AIDEM Custom FN +function recur(obj) { + var result = {}; var _tmp; + for (var i in obj) { + // enabledPlugin is too nested, also skip functions + if (!(i === 'enabledPlugin' || typeof obj[i] === 'function')) { + if (typeof obj[i] === 'object' && obj[i] !== null) { + // get props recursively + _tmp = recur(obj[i]); + // if object is not {} + if (Object.keys(_tmp).length) { + result[i] = _tmp; + } + } else { + // string, number or boolean + result[i] = obj[i]; + } + } + } + return result; +} + +// ================================================================================= +function getConnectionType() { + const connection = navigator.connection || navigator.webkitConnection; + if (!connection) { + return 0; + } + switch (connection.type) { + case 'ethernet': + return 1; + case 'wifi': + return 2; + case 'cellular': + switch (connection.effectiveType) { + case 'slow-2g': + return 4; + case '2g': + return 4; + case '3g': + return 5; + case '4g': + return 6; + case '5g': + return 7; + default: + return 3; + } + default: + return 0; + } +} + +function getDevice() { + const language = navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage; + return { + ua: navigator.userAgent, + dnt: !!getDNT(), + language: language, + connectiontype: getConnectionType(), + screen_width: screen.width, + screen_height: screen.height + }; +} + +function getRegs() { + let regs = {}; + const consentManagement = config.getConfig('consentManagement') + const coppa = config.getConfig('coppa') + if (consentManagement && !!(consentManagement.gdpr)) { + deepSetValue(regs, 'gdpr_applies', !!consentManagement.gdpr); + } else { + deepSetValue(regs, 'gdpr_applies', false); + } + if (consentManagement && deepAccess(consentManagement, 'usp.cmpApi') === 'static') { + deepSetValue(regs, 'usp_applies', !!deepAccess(consentManagement, 'usp')); + deepSetValue(regs, 'us_privacy', deepAccess(consentManagement, 'usp.consentData.getUSPData.uspString')); + } else { + deepSetValue(regs, 'usp_applies', false); + } + + if (isBoolean(coppa)) { + deepSetValue(regs, 'coppa_applies', !!coppa); + } else { + deepSetValue(regs, 'coppa_applies', false); + } + + return regs; +} + +function getPageUrl(bidderRequest) { + return bidderRequest?.refererInfo?.page +} + +function buildWinNotice(bid) { + return { + burl: deepAccess(bid, 'meta.burl'), + cpm: bid.cpm, + currency: bid.currency, + impid: deepAccess(bid, 'meta.impid'), + dsp_id: deepAccess(bid, 'meta.dsp_id'), + adUnitCode: bid.adUnitCode, + auctionId: bid.auctionId, + transactionId: bid.transactionId, + ttl: bid.ttl, + requestTimestamp: bid.requestTimestamp, + responseTimestamp: bid.responseTimestamp, + } +} + +function buildErrorNotice(prebidErrorResponse) { + return { + message: `Prebid.js: Server call for ${prebidErrorResponse.bidderCode} failed.`, + url: encodeURIComponent(getPageUrl(prebidErrorResponse)), + auctionId: prebidErrorResponse.auctionId, + bidderRequestId: prebidErrorResponse.bidderRequestId, + metrics: {} + } +} + +function hasValidFloor(obj) { + if (!obj) return false + const hasValue = !isNaN(Number(obj.value)) + const hasCurrency = contains(AVAILABLE_CURRENCIES, obj.currency) + return hasValue && hasCurrency +} + +function getMediaType(bidRequest) { + if ((bidRequest.mediaTypes && bidRequest.mediaTypes.hasOwnProperty('video')) || bidRequest.params.hasOwnProperty('video')) { return VIDEO } + return BANNER +} + +function getPrebidRequestFields(bidderRequest, bidRequests) { + const payload = {} + // Base Payload Data + deepSetValue(payload, 'id', bidderRequest.auctionId); + // Impressions + setPrebidImpressionObject(bidRequests, payload) + // Device + deepSetValue(payload, 'device', getDevice()) + // Timeout + deepSetValue(payload, 'tmax', bidderRequest.timeout); + // Currency + deepSetValue(payload, 'cur', DEFAULT_CURRENCY); + // Timezone + deepSetValue(payload, 'tz', new Date().getTimezoneOffset()); + // Privacy Regs + deepSetValue(payload, 'regs', getRegs()); + // Site + setPrebidSiteObject(bidderRequest, payload) + // Environment + setPrebidRequestEnvironment(payload) + // AT auction type + deepSetValue(payload, 'at', 1); + + return payload +} + +function setPrebidImpressionObject(bidRequests, payload) { + payload.imp = []; + _each(bidRequests, function (bidRequest) { + const impressionObject = {}; + // Placement or ad tag used to initiate the auction + deepSetValue(impressionObject, 'id', bidRequest.bidId); + // Transaction id + deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'transactionId')); + // Publisher id + deepSetValue(payload, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); + // Site id + deepSetValue(payload, 'site.id', deepAccess(bidRequest, 'params.siteId')); + const mediaType = getMediaType(bidRequest) + switch (mediaType) { + case 'banner': + setPrebidImpressionObjectBanner(bidRequest, impressionObject) + break; + case 'video': + setPrebidImpressionObjectVideo(bidRequest, impressionObject) + break; + } + + // Floor (optional) + setPrebidImpressionObjectFloor(bidRequest, impressionObject) + + impressionObject.imp_ext = {}; + + payload.imp.push(impressionObject); + }); +} + +function setPrebidSiteObject(bidderRequest, payload) { + deepSetValue(payload, 'site.domain', deepAccess(bidderRequest, 'refererInfo.domain')); + deepSetValue(payload, 'site.page', deepAccess(bidderRequest, 'refererInfo.page')); + deepSetValue(payload, 'site.referer', deepAccess(bidderRequest, 'refererInfo.ref')); + deepSetValue(payload, 'site.cat', deepAccess(bidderRequest, 'ortb2.site.cat')); + deepSetValue(payload, 'site.sectioncat', deepAccess(bidderRequest, 'ortb2.site.sectioncat')); + deepSetValue(payload, 'site.keywords', deepAccess(bidderRequest, 'ortb2.site.keywords')); + deepSetValue(payload, 'site.site_ext', deepAccess(bidderRequest, 'ortb2.site.ext')); // see https://docs.prebid.org/features/firstPartyData.html +} + +function setPrebidRequestEnvironment(payload) { + const __navigator = JSON.parse(JSON.stringify(recur(navigator))); + delete __navigator.plugins; + deepSetValue(payload, 'environment.ri', getRefererInfo()); + deepSetValue(payload, 'environment.hl', window.history.length); + deepSetValue(payload, 'environment.nav', __navigator); + deepSetValue(payload, 'environment.inp.euc', window.encodeURIComponent.name === 'encodeURIComponent' && typeof window.encodeURIComponent.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.eu', window.encodeURI.name === 'encodeURI' && typeof window.encodeURI.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.js', window.JSON.stringify.name === 'stringify' && typeof window.JSON.stringify.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.jp', window.JSON.parse.name === 'parse' && typeof window.JSON.parse.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.ofe', window.Object.fromEntries.name === 'fromEntries' && typeof window.Object.fromEntries.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.oa', window.Object.assign.name === 'assign' && typeof window.Object.assign.prototype === 'undefined'); +} + +function setPrebidImpressionObjectFloor(bidRequest, impressionObject) { + const floor = deepAccess(bidRequest, 'params.floor') + if (hasValidFloor(floor)) { + deepSetValue(impressionObject, 'floor.value', floor.value) + deepSetValue(impressionObject, 'floor.currency', floor.currency) + } +} + +function setPrebidImpressionObjectBanner(bidRequest, impressionObject) { + deepSetValue(impressionObject, 'mediatype', BANNER); + deepSetValue(impressionObject, 'banner.topframe', 1); + deepSetValue(impressionObject, 'banner.format', []); + _each(bidRequest.mediaTypes.banner.sizes, function (bannerFormat) { + const format = {}; + deepSetValue(format, 'w', bannerFormat[0]); + deepSetValue(format, 'h', bannerFormat[1]); + deepSetValue(format, 'format_ext', {}); + impressionObject.banner.format.push(format); + }); +} + +function setPrebidImpressionObjectVideo(bidRequest, impressionObject) { + deepSetValue(impressionObject, 'mediatype', VIDEO); + deepSetValue(impressionObject, 'video.format', []); + deepSetValue(impressionObject, 'video.mimes', bidRequest.mediaTypes.video.mimes); + deepSetValue(impressionObject, 'video.minDuration', bidRequest.mediaTypes.video.minduration); + deepSetValue(impressionObject, 'video.maxDuration', bidRequest.mediaTypes.video.maxduration); + deepSetValue(impressionObject, 'video.protocols', bidRequest.mediaTypes.video.protocols); + deepSetValue(impressionObject, 'video.context', bidRequest.mediaTypes.video.context); + deepSetValue(impressionObject, 'video.playbackmethod', bidRequest.mediaTypes.video.playbackmethod); + deepSetValue(impressionObject, 'skip', bidRequest.mediaTypes.video.skip); + deepSetValue(impressionObject, 'skipafter', bidRequest.mediaTypes.video.skipafter); + deepSetValue(impressionObject, 'video.pos', bidRequest.mediaTypes.video.pos); + _each(bidRequest.mediaTypes.video.playerSize, function (videoPlayerSize) { + const format = {}; + deepSetValue(format, 'w', videoPlayerSize[0]); + deepSetValue(format, 'h', videoPlayerSize[1]); + deepSetValue(format, 'format_ext', {}); + impressionObject.video.format.push(format); + }); +} + +function getPrebidResponseBidObject(openRTBResponseBidObject) { + const prebidResponseBidObject = {}; + // Common properties + deepSetValue(prebidResponseBidObject, 'requestId', openRTBResponseBidObject.impid); + deepSetValue(prebidResponseBidObject, 'cpm', parseFloat(openRTBResponseBidObject.price)); + deepSetValue(prebidResponseBidObject, 'creativeId', openRTBResponseBidObject.crid); + deepSetValue(prebidResponseBidObject, 'currency', openRTBResponseBidObject.cur ? openRTBResponseBidObject.cur.toUpperCase() : DEFAULT_CURRENCY); + deepSetValue(prebidResponseBidObject, 'width', openRTBResponseBidObject.w); + deepSetValue(prebidResponseBidObject, 'height', openRTBResponseBidObject.h); + deepSetValue(prebidResponseBidObject, 'dealId', openRTBResponseBidObject.dealid) + deepSetValue(prebidResponseBidObject, 'netRevenue', true); + deepSetValue(prebidResponseBidObject, 'ttl', 60000); + + if (openRTBResponseBidObject.mediatype === VIDEO) { + logInfo('bidObject.mediatype == VIDEO'); + deepSetValue(prebidResponseBidObject, 'mediaType', VIDEO); + deepSetValue(prebidResponseBidObject, 'vastUrl', openRTBResponseBidObject.adm); + } else { + logInfo('bidObject.mediatype == BANNER'); + deepSetValue(prebidResponseBidObject, 'mediaType', BANNER); + deepSetValue(prebidResponseBidObject, 'ad', openRTBResponseBidObject.adm); + } + setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) + return prebidResponseBidObject +} + +function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) { + logInfo('AIDEM Bid Adapter meta', openRTBResponseBidObject); + deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', openRTBResponseBidObject.adomain); + if (openRTBResponseBidObject.cat && Array.isArray(openRTBResponseBidObject.cat)) { + const primaryCatId = openRTBResponseBidObject.cat.shift(); + deepSetValue(prebidResponseBidObject, 'meta.primaryCatId', primaryCatId); + deepSetValue(prebidResponseBidObject, 'meta.secondaryCatIds', openRTBResponseBidObject.cat); + } + deepSetValue(prebidResponseBidObject, 'meta.id', openRTBResponseBidObject.id); + deepSetValue(prebidResponseBidObject, 'meta.dsp_id', openRTBResponseBidObject.dsp_id); + deepSetValue(prebidResponseBidObject, 'meta.adid', openRTBResponseBidObject.adid); + deepSetValue(prebidResponseBidObject, 'meta.burl', openRTBResponseBidObject.burl); + deepSetValue(prebidResponseBidObject, 'meta.impid', openRTBResponseBidObject.impid); + deepSetValue(prebidResponseBidObject, 'meta.cat', openRTBResponseBidObject.cat); + deepSetValue(prebidResponseBidObject, 'meta.cid', openRTBResponseBidObject.cid); +} + +function hasValidMediaType(bidRequest) { + const supported = hasBannerMediaType(bidRequest) || hasVideoMediaType(bidRequest) + if (!supported) { + logError('AIDEM Bid Adapter: media type not supported', { bidder: BIDDER_CODE, code: ERROR_CODES.MEDIA_TYPE_NOT_SUPPORTED }); + } + return supported +} + +function hasBannerMediaType(bidRequest) { + return !!deepAccess(bidRequest, 'mediaTypes.banner') +} + +function hasVideoMediaType(bidRequest) { + return !!deepAccess(bidRequest, 'mediaTypes.video') +} + +function hasValidBannerMediaType(bidRequest) { + const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes') + if (!sizes) { + logError('AIDEM Bid Adapter: media type sizes missing', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); + return false; + } + return true +} + +function hasValidVideoMediaType(bidRequest) { + const sizes = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); + if (!sizes) { + logError('AIDEM Bid Adapter: media type playerSize missing', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); + return false; + } + return true +} + +function hasValidVideoParameters(bidRequest) { + let valid = true + const adUnitsParameters = deepAccess(bidRequest, 'mediaTypes.video'); + const bidderParameter = deepAccess(bidRequest, 'params.video'); + for (let property of REQUIRED_VIDEO_PARAMS) { + const hasAdUnitParameter = adUnitsParameters.hasOwnProperty(property) + const hasBidderParameter = bidderParameter && bidderParameter.hasOwnProperty(property) + if (!hasAdUnitParameter && !hasBidderParameter) { + logError(`AIDEM Bid Adapter: ${property} is not included in either the adunit or params level`, { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); + valid = false + } + } + + return valid +} + +function hasValidParameters(bidRequest) { + // Assigned from AIDEM to a publisher website + const siteId = deepAccess(bidRequest, 'params.siteId'); + const publisherId = deepAccess(bidRequest, 'params.publisherId'); + + if (!isStr(siteId)) { + logError('AIDEM Bid Adapter: siteId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE }); + return false; + } + + if (!isStr(publisherId)) { + logError('AIDEM Bid Adapter: publisherId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.PUBLISHER_ID_INVALID_VALUE }); + return false; + } + + return true +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: SUPPORTED_MEDIA_TYPES, + isBidRequestValid: function(bidRequest) { + logInfo('bid: ', bidRequest); + + // check if request has valid mediaTypes + if (!hasValidMediaType(bidRequest)) return false + + // check if request has valid media type parameters at adUnit level + if (hasBannerMediaType(bidRequest) && !hasValidBannerMediaType(bidRequest)) { + return false + } + + if (hasVideoMediaType(bidRequest) && !hasValidVideoMediaType(bidRequest)) { + return false + } + + if (hasVideoMediaType(bidRequest) && !hasValidVideoParameters(bidRequest)) { + return false + } + + return hasValidParameters(bidRequest) + }, + + buildRequests: function(validBidRequests, bidderRequest) { + logInfo('validBidRequests: ', validBidRequests); + logInfo('bidderRequest: ', bidderRequest); + const prebidRequest = getPrebidRequestFields(bidderRequest, validBidRequests) + const payloadString = JSON.stringify(prebidRequest); + + return { + method: 'POST', + url: endpoints.request, + data: payloadString, + options: { + withCredentials: true + } + }; + }, + + interpretResponse: function (serverResponse) { + const bids = []; + logInfo('serverResponse: ', serverResponse); + _each(serverResponse.body.bid, function (bidObject) { + logInfo('bidObject: ', bidObject); + if (!bidObject.price || !bidObject.adm) { + return; + } + logInfo('CPM OK'); + const bid = getPrebidResponseBidObject(bidObject) + bids.push(bid); + }); + return bids; + }, + + onBidWon: function(bid) { + // Bidder specific code + logInfo('onBidWon bid: ', bid); + const notice = buildWinNotice(bid) + ajax(endpoints.notice.win, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); + }, + + onBidderError: function({ bidderRequest }) { + // Bidder specific code + const notice = buildErrorNotice(bidderRequest) + ajax(endpoints.notice.error, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); + }, +} +registerBidder(spec); diff --git a/modules/aidemBidAdapter.md b/modules/aidemBidAdapter.md new file mode 100644 index 00000000000..a5beca97d10 --- /dev/null +++ b/modules/aidemBidAdapter.md @@ -0,0 +1,187 @@ +# Overview + +``` +name: AIDEM Adapter +type: Bidder Adapter +support: prebid@aidem.com +biddercode: aidem +``` + +# Description +This module connects publishers to AIDEM demand. + +This module is GDPR and CCPA compliant, and no 3rd party userIds are allowed. + + +## Global Bid Params +| Name | Scope | Description | Example | Type | +|---------------|----------|---------------------|---------------|----------| +| `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | +| `publisherId` | required | Unique publisher ID | `'ABCDEF'` | `String` | + + +### Banner Bid Params +| Name | Scope | Description | Example | Type | +|------------|----------|--------------------------|---------------------------|---------| +| `sizes` | required | List of the sizes wanted | `[[300, 250], [300,600]]` | `Array` | + + +### Video Bid Params +| Name | Scope | Description | Example | Type | +|---------------|----------|-----------------------------------------|-----------------|-----------| +| `context` | required | One of instream, outstream, adpod | `'instream'` | `String` | +| `playerSize` | required | Width and height of the player | `'[640, 480]'` | `Array` | +| `maxduration` | required | Maximum video ad duration, in seconds | `30` | `Integer` | +| `minduration` | required | Minimum video ad duration, in seconds | `5` | `Integer` | +| `mimes` | required | List of the content MIME types supported by the player | `["video/mp4"]` | `Array` | +| `protocols` | required | An array of supported video protocols. At least one supported protocol must be specified, where: `2` = VAST 2.0 `3` = VAST 3.0 `5` = VAST 2.0 wrapper `6` = VAST 3.0 wrapper | `2` | `Array` | + + +### Additional Config +| Name | Scope | Description | Example | Type | +|---------------------|----------|---------------------------------------------------------|---------|-----------| +| `coppa` | optional | Child Online Privacy Protection Act | `true` | `Boolean` | +| `consentManagement` | optional | [Consent Management Object](#consent-management-object) | `{}` | `Object` | + + +### Consent Management Object +| Name | Scope | Description | Example | Type | +|--------|----------|--------------------------------------------------------------------------------------------------|---------|----------| +| `gdpr` | optional | GDPR Object see [Prebid.js doc](https://docs.prebid.org/dev-docs/modules/consentManagement.html) | `{}` | `Object` | +| `usp` | optional | USP Object see [Prebid.js doc](https://docs.prebid.org/dev-docs/modules/consentManagementUsp.html) | `{}` | `Object` | + + +### Example Banner ad unit +```javascript +var adUnits = [{ + code: 'banner-prebid-test-site', + mediaTypes: { + banner: { + sizes: [ + [300, 600], + [300, 250] + ] + } + }, + bids: [{ + bidder: 'aidem', + params: { + siteId: 'prebid-test-site', + }, + }] +}]; +``` + +### Example Video ad unit +```javascript +var adUnits = [{ + code: 'video-prebid-test-site', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480], + maxduration: 30, + minduration: 5, + mimes: ["video/mp4"], + protocols: 2 + } + }, + bids: [{ + bidder: 'aidem', + params: { + siteId: 'prebid-test-site', + }, + }] +}]; +``` + +### Example GDPR Consent Management +```javascript +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +pbjs.que.push(function (){ + pbjs.setConfig({ + consentManagement: { + gdpr:{ + cmpApi: 'iab' + } + } + }); +}) +``` + + +### Example USP Consent Management +```javascript +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +pbjs.que.push(function (){ + pbjs.setConfig({ + consentManagement: { + usp:{ + cmpApi: 'static', + consentData:{ + getUSPData:{ + uspString: '1YYY' + } + } + } + } + }); +}) +``` + + +### Setting First Party Data (FPD) +```javascript +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +pbjs.que.push(function (){ + pbjs.setConfig({ + ortb2: { + site: { + cat: ['IAB2'], + sectioncat: ['IAB2-2'], + keywords: 'power tools, drills' + }, + } + }); +}) +``` + +### Supported Media Types +| Type | Support | +|--------|--------------------------------------------------------------------| +| Banner | Support all [AIDEM Sizes](https://kb.aidem.com/ssp/lists/adsizes/) | +| Video | Support all [AIDEM Sizes](https://kb.aidem.com/ssp/lists/adsizes/) | + + +# Setup / Dev Guide +```shell +nvm use + +npm install + +gulp build --modules=aidemBidAdapter + +gulp serve --modules=aidemBidAdapter + +# Open a chrome browser with no ad blockers enabled, and paste in this URL. The `pbjs_debug=true` is needed if you want to enable `loggerInfo` output on the `console` tab of Chrome Developer Tools. +http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true +``` + +If you need to run the tests suite but do *not* want to have to build the full adapter and serve it, simply run: +```shell +gulp test --file "test/spec/modules/aidemBidAdapter_spec.js" +``` + + +For video: gulp serve --modules=aidemBidAdapter,dfpAdServerVideo + +# FAQs +### How do I view AIDEM bid request? +Navigate to a page where AIDEM is setup to bid. In the network tab, +search for requests to `zero.aidemsrv.com/bid/request`. diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js new file mode 100644 index 00000000000..472b226ab8a --- /dev/null +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -0,0 +1,664 @@ +import {expect} from 'chai'; +import {setEndPoints, spec} from 'modules/aidemBidAdapter.js'; +import * as utils from '../../../src/utils'; +import {deepSetValue} from '../../../src/utils'; +import {server} from '../../mocks/xhr'; +import {config} from '../../../src/config'; +import {NATIVE} from '../../../src/mediaTypes.js'; + +// Full banner + Full Video + Basic Banner + Basic Video +const VALID_BIDS = [ + { + bidder: 'aidem', + params: { + siteId: '301491', + publisherId: '3021491', + placementId: 13144370, + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + }, + { + bidder: 'aidem', + params: { + siteId: '301491', + publisherId: '3021491', + placementId: 13144370, + }, + mediaTypes: { + video: { + context: 'instream', + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2] + } + }, + }, +] + +const INVALID_BIDS = [ + { + bidder: 'aidem', + params: { + siteId: '3014912' + } + }, + { + bidder: 'aidem', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + params: { + siteId: '3014912', + } + }, + { + bidder: 'aidem', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + params: { + publisherId: '3014912', + } + }, + { + bidder: 'aidem', + params: { + siteId: '3014912', + member: '301e4912' + } + }, + { + bidder: 'aidem', + params: { + siteId: '3014912', + invCode: '3014912' + } + }, + { + bidder: 'aidem', + mediaType: NATIVE, + params: { + siteId: '3014912' + } + }, + { + bidder: 'aidem', + mediaTypes: { + banner: {} + }, + }, + { + bidder: 'aidem', + mediaTypes: { + video: { + placement: 1, + minduration: 7, + maxduration: 30, + mimes: ['video/mp4'], + protocols: [2] + } + }, + params: { + siteId: '301491', + placementId: 13144370, + }, + }, + { + bidder: 'aidem', + mediaTypes: { + video: { + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2] + } + }, + params: { + siteId: '301491', + placementId: 13144370, + }, + }, + { + bidder: 'aidem', + mediaTypes: { + video: { + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2], + placement: 1 + } + }, + params: { + siteId: '301491', + placementId: 13144370, + video: { + size: [480, 40] + } + }, + }, +] + +const DEFAULT_VALID_BANNER_REQUESTS = [ + { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'aidem', + bidderRequestId: '15246a574e859f', + mediaTypes: { + banner: { + sizes: [ + [ 300, 250 ], + [ 300, 600 ] + ] + } + }, + params: { + siteId: 1, + placementId: 13144370 + }, + src: 'client', + transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c' + } +]; + +const DEFAULT_VALID_VIDEO_REQUESTS = [ + { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'aidem', + bidderRequestId: '15246a574e859f', + mediaTypes: { + video: { + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2] + } + }, + params: { + siteId: 1, + placementId: 13144370 + }, + src: 'client', + transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c' + } +]; + +const VALID_BIDDER_REQUEST = { + auctionId: '6e9b46c3-65a8-46ea-89f4-c5071110c85c', + bidderCode: 'aidem', + bidderRequestId: '170ea5d2b1d073', + refererInfo: { + page: 'test-page', + domain: 'test-domain', + ref: 'test-referer' + }, +} + +// Add mediatype +const SERVER_RESPONSE_BANNER = { + body: { + id: 'efa1930a-bc3e-4fd0-8368-08bc40236b4f', + bid: [ + // BANNER + { + 'id': '2e614be960ee1d', + 'impid': '2e614be960ee1d', + 'price': 7.91, + 'mediatype': 'banner', + 'adid': '24277955', + 'adm': 'creativity_banner', + 'adomain': [ + 'aidem.com' + ], + 'iurl': 'http://www.aidem.com', + 'cat': [], + 'cid': '4193561', + 'crid': '24277955', + 'w': 300, + 'h': 250, + 'ext': { + 'dspid': 85, + 'advbrandid': 1246, + 'advbrand': 'AIDEM' + } + }, + ], + cur: 'USD' + }, +} + +const SERVER_RESPONSE_VIDEO = { + body: { + id: 'efa1930a-bc3e-4fd0-8368-08bc40236b4f', + bid: [ + // VIDEO + { + 'id': '2876a29392a47c', + 'impid': '2876a29392a47c', + 'price': 7.93, + 'mediatype': 'video', + 'adid': '24277955', + 'adm': 'https://hermes.aidemsrv.com/vast-tag/cl9mzhhd502uq09l720uegb02?auction_id={{AUCTION_ID}}&cachebuster={{CACHEBUSTER}}', + 'adomain': [ + 'aidem.com' + ], + 'iurl': 'http://www.aidem.com', + 'cat': [], + 'cid': '4193561', + 'crid': '24277955', + 'w': 640, + 'h': 480, + 'ext': { + 'dspid': 85, + 'advbrandid': 1246, + 'advbrand': 'AIDEM' + } + } + ], + cur: 'USD' + }, +} + +const WIN_NOTICE = { + 'adId': '3a20ee5dc78c1e', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'creativeId': '24277955', + 'cpm': 1, + 'netRevenue': false, + 'adserverTargeting': { + 'hb_bidder': 'aidem', + 'hb_adid': '3a20ee5dc78c1e', + 'hb_pb': '1.00', + 'hb_size': '300x250', + 'hb_source': 'client', + 'hb_format': 'banner', + 'hb_adomain': 'tenutabene.it' + }, + 'auctionId': '85864730-6cbc-4e56-bc3c-a4a6596dca5b', + 'currency': [ + 'USD' + ], + 'mediaType': 'banner', + 'size': '300x250', + 'width': 300, + 'height': 250, + 'status': 'rendered', + 'transactionId': 'ce089116-4251-45c3-bdbb-3a03cb13816b', + 'ttl': 300, + 'requestTimestamp': 1666796241007, + 'responseTimestamp': 1666796241021, + metrics: { + getMetrics() { + return { + + } + } + } +} + +const ERROR_NOTICE = { + 'message': 'Prebid.js: Server call for aidem failed.', + 'url': 'http%3A%2F%2Flocalhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue', + 'auctionId': 'b57faab7-23f7-4b63-90db-67b259d20db7', + 'bidderRequestId': '1c53857d1ce616', + 'timeout': 1000, + 'bidderCode': 'aidem', + metrics: { + getMetrics() { + return { + + } + } + } +} + +describe('Aidem adapter', () => { + describe('isBidRequestValid', () => { + it('should return true for each valid bid requests', function () { + // spec.isBidRequestValid() + VALID_BIDS.forEach((value, index) => { + expect(spec.isBidRequestValid(value)).to.be.true + }) + }); + + it('should return false for each invalid bid requests', function () { + // spec.isBidRequestValid() + INVALID_BIDS.forEach((value, index) => { + expect(spec.isBidRequestValid(value)).to.be.false + }) + }); + + it('should return true if valid banner sizes are specified in params as single array', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'banner.size', [300, 250]) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.true + }); + + it('should return true if valid banner sizes are specified in params as array of array', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'banner.size', [[300, 600]]) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.true + }); + + it('should return true if valid video sizes are specified in params as single array', function () { + // spec.isBidRequestValid() + const validVideoRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validVideoRequest.params, 'video.size', [640, 480]) + expect(spec.isBidRequestValid(validVideoRequest)).to.be.true + }); + }); + + describe('buildRequests', () => { + it('should match server requirements', () => { + const requests = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + expect(requests).to.be.an('object'); + expect(requests.method).to.be.a('string') + expect(requests.data).to.be.a('string') + expect(requests.options).to.be.an('object').that.have.a.property('withCredentials') + }); + + it('should have a well formatted banner payload', () => { + const requests = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + expect(payload).to.be.a('object').that.has.all.keys( + 'id', 'imp', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at' + ) + expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_BANNER_REQUESTS.length) + + expect(payload.imp[0]).to.be.a('object').that.has.all.keys( + 'banner', 'id', 'mediatype', 'imp_ext', 'tid' + ) + expect(payload.imp[0].banner).to.be.a('object').that.has.all.keys( + 'format', 'topframe' + ) + }); + + it('should have a well formatted video payload', () => { + const requests = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + expect(payload).to.be.a('object').that.has.all.keys( + 'id', 'imp', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at' + ) + expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_VIDEO_REQUESTS.length) + + expect(payload.imp[0]).to.be.a('object').that.has.all.keys( + 'video', 'id', 'mediatype', 'imp_ext', 'tid' + ) + expect(payload.imp[0].video).to.be.a('object').that.has.all.keys( + 'format', 'mimes', 'minDuration', 'maxDuration', 'protocols' + ) + }); + + it('should have a well formatted bid floor payload if configured', () => { + const validBannerRequests = utils.deepClone(DEFAULT_VALID_BANNER_REQUESTS) + validBannerRequests[0].params.floor = { + value: 1.98, + currency: 'USD' + } + const requests = spec.buildRequests(validBannerRequests, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + const { floor } = payload.imp[0] + expect(floor).to.be.a('object').that.has.all.keys( + 'value', 'currency' + ) + }); + }) + + describe('interpretResponse', () => { + it('should return a valid bid array with a banner bid', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(1) + interpreted.forEach(value => { + expect(value).to.be.a('object').that.has.all.keys( + 'ad', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'dealId' + ) + }) + }); + + it('should return a valid bid array with a banner bid', () => { + const response = utils.deepClone(SERVER_RESPONSE_VIDEO) + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(1) + interpreted.forEach(value => { + expect(value).to.be.a('object').that.has.all.keys( + 'vastUrl', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'dealId' + ) + }) + }); + + it('should return a valid bid array with netRevenue', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + response.body.bid[0].isNet = true + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(1) + expect(interpreted[0].netRevenue).to.be.true + }); + + it('should return an empty bid array if one of seatbid entry is missing price property', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + delete response.body.bid[0].price + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(0) + }); + + it('should return an empty bid array if one of seatbid entry is missing adm property', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + delete response.body.bid[0].adm + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(0) + }); + }) + + describe('onBidWon', () => { + it(`should exists and type function`, function () { + expect(spec.onBidWon).to.exist.and.to.be.a('function') + }); + + it(`should send a valid bid won notice`, function () { + spec.onBidWon(WIN_NOTICE); + // server.respondWith('POST', WIN_EVENT_URL, [ + // 400, {'Content-Type': 'application/json'}, ) + // ]); + expect(server.requests.length).to.equal(1); + }); + }); + + describe('onBidderError', () => { + it(`should exists and type function`, function () { + expect(spec.onBidderError).to.exist.and.to.be.a('function') + }); + + it(`should send a valid error notice`, function () { + spec.onBidderError({ bidderRequest: ERROR_NOTICE }) + expect(server.requests.length).to.equal(1); + const body = JSON.parse(server.requests[0].requestBody) + expect(body).to.be.a('object').that.has.all.keys('message', 'auctionId', 'bidderRequestId', 'url', 'metrics') + // const { bids } = JSON.parse(server.requests[0].requestBody) + // expect(bids).to.be.a('array').that.has.lengthOf(1) + // _each(bids, (bid) => { + // expect(bid).to.be.a('object').that.has.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'transactionId', 'metrics') + // }) + }); + }); + + describe('setEndPoints', () => { + it(`should exists and type function`, function () { + expect(setEndPoints).to.exist.and.to.be.a('function') + }); + + it(`should not modify default endpoints`, function () { + const endpoints = setEndPoints() + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(requestURL.host).to.equal('zero.aidemsrv.com') + expect(winNoticeURL.host).to.equal('zero.aidemsrv.com') + expect(timeoutNoticeURL.host).to.equal('zero.aidemsrv.com') + expect(errorNoticeURL.host).to.equal('zero.aidemsrv.com') + + expect(decodeURIComponent(requestURL.pathname)).to.equal('/bid/request') + expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/notice/win') + expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/notice/timeout') + expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/notice/error') + }); + + it(`should not change request endpoint`, function () { + const endpoints = setEndPoints('default') + const requestURL = new URL(endpoints.request) + expect(decodeURIComponent(requestURL.pathname)).to.equal('/bid/request') + }); + + it(`should change to local env`, function () { + const endpoints = setEndPoints('local') + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(requestURL.host).to.equal('127.0.0.1:8787') + expect(winNoticeURL.host).to.equal('127.0.0.1:8787') + expect(timeoutNoticeURL.host).to.equal('127.0.0.1:8787') + expect(errorNoticeURL.host).to.equal('127.0.0.1:8787') + }); + + it(`should add a path prefix`, function () { + const endpoints = setEndPoints('local', '/path') + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(decodeURIComponent(requestURL.pathname)).to.equal('/path/bid/request') + expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/path/notice/win') + expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/path/notice/timeout') + expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/path/notice/error') + }); + + it(`should add a path prefix and change request endpoint`, function () { + const endpoints = setEndPoints('local', '/path') + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(decodeURIComponent(requestURL.pathname)).to.equal('/path/bid/request') + expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/path/notice/win') + expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/path/notice/timeout') + expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/path/notice/error') + }); + }); + + describe('config', () => { + beforeEach(() => { + config.setConfig({ + aidem: { + env: 'main' + } + }); + }) + + it(`should not override default endpoints`, function () { + config.setConfig({ + aidem: { + env: 'unknown', + path: '/test' + } + }); + const { url } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const requestURL = new URL(url) + expect(requestURL.host).to.equal('zero.aidemsrv.com') + }); + + it(`should set local endpoints`, function () { + config.setConfig({ + aidem: { + env: 'local', + path: '/test' + } + }); + const { url } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const requestURL = new URL(url) + expect(requestURL.host).to.equal('127.0.0.1:8787') + }); + + it(`should set coppa`, function () { + config.setConfig({ + coppa: true + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.coppa_applies).to.equal(true) + }); + + it(`should set gdpr to true`, function () { + config.setConfig({ + consentManagement: { + gdpr: { + // any data here set gdpr to true + }, + } + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.gdpr_applies).to.equal(true) + }); + + it(`should set usp_consent string`, function () { + config.setConfig({ + consentManagement: { + usp: { + cmpApi: 'static', + consentData: { + getUSPData: { + uspString: '1YYY' + } + } + } + } + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.us_privacy).to.equal('1YYY') + }); + + it(`should not set usp_consent string`, function () { + config.setConfig({ + consentManagement: { + usp: { + cmpApi: 'iab', + consentData: { + getUSPData: { + uspString: '1YYY' + } + } + } + } + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.us_privacy).to.undefined + }); + }); +}); From 22bf423e28b74674ecd89e7fc3f48473487f33dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C5=82awomir=20Kok=C5=82owski?= <38455696+skoklowski@users.noreply.github.com> Date: Mon, 28 Nov 2022 18:06:31 +0100 Subject: [PATCH 155/367] Ringier Axel Springer Bidder Adapter (#9239) - New parameter `customParams` Co-authored-by: skoklowski --- modules/rasBidAdapter.js | 11 ++++++--- modules/rasBidAdapter.md | 31 +++++++++++++------------ test/spec/modules/rasBidAdapter_spec.js | 6 ++++- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/modules/rasBidAdapter.js b/modules/rasBidAdapter.js index 7bc3cf66b0d..f8ca260d490 100644 --- a/modules/rasBidAdapter.js +++ b/modules/rasBidAdapter.js @@ -1,4 +1,3 @@ -import * as utils from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { isEmpty, getAdUnitSizes, parseSizesInput, deepAccess } from '../src/utils.js'; @@ -12,9 +11,15 @@ const getEndpoint = (network) => { function parseParams(params, bidderRequest) { const newParams = {}; + if (params.customParams && typeof params.customParams === 'object') { + for (const param in params.customParams) { + if (params.customParams.hasOwnProperty(param)) { + newParams[param] = params.customParams[param]; + } + } + } const du = deepAccess(bidderRequest, 'refererInfo.page'); const dr = deepAccess(bidderRequest, 'refererInfo.ref'); - if (du) { newParams.du = du; } @@ -93,7 +98,7 @@ const getSlots = (bidRequests) => { const batchSize = bidRequests.length; for (let i = 0; i < batchSize; i++) { const adunit = bidRequests[i]; - const slotSequence = utils.deepAccess(adunit, 'params.slotSequence'); + const slotSequence = deepAccess(adunit, 'params.slotSequence'); const sizes = parseSizesInput(getAdUnitSizes(adunit)).join(','); diff --git a/modules/rasBidAdapter.md b/modules/rasBidAdapter.md index 384ba0b611f..e8a61974130 100644 --- a/modules/rasBidAdapter.md +++ b/modules/rasBidAdapter.md @@ -34,18 +34,19 @@ var adUnits = [{ # Parameters -| Name | Scope | Type | Description | Example -| --- | --- | --- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| --- -| network | required | String | Specific identifier provided by RAS | `"4178463"` -| site | required | String | Specific identifier name (case-insensitive) that is associated with this ad unit and provided by RAS | `"example_com"` -| area | required | String | Ad unit category name; only case-insensitive alphanumeric with underscores and hyphens are allowed | `"sport"` -| slot | required | String | Ad unit placement name (case-insensitive) provided by RAS | `"slot"` -| slotSequence | optional | Number | Ad unit sequence position provided by RAS | `1` -| pageContext | optional | Object | Web page context data | `{}` -| pageContext.dr | optional | String | Document referrer URL address | `"https://example.com/"` -| pageContext.du | optional | String | Document URL address | `"https://example.com/sport/football/article.html?id=932016a5-02fc-4d5c-b643-fafc2f270f06"` -| pageContext.dv | optional | String | Document virtual address as slash-separated path that may consist of any number of parts (case-insensitive alphanumeric with underscores and hyphens); first part should be the same as `site` value and second as `area` value; next parts may reflect website navigation | `"example_com/sport/football"` -| pageContext.keyWords | optional | String[] | List of keywords associated with this ad unit; only case-insensitive alphanumeric with underscores and hyphens are allowed | `["euro", "lewandowski"]` -| pageContext.keyValues | optional | Object | Key-values associated with this ad unit (case-insensitive); following characters are not allowed in the values: `" ' = ! + # * ~ ; ^ ( ) < > [ ] & @` | `{}` -| pageContext.keyValues.ci | optional | String | Content unique identifier | `"932016a5-02fc-4d5c-b643-fafc2f270f06"` -| pageContext.keyValues.adunit | optional | String | Ad unit name | `"example_com/sport"` +| Name | Scope | Type | Description | Example | +|------------------------------|----------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| network | required | String | Specific identifier provided by RAS | `"4178463"` | +| site | required | String | Specific identifier name (case-insensitive) that is associated with this ad unit and provided by RAS | `"example_com"` | +| area | required | String | Ad unit category name; only case-insensitive alphanumeric with underscores and hyphens are allowed | `"sport"` | +| slot | required | String | Ad unit placement name (case-insensitive) provided by RAS | `"slot"` | +| slotSequence | optional | Number | Ad unit sequence position provided by RAS | `1` | +| pageContext | optional | Object | Web page context data | `{}` | +| pageContext.dr | optional | String | Document referrer URL address | `"https://example.com/"` | +| pageContext.du | optional | String | Document URL address | `"https://example.com/sport/football/article.html?id=932016a5-02fc-4d5c-b643-fafc2f270f06"` | +| pageContext.dv | optional | String | Document virtual address as slash-separated path that may consist of any number of parts (case-insensitive alphanumeric with underscores and hyphens); first part should be the same as `site` value and second as `area` value; next parts may reflect website navigation | `"example_com/sport/football"` | +| pageContext.keyWords | optional | String[] | List of keywords associated with this ad unit; only case-insensitive alphanumeric with underscores and hyphens are allowed | `["euro", "lewandowski"]` | +| pageContext.keyValues | optional | Object | Key-values associated with this ad unit (case-insensitive); following characters are not allowed in the values: `" ' = ! + # * ~ ; ^ ( ) < > [ ] & @` | `{}` | +| pageContext.keyValues.ci | optional | String | Content unique identifier | `"932016a5-02fc-4d5c-b643-fafc2f270f06"` | +| pageContext.keyValues.adunit | optional | String | Ad unit name | `"example_com/sport"` | +| customParams | optional | Object | Custom request params | `{}` | \ No newline at end of file diff --git a/test/spec/modules/rasBidAdapter_spec.js b/test/spec/modules/rasBidAdapter_spec.js index 8c378aaa416..bfa72a2510e 100644 --- a/test/spec/modules/rasBidAdapter_spec.js +++ b/test/spec/modules/rasBidAdapter_spec.js @@ -59,7 +59,10 @@ describe('rasBidAdapter', function () { area: 'areatest', site: 'test', slotSequence: '0', - network: '4178463' + network: '4178463', + customParams: { + test: 'name=value' + } } }; const bid2 = { @@ -98,6 +101,7 @@ describe('rasBidAdapter', function () { expect(requests[0].url).to.have.string('euconsent=some-consent-string'); expect(requests[0].url).to.have.string('du=https%3A%2F%2Fexample.com%2F'); expect(requests[0].url).to.have.string('dr=https%3A%2F%2Fexample.org%2F'); + expect(requests[0].url).to.have.string('test=name%3Dvalue'); }); it('should return empty consent string when undefined', function () { From 54b6e7fb9ef2da399b3c95a03891db4b4e51f8fd Mon Sep 17 00:00:00 2001 From: Jason Quaccia Date: Mon, 28 Nov 2022 09:09:16 -0800 Subject: [PATCH 156/367] updated ref info page logic (#9241) --- src/refererDetection.js | 7 ++- test/spec/modules/enrichmentFpdModule_spec.js | 5 +- test/spec/modules/fpdModule_spec.js | 2 +- test/spec/refererDetection_spec.js | 52 ++++++++++++++++--- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/refererDetection.js b/src/refererDetection.js index 15c080f5c69..e0cb15522cc 100644 --- a/src/refererDetection.js +++ b/src/refererDetection.js @@ -120,6 +120,7 @@ export function detectReferer(win) { const stack = []; const ancestors = getAncestorOrigins(win); const maxNestedIframes = config.getConfig('maxNestedIframes'); + let currentWindow; let bestLocation; let bestCanonicalUrl; @@ -226,7 +227,11 @@ export function detectReferer(win) { const location = reachedTop || hasTopLocation ? bestLocation : null; const canonicalUrl = config.getConfig('pageUrl') || bestCanonicalUrl || null; - const page = ensureProtocol(canonicalUrl, win) || location; + let page = config.getConfig('pageUrl') || location || ensureProtocol(canonicalUrl, win); + + if (location && location.indexOf('?') > -1 && page.indexOf('?') === -1) { + page = `${page}${location.substring(location.indexOf('?'))}`; + } return { reachedTop, diff --git a/test/spec/modules/enrichmentFpdModule_spec.js b/test/spec/modules/enrichmentFpdModule_spec.js index 1c6cab5afec..38853f1528c 100644 --- a/test/spec/modules/enrichmentFpdModule_spec.js +++ b/test/spec/modules/enrichmentFpdModule_spec.js @@ -1,4 +1,5 @@ import { expect } from 'chai'; +import {config} from 'src/config.js'; import { getRefererInfo } from 'src/refererDetection.js'; import {processFpd, coreStorage, resetEnrichments} from 'modules/enrichmentFpdModule.js'; import * as enrichmentModule from 'modules/enrichmentFpdModule.js'; @@ -77,10 +78,10 @@ describe('the first party data enrichment module', function() { expect(validated.site.keywords).to.be.undefined; }); - it('adds page domain values if canonical url exists', function() { + it('adds page domain values if pageUrl url exists', function() { + config.setConfig({'pageUrl': 'https://www.subdomain.domain.co.uk/path?query=12345'}); width = 800; height = 500; - canonical.href = 'https://www.subdomain.domain.co.uk/path?query=12345'; let validated = syncProcessFpd({}, {}).global; diff --git a/test/spec/modules/fpdModule_spec.js b/test/spec/modules/fpdModule_spec.js index 8e95f462830..7d41fbb55e1 100644 --- a/test/spec/modules/fpdModule_spec.js +++ b/test/spec/modules/fpdModule_spec.js @@ -130,7 +130,7 @@ describe('the first party data module', function () { } }; - canonical.href = 'https://www.domain.com/path?query=12345'; + config.setConfig({'pageUrl': 'https://www.domain.com/path?query=12345'}); width = 1120; height = 750; diff --git a/test/spec/refererDetection_spec.js b/test/spec/refererDetection_spec.js index 3f33d1646a1..f8166a27d85 100644 --- a/test/spec/refererDetection_spec.js +++ b/test/spec/refererDetection_spec.js @@ -128,11 +128,49 @@ describe('Referer detection', () => { numIframes: 0, stack: ['https://example.com/some/page'], canonicalUrl: 'https://example.com/canonical/page', - page: 'https://example.com/canonical/page', + page: 'https://example.com/some/page', ref: 'https://othersite.com/', domain: 'example.com' }); }); + + it('Should set page and canonical to pageUrl value set in config if present, even if canonical url is also present in head', () => { + config.setConfig({'pageUrl': 'https://www.set-from-config.com/path'}); + const testWindow = buildWindowTree(['https://example.com/some/page'], 'https://othersite.com/', 'https://example.com/canonical/page'), + result = detectReferer(testWindow)(); + + sinon.assert.match(result, { + topmostLocation: 'https://example.com/some/page', + location: 'https://example.com/some/page', + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: ['https://example.com/some/page'], + canonicalUrl: 'https://www.set-from-config.com/path', + page: 'https://www.set-from-config.com/path', + ref: 'https://othersite.com/', + domain: 'www.set-from-config.com' + }); + }); + + it('Should set page with query params if canonical url is present without query params but the current page does have them', () => { + config.setConfig({'pageUrl': 'https://www.set-from-config.com/path'}); + const testWindow = buildWindowTree(['https://example.com/some/page?query1=123&query2=456'], 'https://othersite.com/', 'https://example.com/canonical/page'), + result = detectReferer(testWindow)(); + + sinon.assert.match(result, { + topmostLocation: 'https://example.com/some/page?query1=123&query2=456', + location: 'https://example.com/some/page?query1=123&query2=456', + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: ['https://example.com/some/page?query1=123&query2=456'], + canonicalUrl: 'https://www.set-from-config.com/path', + page: 'https://www.set-from-config.com/path?query1=123&query2=456', + ref: 'https://othersite.com/', + domain: 'www.set-from-config.com' + }); + }); }); describe('Friendly iframes', () => { @@ -174,7 +212,7 @@ describe('Referer detection', () => { 'https://example.com/third/page' ], canonicalUrl: 'https://example.com/canonical/page', - page: 'https://example.com/canonical/page', + page: 'https://example.com/some/page', ref: 'https://othersite.com/', domain: 'example.com' }); @@ -317,7 +355,7 @@ describe('Referer detection', () => { 'https://ad-iframe.ampproject.org/ad' ], canonicalUrl: 'https://example.com/some/page/', - page: 'https://example.com/some/page/', + page: 'https://example.com/some/page/amp/', ref: null, domain: 'example.com' }); @@ -344,7 +382,7 @@ describe('Referer detection', () => { 'https://ad-iframe.ampproject.org/ad' ], canonicalUrl: 'https://example.com/some/page/', - page: 'https://example.com/some/page/', + page: 'https://example.com/some/page/amp/', ref: null, domain: 'example.com' }); @@ -384,7 +422,7 @@ describe('Referer detection', () => { 'https://ad-iframe.ampproject.org/ad' ], canonicalUrl: 'https://example.com/some/page/', - page: 'https://example.com/some/page/', + page: 'https://example.com/some/page/amp/', ref: null, domain: 'example.com', }); @@ -412,7 +450,7 @@ describe('Referer detection', () => { 'https://ad-iframe.ampproject.org/ad' ], canonicalUrl: 'https://example.com/some/page/', - page: 'https://example.com/some/page/', + page: 'https://example.com/some/page/amp/', ref: null, domain: 'example.com' }); @@ -441,7 +479,7 @@ describe('Referer detection', () => { 'https://ad-iframe.ampproject.org/ad' ], canonicalUrl: 'https://example.com/some/page/', - page: 'https://example.com/some/page/', + page: 'https://example.com/some/page/amp/', ref: null, domain: 'example.com', }); From 5a9aaa8ca5bb47393ddfb08b00d1c4e0af5fd850 Mon Sep 17 00:00:00 2001 From: Elad Yosifon Date: Mon, 28 Nov 2022 19:10:23 +0200 Subject: [PATCH 157/367] fix for broken download bundle https://github.com/prebid/prebid.github.io/issues/4177 (#9289) --- modules/{kueezRtbBidAdapter.js => kueezrtbBidAdapter.js} | 0 modules/{kueezRtbBidAdapter.md => kueezrtbBidAdapter.md} | 0 .../{kueezRtbBidAdapter_spec.js => kueezrtbBidAdapter_spec.js} | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename modules/{kueezRtbBidAdapter.js => kueezrtbBidAdapter.js} (100%) rename modules/{kueezRtbBidAdapter.md => kueezrtbBidAdapter.md} (100%) rename test/spec/modules/{kueezRtbBidAdapter_spec.js => kueezrtbBidAdapter_spec.js} (99%) diff --git a/modules/kueezRtbBidAdapter.js b/modules/kueezrtbBidAdapter.js similarity index 100% rename from modules/kueezRtbBidAdapter.js rename to modules/kueezrtbBidAdapter.js diff --git a/modules/kueezRtbBidAdapter.md b/modules/kueezrtbBidAdapter.md similarity index 100% rename from modules/kueezRtbBidAdapter.md rename to modules/kueezrtbBidAdapter.md diff --git a/test/spec/modules/kueezRtbBidAdapter_spec.js b/test/spec/modules/kueezrtbBidAdapter_spec.js similarity index 99% rename from test/spec/modules/kueezRtbBidAdapter_spec.js rename to test/spec/modules/kueezrtbBidAdapter_spec.js index f9b2cd41a43..70ece966651 100644 --- a/test/spec/modules/kueezRtbBidAdapter_spec.js +++ b/test/spec/modules/kueezrtbBidAdapter_spec.js @@ -11,7 +11,7 @@ import { setStorageItem, tryParseJSON, getUniqueDealId, -} from 'modules/kueezRtbBidAdapter.js'; +} from 'modules/kueezrtbBidAdapter.js'; import * as utils from 'src/utils.js'; import {version} from 'package.json'; import {useFakeTimers} from 'sinon'; From 34fd9fbe0c19c94a2b62e2c49f2f16453d36c79e Mon Sep 17 00:00:00 2001 From: Saveliev Taras Date: Mon, 28 Nov 2022 18:21:55 +0100 Subject: [PATCH 158/367] Yandex Bid Adapter: (#9280) * refactoring; * added banner.format to payload; * added tmax support; * fixed nurl sending; * added support for the block identifier format in the Yandex Ad system; Co-authored-by: Taras Saveliev --- modules/yandexBidAdapter.js | 104 +++++++++++++++++---- modules/yandexBidAdapter.md | 14 +-- test/spec/modules/yandexBidAdapter_spec.js | 35 ++++--- 3 files changed, 114 insertions(+), 39 deletions(-) diff --git a/modules/yandexBidAdapter.js b/modules/yandexBidAdapter.js index af465453c22..f73b4369869 100644 --- a/modules/yandexBidAdapter.js +++ b/modules/yandexBidAdapter.js @@ -1,5 +1,6 @@ -import { formatQS, deepAccess, triggerPixel } from '../src/utils.js'; +import { formatQS, deepAccess, triggerPixel, isArray, isNumber } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js' const BIDDER_CODE = 'yandex'; const BIDDER_URL = 'https://bs.yandex.ru/metadsp'; @@ -10,9 +11,19 @@ const SSP_ID = 10500; export const spec = { code: BIDDER_CODE, aliases: ['ya'], // short code + supportedMediaTypes: [ BANNER ], isBidRequestValid: function(bid) { - return !!(bid.params && bid.params.pageId && bid.params.impId); + const { params } = bid; + if (!params) { + return false; + } + const { pageId, impId } = extractPlacementIds(params); + if (!(pageId && impId)) { + return false; + } + const sizes = bid.mediaTypes?.banner?.sizes; + return isArray(sizes) && isArray(sizes[0]) && isNumber(sizes[0][0]) && isNumber(sizes[0][1]); }, buildRequests: function(validBidRequests, bidderRequest) { @@ -29,9 +40,19 @@ export const spec = { page = bidderRequest.refererInfo.page; } + let timeout = null; + if (bidderRequest) { + timeout = bidderRequest.timeout; + } + return validBidRequests.map((bidRequest) => { const { params } = bidRequest; - const { pageId, impId, targetRef, withCredentials = true } = params; + const { targetRef, withCredentials = true } = params; + const sizes = bidRequest.mediaTypes.banner.sizes; + const size = sizes[0]; + const [ w, h ] = size; + + const { pageId, impId } = extractPlacementIds(params); const queryParams = { 'imp-id': impId, @@ -43,24 +64,23 @@ export const spec = { queryParams['tcf-consent'] = consentString; } - const floorInfo = bidRequest.getFloor ? bidRequest.getFloor({ - currency: DEFAULT_CURRENCY - }) : {}; - const bidfloor = floorInfo.floor; - const bidfloorcur = floorInfo.currency; - const imp = { id: impId, - bidfloor, - bidfloorcur, - }; - const bannerParams = deepAccess(bidRequest, 'mediaTypes.banner'); - if (bannerParams) { - const [ w, h ] = bannerParams.sizes[0]; - imp.banner = { + banner: { + format: sizes, w, h, - }; + } + }; + + if (bidRequest.getFloor) { + const floorInfo = bidRequest.getFloor({ + currency: DEFAULT_CURRENCY, + size + }); + + imp.bidfloor = floorInfo.floor; + imp.bidfloorcur = floorInfo.currency; } const queryParamsString = formatQS(queryParams); @@ -74,6 +94,7 @@ export const spec = { ref_url: referrer, page_url: page, }, + tmax: timeout, }, options: { withCredentials, @@ -102,6 +123,7 @@ export const spec = { width: rtbBid.w, height: rtbBid.h, creativeId: rtbBid.adid, + nurl: rtbBid.nurl, netRevenue: true, ttl: DEFAULT_TTL, @@ -118,13 +140,57 @@ export const spec = { }, onBidWon: function (bid) { - const nurl = bid['nurl']; - + let nurl = bid['nurl']; if (!nurl) { return; } + + const cpm = deepAccess(bid, 'adserverTargeting.hb_pb') || ''; + const curr = (bid.hasOwnProperty('originalCurrency') && bid.hasOwnProperty('originalCpm')) + ? bid.originalCurrency + : bid.currency; + + nurl = nurl + .replace(/\${AUCTION_PRICE}/, cpm) + .replace(/\${AUCTION_CURRENCY}/, curr) + ; + triggerPixel(nurl); } } +function extractPlacementIds(bidRequestParams) { + const { placementId } = bidRequestParams; + const result = { pageId: null, impId: null }; + + let pageId, impId; + if (placementId) { + /* + * Possible formats + * R-I-123456-2 + * R-123456-1 + * 123456-789 + */ + const num = placementId.lastIndexOf('-'); + if (num === -1) { + return result; + } + const num2 = placementId.lastIndexOf('-', num - 1); + pageId = placementId.slice(num2 + 1, num); + impId = placementId.slice(num + 1); + } else { + pageId = bidRequestParams.pageId; + impId = bidRequestParams.impId; + } + + if (!parseInt(pageId, 10) || !parseInt(impId, 10)) { + return result; + } + + result.pageId = pageId; + result.impId = impId; + + return result; +} + registerBidder(spec); diff --git a/modules/yandexBidAdapter.md b/modules/yandexBidAdapter.md index 7a51d7bc5fb..aee51bca249 100644 --- a/modules/yandexBidAdapter.md +++ b/modules/yandexBidAdapter.md @@ -12,10 +12,11 @@ Yandex Bidder Adapter for Prebid.js. # Parameters -| Name | Scope | Description | Example | Type | -|---------------|----------|-------------------------|-----------|-----------| -| `pageId` | required | Page ID | `123` | `Integer` | -| `impId` | required | Block ID | `1` | `Integer` | +| Name | Required? | Description | Example | Type | +|---------------|--------------------------------------------|-------------|---------|-----------| +| `placementId` | Yes | Block ID | `123-1` | `String` | +| `pageId` | No
Deprecated. Please use `placementId` | Page ID | `123` | `Integer` | +| `impId` | No
Deprecated. Please use `placementId` | Imp ID | `1` | `Integer` | # Test Parameters @@ -24,15 +25,14 @@ var adUnits = [{ code: 'banner-1', mediaTypes: { banner: { - sizes: [[240, 400]], + sizes: [[240, 400], [300, 600]], } }, bids: [{ { bidder: 'yandex', params: { - pageId: 346580, - impId: 143, + placementId: '346580-1' }, } }] diff --git a/test/spec/modules/yandexBidAdapter_spec.js b/test/spec/modules/yandexBidAdapter_spec.js index eee53771a80..df91100b966 100644 --- a/test/spec/modules/yandexBidAdapter_spec.js +++ b/test/spec/modules/yandexBidAdapter_spec.js @@ -1,15 +1,14 @@ -import {assert, expect} from 'chai'; -import {spec} from 'modules/yandexBidAdapter.js'; -import {parseUrl} from 'src/utils.js'; -import {BANNER} from '../../../src/mediaTypes'; +import { assert, expect } from 'chai'; +import { spec } from 'modules/yandexBidAdapter.js'; +import { parseUrl } from 'src/utils.js'; +import { BANNER } from '../../../src/mediaTypes'; describe('Yandex adapter', function () { function getBidConfig() { return { bidder: 'yandex', params: { - pageId: 123, - impId: 1, + placementId: '123-1', }, }; } @@ -32,7 +31,7 @@ describe('Yandex adapter', function () { describe('isBidRequestValid', function () { it('should return true when required params found', function () { - const bid = getBidConfig(); + const bid = getBidRequest(); assert(spec.isBidRequestValid(bid)); }); @@ -40,18 +39,28 @@ describe('Yandex adapter', function () { expect(spec.isBidRequestValid({})).to.be.false; }); - it('should return false when required params.pageId are not passed', function () { + it('should return false when required params.placementId are not passed', function () { + const bid = getBidConfig(); + delete bid.params.placementId; + + expect(spec.isBidRequestValid(bid)).to.be.false; + }); + + it('should return false when required params.placementId are not valid', function () { const bid = getBidConfig(); - delete bid.params.pageId; + bid.params.placementId = '123'; - expect(spec.isBidRequestValid(bid)).to.be.false + expect(spec.isBidRequestValid(bid)).to.be.false; }); - it('should return false when required params.impId are not passed', function () { + it('should return true when passed deprecated placement config', function () { const bid = getBidConfig(); - delete bid.params.impId; + delete bid.params.placementId; + + bid.params.pageId = 123; + bid.params.impId = 1; - expect(spec.isBidRequestValid(bid)).to.be.false + expect(spec.isBidRequestValid(bid)); }); }); From 78aa883107e519980a87e298d0c8d8b6bac46029 Mon Sep 17 00:00:00 2001 From: Yoko OYAMA Date: Tue, 29 Nov 2022 02:41:19 +0900 Subject: [PATCH 159/367] Fluct Bid Adapter: add schain support (#9266) * add schain to req * run circleci Co-authored-by: Chris Huie --- modules/fluctBidAdapter.js | 5 +++ test/spec/modules/fluctBidAdapter_spec.js | 38 ++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/modules/fluctBidAdapter.js b/modules/fluctBidAdapter.js index ea634027dbe..004d44e6737 100644 --- a/modules/fluctBidAdapter.js +++ b/modules/fluctBidAdapter.js @@ -62,6 +62,11 @@ export const spec = { }); data.params = request.params; + + if (request.schain) { + data.schain = request.schain; + } + const searchParams = new URLSearchParams({ dfpUnitCode: request.params.dfpUnitCode, tagId: request.params.tagId, diff --git a/test/spec/modules/fluctBidAdapter_spec.js b/test/spec/modules/fluctBidAdapter_spec.js index 8ef99727ce7..92a4b42f6f8 100644 --- a/test/spec/modules/fluctBidAdapter_spec.js +++ b/test/spec/modules/fluctBidAdapter_spec.js @@ -94,7 +94,12 @@ describe('fluctAdapter', function () { expect(request.data.params.kv).to.eql(undefined); }); - it('includes filtered user.eids if any exists', function () { + it('includes no data.schain by default', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.schain).to.eql(undefined); + }); + + it('includes filtered user.eids if any exist', function () { const bidRequests2 = bidRequests.map( (bidReq) => Object.assign(bidReq, { userIdAsEids: [ @@ -175,6 +180,37 @@ describe('fluctAdapter', function () { imsids: ['imsid1', 'imsid2'] }); }); + + it('includes data.schain if any exists', function () { + // this should be done by schain.js + const bidRequests2 = bidRequests.map( + (bidReq) => Object.assign(bidReq, { + schain: { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'example.com', + sid: 'publisher-id', + hp: 1 + } + ] + } + }) + ); + const request = spec.buildRequests(bidRequests2, bidderRequest)[0]; + expect(request.data.schain).to.eql({ + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'example.com', + sid: 'publisher-id', + hp: 1 + } + ] + }); + }); }); describe('interpretResponse', function() { From 3261b061678ef9f565107de96b8457b35d763cd2 Mon Sep 17 00:00:00 2001 From: ssorleti <100858633+ssorleti@users.noreply.github.com> Date: Mon, 28 Nov 2022 18:44:55 +0100 Subject: [PATCH 160/367] Update bucksense adapter - new server endpoint (#9292) --- modules/bucksenseBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/bucksenseBidAdapter.js b/modules/bucksenseBidAdapter.js index fcf99179993..7b6c3911ea1 100644 --- a/modules/bucksenseBidAdapter.js +++ b/modules/bucksenseBidAdapter.js @@ -4,7 +4,7 @@ import { BANNER } from '../src/mediaTypes.js'; const WHO = 'BKSHBID-005'; const BIDDER_CODE = 'bucksense'; -const URL = 'https://prebid.bksn.se/prebidjs/'; +const URL = 'https://directo.prebidserving.com/prebidjs/'; export const spec = { code: BIDDER_CODE, From b50716816925f8c4865a21ad3969eaad20942a35 Mon Sep 17 00:00:00 2001 From: Yohan Boutin Date: Mon, 28 Nov 2022 18:45:35 +0100 Subject: [PATCH 161/367] Seedtag Bid Adapter : add support for inBanner and inStream (#9230) * use inBanner and inStream for video * remove duplicate video params, now use only params from adunit level * lint * improve unit test * fix adapter for instream support, and fix unit test * use inStream placement for instream context * use ALLOWED_DISPLAY_PLACEMENTS * fix lint error * empty commit to relaunch CI --- modules/seedtagBidAdapter.js | 123 ++++++++------- modules/seedtagBidAdapter.md | 60 ++++++++ test/spec/modules/seedtagBidAdapter_spec.js | 157 ++++++++------------ 3 files changed, 192 insertions(+), 148 deletions(-) diff --git a/modules/seedtagBidAdapter.js b/modules/seedtagBidAdapter.js index 850ac5610f5..1a4f903789b 100644 --- a/modules/seedtagBidAdapter.js +++ b/modules/seedtagBidAdapter.js @@ -1,19 +1,18 @@ import { isArray, _map, triggerPixel } from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js' -import { VIDEO, BANNER } from '../src/mediaTypes.js' +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; const BIDDER_CODE = 'seedtag'; const SEEDTAG_ALIAS = 'st'; const SEEDTAG_SSP_ENDPOINT = 'https://s.seedtag.com/c/hb/bid'; const SEEDTAG_SSP_ONTIMEOUT_ENDPOINT = 'https://s.seedtag.com/se/hb/timeout'; -const ALLOWED_PLACEMENTS = { - inImage: true, - inScreen: true, - inArticle: true, - banner: true, - video: true -} +const ALLOWED_DISPLAY_PLACEMENTS = [ + 'inScreen', + 'inImage', + 'inArticle', + 'inBanner', +]; // Global Vendor List Id // https://iabeurope.eu/vendor-list-tcf-v2-0/ @@ -21,27 +20,33 @@ const GVLID = 157; const mediaTypesMap = { [BANNER]: 'display', - [VIDEO]: 'video' + [VIDEO]: 'video', }; const deviceConnection = { FIXED: 'fixed', MOBILE: 'mobile', - UNKNOWN: 'unknown' + UNKNOWN: 'unknown', }; const getConnectionType = () => { - const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection || {} + const connection = + navigator.connection || + navigator.mozConnection || + navigator.webkitConnection || + {}; switch (connection.type || connection.effectiveType) { case 'wifi': case 'ethernet': - return deviceConnection.FIXED + return deviceConnection.FIXED; case 'cellular': case 'wimax': - return deviceConnection.MOBILE + return deviceConnection.MOBILE; default: - const isMobile = /iPad|iPhone|iPod/.test(navigator.userAgent) || /android/i.test(navigator.userAgent) - return isMobile ? deviceConnection.UNKNOWN : deviceConnection.FIXED + const isMobile = + /iPad|iPhone|iPod/.test(navigator.userAgent) || + /android/i.test(navigator.userAgent); + return isMobile ? deviceConnection.UNKNOWN : deviceConnection.FIXED; } }; @@ -52,24 +57,32 @@ function mapMediaType(seedtagMediaType) { } function hasVideoMediaType(bid) { - return (!!bid.mediaTypes && !!bid.mediaTypes.video) || (!!bid.params && !!bid.params.video) + return !!bid.mediaTypes && !!bid.mediaTypes.video; } -function hasMandatoryParams(params) { +function hasMandatoryDisplayParams(bid) { + const p = bid.params; return ( - !!params.publisherId && - !!params.adUnitId && - !!params.placement && - !!ALLOWED_PLACEMENTS[params.placement] + !!p.publisherId && + !!p.adUnitId && + ALLOWED_DISPLAY_PLACEMENTS.indexOf(p.placement) > -1 ); } function hasMandatoryVideoParams(bid) { - const videoParams = getVideoParams(bid) + const videoParams = getVideoParams(bid); - return hasVideoMediaType(bid) && !!videoParams.playerSize && + return ( + !!bid.params.publisherId && + !!bid.params.adUnitId && + hasVideoMediaType(bid) && + !!videoParams.playerSize && isArray(videoParams.playerSize) && - videoParams.playerSize.length > 0; + videoParams.playerSize.length > 0 && + // only instream is supported for video + videoParams.context === 'instream' && + bid.params.placement === 'inStream' + ); } function buildBidRequest(validBidRequest) { @@ -89,15 +102,11 @@ function buildBidRequest(validBidRequest) { adUnitId: params.adUnitId, adUnitCode: validBidRequest.adUnitCode, placement: params.placement, - requestCount: validBidRequest.bidderRequestsCount || 1 // FIXME : in unit test the parameter bidderRequestsCount is undefined + requestCount: validBidRequest.bidderRequestsCount || 1, // FIXME : in unit test the parameter bidderRequestsCount is undefined }; - if (params.adPosition) { - bidRequest.adPosition = params.adPosition; - } - if (hasVideoMediaType(validBidRequest)) { - bidRequest.videoParams = getVideoParams(validBidRequest) + bidRequest.videoParams = getVideoParams(validBidRequest); } return bidRequest; @@ -113,13 +122,7 @@ function getVideoParams(validBidRequest) { videoParams.h = videoParams.playerSize[0][1]; } - const bidderVideoParams = (validBidRequest.params && validBidRequest.params.video) || {} - // override video params from seedtag bidder params - Object.keys(bidderVideoParams).forEach(key => { - videoParams[key] = validBidRequest.params.video[key] - }) - - return videoParams + return videoParams; } function buildBidResponse(seedtagBid) { @@ -136,8 +139,11 @@ function buildBidResponse(seedtagBid) { ttl: seedtagBid.ttl, nurl: seedtagBid.nurl, meta: { - advertiserDomains: seedtagBid && seedtagBid.adomain && seedtagBid.adomain.length > 0 ? seedtagBid.adomain : [] - } + advertiserDomains: + seedtagBid && seedtagBid.adomain && seedtagBid.adomain.length > 0 + ? seedtagBid.adomain + : [], + }, }; if (mediaType === VIDEO) { @@ -181,16 +187,21 @@ function ttfb() { export function getTimeoutUrl(data) { let queryParams = ''; if ( - isArray(data) && data[0] && - isArray(data[0].params) && data[0].params[0] + isArray(data) && + data[0] && + isArray(data[0].params) && + data[0].params[0] ) { const params = data[0].params[0]; - const timeout = data[0].timeout + const timeout = data[0].timeout; queryParams = - '?publisherToken=' + params.publisherId + - '&adUnitId=' + params.adUnitId + - '&timeout=' + timeout; + '?publisherToken=' + + params.publisherId + + '&adUnitId=' + + params.adUnitId + + '&timeout=' + + timeout; } return SEEDTAG_SSP_ONTIMEOUT_ENDPOINT + queryParams; } @@ -208,8 +219,8 @@ export const spec = { */ isBidRequestValid(bid) { return hasVideoMediaType(bid) - ? hasMandatoryParams(bid.params) && hasMandatoryVideoParams(bid) - : hasMandatoryParams(bid.params); + ? hasMandatoryVideoParams(bid) + : hasMandatoryDisplayParams(bid); }, /** @@ -237,24 +248,24 @@ export const spec = { payload['cd'] = bidderRequest.gdprConsent.consentString; } if (bidderRequest.uspConsent) { - payload['uspConsent'] = bidderRequest.uspConsent + payload['uspConsent'] = bidderRequest.uspConsent; } if (validBidRequests[0].schain) { payload.schain = validBidRequests[0].schain; } - let coppa = config.getConfig('coppa') + let coppa = config.getConfig('coppa'); if (coppa) { - payload.coppa = coppa + payload.coppa = coppa; } - const payloadString = JSON.stringify(payload) + const payloadString = JSON.stringify(payload); return { method: 'POST', url: SEEDTAG_SSP_ENDPOINT, - data: payloadString - } + data: payloadString, + }; }, /** @@ -308,6 +319,6 @@ export const spec = { if (bid && bid.nurl) { triggerPixel(bid.nurl); } - } -} + }, +}; registerBidder(spec); diff --git a/modules/seedtagBidAdapter.md b/modules/seedtagBidAdapter.md index 061a254c5fa..8ccfcfb701e 100644 --- a/modules/seedtagBidAdapter.md +++ b/modules/seedtagBidAdapter.md @@ -59,3 +59,63 @@ const adUnits = [ } ] ``` + +## InBanner +```js +const adUnits = [ + { + code: '/21804003197/prebid_test_300x250', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [ + { + bidder: 'seedtag', + params: { + publisherId: '0000-0000-01', // required + adUnitId: '0000', // required + placement: 'inBanner', // required + } + } + ] + } +] +``` + +## inStream Video +```js +var adUnits = [{ + code: 'video', + mediaTypes: { + video: { + context: 'instream', // required + playerSize: [640, 360], // required + // Video object as specified in OpenRTB 2.5 + mimes: ['video/mp4'], // recommended + minduration: 5, // optional + maxduration: 60, // optional + boxingallowed: 1, // optional + skip: 1, // optional + startdelay: 1, // optional + linearity: 1, // optional + battr: [1, 2], // optional + maxbitrate: 10, // optional + playbackmethod: [1], // optional + delivery: [1], // optional + placement: 1, // optional + } + }, + bids: [ + { + bidder: 'seedtag', + params: { + publisherId: '0000-0000-01', // required + adUnitId: '0000', // required + placement: 'inStream', // required + } + } + ] +}]; +``` diff --git a/test/spec/modules/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js index bd726bfe971..d0efd5f1f75 100644 --- a/test/spec/modules/seedtagBidAdapter_spec.js +++ b/test/spec/modules/seedtagBidAdapter_spec.js @@ -25,11 +25,11 @@ function getSlotConfigs(mediaTypes, params) { }; } -function createVideoSlotConfig(mediaType) { +function createInStreamSlotConfig(mediaType) { return getSlotConfigs(mediaType, { publisherId: PUBLISHER_ID, adUnitId: ADUNIT_ID, - placement: 'video', + placement: 'inStream', }); } @@ -48,13 +48,7 @@ describe('Seedtag Adapter', function () { } ); }; - const placements = [ - 'banner', - 'video', - 'inImage', - 'inScreen', - 'inArticle', - ]; + const placements = ['inBanner', 'inImage', 'inScreen', 'inArticle']; placements.forEach((placement) => { it('should be ' + placement, function () { const isBidRequestValid = spec.isBidRequestValid( @@ -67,39 +61,41 @@ describe('Seedtag Adapter', function () { }); describe('when video slot has all mandatory params', function () { it('should return true, when video context is instream', function () { - const slotConfig = getSlotConfigs( - { - video: { - context: 'instream', - playerSize: [[600, 200]], - }, + const slotConfig = createInStreamSlotConfig({ + video: { + context: 'instream', + playerSize: [[600, 200]], }, - { - publisherId: PUBLISHER_ID, - adUnitId: ADUNIT_ID, - placement: 'video', - } - ); + }); const isBidRequestValid = spec.isBidRequestValid(slotConfig); expect(isBidRequestValid).to.equal(true); }); - - it('should return true, when video context is outstream', function () { + it('should return true, when video context is instream, but placement is not inStream', function () { const slotConfig = getSlotConfigs( { video: { - context: 'outstream', + context: 'instream', playerSize: [[600, 200]], }, }, { publisherId: PUBLISHER_ID, adUnitId: ADUNIT_ID, - placement: 'video', + placement: 'inBanner', } ); const isBidRequestValid = spec.isBidRequestValid(slotConfig); - expect(isBidRequestValid).to.equal(true); + expect(isBidRequestValid).to.equal(false); + }); + it('should return false, when video context is outstream', function () { + const slotConfig = createInStreamSlotConfig({ + video: { + context: 'outstream', + playerSize: [[600, 200]], + }, + }); + const isBidRequestValid = spec.isBidRequestValid(slotConfig); + expect(isBidRequestValid).to.equal(false); }); }); }); @@ -112,7 +108,7 @@ describe('Seedtag Adapter', function () { const isBidRequestValid = spec.isBidRequestValid( createSlotConfig({ adUnitId: ADUNIT_ID, - placement: 'banner', + placement: 'inBanner', }) ); expect(isBidRequestValid).to.equal(false); @@ -121,7 +117,7 @@ describe('Seedtag Adapter', function () { const isBidRequestValid = spec.isBidRequestValid( createSlotConfig({ publisherId: PUBLISHER_ID, - placement: 'banner', + placement: 'inBanner', }) ); expect(isBidRequestValid).to.equal(false); @@ -146,47 +142,41 @@ describe('Seedtag Adapter', function () { expect(isBidRequestValid).to.equal(false); }); }); + describe('when video mediaType object is not correct', function () { - function createVideoSlotconfig(mediaType) { - return getSlotConfigs(mediaType, { - publisherId: PUBLISHER_ID, - adUnitId: ADUNIT_ID, - placement: 'video', - }); - } it('is a void object', function () { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotConfig({ video: {} }) + createInStreamSlotConfig({ video: {} }) ); expect(isBidRequestValid).to.equal(false); }); it('does not have playerSize.', function () { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotConfig({ video: { context: 'instream' } }) + createInStreamSlotConfig({ video: { context: 'instream' } }) ); expect(isBidRequestValid).to.equal(false); }); it('is outstream ', function () { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotConfig({ + createInStreamSlotConfig({ video: { context: 'outstream', playerSize: [[600, 200]], }, }) ); - expect(isBidRequestValid).to.equal(true); + expect(isBidRequestValid).to.equal(false); }); describe('order does not matter', function () { it('when video is not the first slot', function () { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotConfig({ banner: {}, video: {} }) + createInStreamSlotConfig({ banner: {}, video: {} }) ); expect(isBidRequestValid).to.equal(false); }); it('when video is the first slot', function () { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotConfig({ video: {}, banner: {} }) + createInStreamSlotConfig({ video: {}, banner: {} }) ); expect(isBidRequestValid).to.equal(false); }); @@ -200,21 +190,27 @@ describe('Seedtag Adapter', function () { refererInfo: { page: 'referer' }, timeout: 1000, }; - const mandatoryParams = { + const mandatoryDisplayParams = { publisherId: PUBLISHER_ID, adUnitId: ADUNIT_ID, - placement: 'banner', + placement: 'inBanner', + }; + const mandatoryVideoParams = { + publisherId: PUBLISHER_ID, + adUnitId: ADUNIT_ID, + placement: 'inStream', }; - const inStreamParams = Object.assign({}, mandatoryParams, { - video: { - mimes: 'mp4', - }, - }); const validBidRequests = [ - getSlotConfigs({ banner: {} }, mandatoryParams), + getSlotConfigs({ banner: {} }, mandatoryDisplayParams), getSlotConfigs( - { video: { context: 'instream', playerSize: [[300, 200]] } }, - inStreamParams + { + video: { + context: 'instream', + playerSize: [[300, 200]], + mimes: ['video/mp4'], + }, + }, + mandatoryVideoParams ), ]; it('Url params should be correct ', function () { @@ -239,26 +235,6 @@ describe('Seedtag Adapter', function () { expect(data.bidRequests[0].adUnitCode).to.equal('adunit-code'); }); - describe('adPosition param', function () { - it('should sended when publisher set adPosition param', function () { - const params = Object.assign({}, mandatoryParams, { - adPosition: 1, - }); - const validBidRequests = [getSlotConfigs({ banner: {} }, params)]; - const request = spec.buildRequests(validBidRequests, bidderRequest); - const data = JSON.parse(request.data); - expect(data.bidRequests[0].adPosition).to.equal(1); - }); - it('should not sended when publisher has not set adPosition param', function () { - const validBidRequests = [ - getSlotConfigs({ banner: {} }, mandatoryParams), - ]; - const request = spec.buildRequests(validBidRequests, bidderRequest); - const data = JSON.parse(request.data); - expect(data.bidRequests[0].adPosition).to.equal(undefined); - }); - }); - describe('GDPR params', function () { describe('when there arent consent management platform', function () { it('cmp should be false', function () { @@ -310,10 +286,7 @@ describe('Seedtag Adapter', function () { bidderRequest['uspConsent'] = uspConsent; - const request = spec.buildRequests( - validBidRequests, - bidderRequest - ); + const request = spec.buildRequests(validBidRequests, bidderRequest); const payload = JSON.parse(request.data); expect(payload.uspConsent).to.not.exist; @@ -347,7 +320,7 @@ describe('Seedtag Adapter', function () { ); expect(videoBid.supplyTypes[0]).to.equal('video'); expect(videoBid.adUnitId).to.equal('000000'); - expect(videoBid.videoParams.mimes).to.equal('mp4'); + expect(videoBid.videoParams.mimes).to.eql(['video/mp4']); expect(videoBid.videoParams.w).to.equal(300); expect(videoBid.videoParams.h).to.equal(200); expect(videoBid.sizes[0][0]).to.equal(300); @@ -360,27 +333,27 @@ describe('Seedtag Adapter', function () { describe('COPPA param', function () { it('should add COPPA param to payload when prebid config has parameter COPPA equal to true', function () { - config.setConfig({ coppa: true }) + config.setConfig({ coppa: true }); const request = spec.buildRequests(validBidRequests, bidderRequest); const data = JSON.parse(request.data); expect(data.coppa).to.equal(true); - }) + }); it('should not add COPPA param to payload when prebid config has parameter COPPA equal to false', function () { - config.setConfig({ coppa: false }) + config.setConfig({ coppa: false }); const request = spec.buildRequests(validBidRequests, bidderRequest); const data = JSON.parse(request.data); expect(data.coppa).to.be.undefined; - }) + }); it('should not add COPPA param to payload when prebid config has not parameter COPPA', function () { const request = spec.buildRequests(validBidRequests, bidderRequest); const data = JSON.parse(request.data); expect(data.coppa).to.be.undefined; - }) - }) + }); + }); describe('schain param', function () { it('should add schain to payload when exposed on validBidRequest', function () { // https://github.com/prebid/Prebid.js/blob/master/modules/schain.md#sample-code-for-passing-the-schain-object @@ -560,11 +533,11 @@ describe('Seedtag Adapter', function () { const timeoutUrl = getTimeoutUrl(timeoutData); expect(timeoutUrl).to.equal( 'https://s.seedtag.com/se/hb/timeout?publisherToken=' + - params.publisherId + - '&adUnitId=' + - params.adUnitId + - '&timeout=' + - timeout + params.publisherId + + '&adUnitId=' + + params.adUnitId + + '&timeout=' + + timeout ); }); @@ -576,11 +549,11 @@ describe('Seedtag Adapter', function () { expect( utils.triggerPixel.calledWith( 'https://s.seedtag.com/se/hb/timeout?publisherToken=' + - params.publisherId + - '&adUnitId=' + - params.adUnitId + - '&timeout=' + - timeout + params.publisherId + + '&adUnitId=' + + params.adUnitId + + '&timeout=' + + timeout ) ).to.equal(true); }); From fe652b47deecf0eab3d16bfa02d1bbaa5b032c2b Mon Sep 17 00:00:00 2001 From: GeoEdge-r-and-d <72186958+GeoEdge-r-and-d@users.noreply.github.com> Date: Mon, 28 Nov 2022 20:22:03 +0200 Subject: [PATCH 162/367] Geoedge RTD module: support billing events (#9267) * Add billable events for applicable winning bids * Update test for billable events * Add meta bid advertiser domains collection * Revert "Add meta bid advertiser domains collection" This reverts commit 09c19c90b4dc9d234f282de8adb40850cce31101. * Add meta bid advertiser domains collection * Update geoedgeRtdProvider_spec.js Force circleci Co-authored-by: daniel manan Co-authored-by: Patrick McCann --- modules/geoedgeRtdProvider.js | 22 ++++++++++++++++++++ test/spec/modules/geoedgeRtdProvider_spec.js | 15 +++++++++++++ 2 files changed, 37 insertions(+) diff --git a/modules/geoedgeRtdProvider.js b/modules/geoedgeRtdProvider.js index 001ef67b66a..6f910632fbc 100644 --- a/modules/geoedgeRtdProvider.js +++ b/modules/geoedgeRtdProvider.js @@ -18,6 +18,8 @@ import { submodule } from '../src/hook.js'; import { ajax } from '../src/ajax.js'; import { generateUUID, insertElement, isEmpty, logError } from '../src/utils.js'; +import * as events from '../src/events.js'; +import CONSTANTS from '../src/constants.json'; /** @type {string} */ const SUBMODULE_NAME = 'geoedge'; @@ -105,6 +107,7 @@ function getMacros(bid, key) { '%%PATTERN:hb_bidder%%': bid.bidderCode, '%_isHb!': true, '%_hbcid!': bid.creativeId || '', + '%_hbadomains': bid.meta && bid.meta.advertiserDomains, '%%PATTERN:hb_pb%%': bid.pbHg, '%%SITE%%': location.hostname, '%_pimp%': PV_ID @@ -184,6 +187,24 @@ function conditionallyWrap(bidResponse, config, userConsent) { } } +/** + * Fire billable events for applicable bids + */ +function fireBillableEventsForApplicableBids(params) { + events.on(CONSTANTS.EVENTS.BID_WON, function (winningBid) { + if (shouldWrap(winningBid, params)) { + events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + vendor: SUBMODULE_NAME, + billingId: generateUUID(), + type: 'impression', + transactionId: winningBid.transactionId, + auctionId: winningBid.auctionId, + bidId: winningBid.requestId + }); + } + }); +} + function init(config, userConsent) { let params = config.params; if (!params || !params.key) { @@ -191,6 +212,7 @@ function init(config, userConsent) { return false; } preloadClient(params.key); + fireBillableEventsForApplicableBids(params); return true; } diff --git a/test/spec/modules/geoedgeRtdProvider_spec.js b/test/spec/modules/geoedgeRtdProvider_spec.js index cf4e0b53fde..eec1feff87a 100644 --- a/test/spec/modules/geoedgeRtdProvider_spec.js +++ b/test/spec/modules/geoedgeRtdProvider_spec.js @@ -2,6 +2,8 @@ import * as utils from '../../../src/utils.js'; import * as hook from '../../../src/hook.js' import { beforeInit, geoedgeSubmodule, setWrapper, wrapper, htmlPlaceholder, WRAPPER_URL, getClientUrl } from '../../../modules/geoedgeRtdProvider.js'; import { server } from '../../../test/mocks/xhr.js'; +import * as events from '../../../src/events.js'; +import CONSTANTS from '../../../src/constants.json'; let key = '123123123'; function makeConfig() { @@ -88,6 +90,19 @@ describe('Geoedge RTD module', function () { let isLinkPreloadAsScript = arg => arg.tagName === 'LINK' && arg.rel === 'preload' && arg.as === 'script' && arg.href === getClientUrl(key); expect(insertElementStub.calledWith(sinon.match(isLinkPreloadAsScript))).to.equal(true); }); + it('should emit billable events with applicable winning bids', function () { + let applicableBid = mockBid('bidderA'); + let nonApplicableBid = mockBid('bidderB'); + let counter = 0; + events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, function (event) { + if (event.vendor === 'geoedge' && event.type === 'impression') { + counter += 1; + } + }); + events.emit(CONSTANTS.EVENTS.BID_WON, applicableBid); + events.emit(CONSTANTS.EVENTS.BID_WON, nonApplicableBid); + expect(counter).to.equal(1); + }); }); describe('onBidResponseEvent', function () { let bidFromA = mockBid('bidderA'); From ad595cc7e54b81ebbece381c9df9bb36d526ddb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udi=20Talias=20=E2=9A=9B=EF=B8=8F?= Date: Tue, 29 Nov 2022 16:43:26 +0200 Subject: [PATCH 163/367] Vidazoo Bid Adapter: added bid request params (gpid, cat, pagecat) (#9293) * feat(module): multi size request * fix getUserSyncs added tests * update(module): package-lock.json from master * feat(module): VidazooBidAdapter - send top query params to server * added bid request params * making the linter happy :) Co-authored-by: roman Co-authored-by: Saar Amrani <89377180+saar120@users.noreply.github.com> Co-authored-by: Saar Amrani --- modules/vidazooBidAdapter.js | 9 ++- test/spec/modules/vidazooBidAdapter_spec.js | 62 +++++++++++++-------- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index ac74dd18405..39c407ae8a6 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -70,6 +70,10 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { const subDomain = extractSubDomain(params); const ptrace = getCacheOpt(); + const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid', deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', '')); + const cat = deepAccess(bidderRequest, 'ortb2.site.cat', []); + const pagecat = deepAccess(bidderRequest, 'ortb2.site.pagecat', []); + if (isFn(bid.getFloor)) { const floorInfo = bid.getFloor({ currency: 'USD', @@ -99,7 +103,10 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { prebidVersion: '$prebid.version$', res: `${screen.width}x${screen.height}`, schain: schain, - ptrace: ptrace + ptrace: ptrace, + gpid: gpid, + cat: cat, + pagecat: pagecat }; appendUserIdsToRequestPayload(data, userId); diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index 856ceaf438d..7c7f27a830b 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -1,4 +1,4 @@ -import {expect} from 'chai'; +import { expect } from 'chai'; import { spec as adapter, SUPPORTED_ID_SYSTEMS, @@ -15,8 +15,8 @@ import { getVidazooSessionId, } from 'modules/vidazooBidAdapter.js'; import * as utils from 'src/utils.js'; -import {version} from 'package.json'; -import {useFakeTimers} from 'sinon'; +import { version } from 'package.json'; +import { useFakeTimers } from 'sinon'; const SUB_DOMAIN = 'openrtb'; @@ -38,7 +38,12 @@ const BID = { 'sizes': [[300, 250], [300, 600]], 'bidderRequestId': '1fdb5ff1b6eaa7', 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', - 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc' + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'ortb2Imp': { + 'ext': { + 'gpid': '1234567890' + } + } }; const BIDDER_REQUEST = { @@ -50,7 +55,13 @@ const BIDDER_REQUEST = { 'refererInfo': { 'page': 'https://www.greatsite.com', 'ref': 'https://www.somereferrer.com' - } + }, + 'ortb2': { + 'site': { + 'cat': ['IAB2'], + 'pagecat': ['IAB2-2'] + } + }, }; const SERVER_RESPONSE = { @@ -85,7 +96,7 @@ const REQUEST = { function getTopWindowQueryParams() { try { - const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true}); + const parsedUrl = utils.parseUrl(window.top.document.URL, { decodeSearchAsString: true }); return parsedUrl.search; } catch (e) { return ''; @@ -150,7 +161,7 @@ describe('VidazooBidAdapter', function () { before(function () { $$PREBID_GLOBAL$$.bidderSettings = { vidazoo: { - storageAllowed: true + storageAllowed: true, } }; sandbox = sinon.sandbox.create(); @@ -187,6 +198,9 @@ describe('VidazooBidAdapter', function () { uqs: getTopWindowQueryParams(), 'ext.param1': 'loremipsum', 'ext.param2': 'dolorsitamet', + gpid: '1234567890', + cat: ['IAB2'], + pagecat: ['IAB2-2'] } }); }); @@ -198,7 +212,7 @@ describe('VidazooBidAdapter', function () { }); describe('getUserSyncs', function () { it('should have valid user sync with iframeEnabled', function () { - const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ type: 'iframe', @@ -207,7 +221,7 @@ describe('VidazooBidAdapter', function () { }); it('should have valid user sync with cid on response', function () { - const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ type: 'iframe', url: 'https://sync.cootlogix.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' @@ -215,7 +229,7 @@ describe('VidazooBidAdapter', function () { }); it('should have valid user sync with pixelEnabled', function () { - const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({ pixelEnabled: true }, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ 'url': 'https://sync.cootlogix.com/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=', @@ -231,12 +245,12 @@ describe('VidazooBidAdapter', function () { }); it('should return empty array when there is no ad', function () { - const responses = adapter.interpretResponse({price: 1, ad: ''}); + const responses = adapter.interpretResponse({ price: 1, ad: '' }); expect(responses).to.be.empty; }); it('should return empty array when there is no price', function () { - const responses = adapter.interpretResponse({price: null, ad: 'great ad'}); + const responses = adapter.interpretResponse({ price: null, ad: 'great ad' }); expect(responses).to.be.empty; }); @@ -276,11 +290,11 @@ describe('VidazooBidAdapter', function () { const userId = (function () { switch (idSystemProvider) { case 'lipb': - return {lipbid: id}; + return { lipbid: id }; case 'parrableId': - return {eid: id}; + return { eid: id }; case 'id5id': - return {uid: id}; + return { uid: id }; default: return id; } @@ -299,18 +313,18 @@ describe('VidazooBidAdapter', function () { describe('alternate param names extractors', function () { it('should return undefined when param not supported', function () { - const cid = extractCID({'c_id': '1'}); - const pid = extractPID({'p_id': '1'}); - const subDomain = extractSubDomain({'sub_domain': 'prebid'}); + const cid = extractCID({ 'c_id': '1' }); + const pid = extractPID({ 'p_id': '1' }); + const subDomain = extractSubDomain({ 'sub_domain': 'prebid' }); expect(cid).to.be.undefined; expect(pid).to.be.undefined; expect(subDomain).to.be.undefined; }); it('should return value when param supported', function () { - const cid = extractCID({'cID': '1'}); - const pid = extractPID({'Pid': '2'}); - const subDomain = extractSubDomain({'subDOMAIN': 'prebid'}); + const cid = extractCID({ 'cID': '1' }); + const pid = extractPID({ 'Pid': '2' }); + const subDomain = extractSubDomain({ 'subDOMAIN': 'prebid' }); expect(cid).to.be.equal('1'); expect(pid).to.be.equal('2'); expect(subDomain).to.be.equal('prebid'); @@ -423,7 +437,7 @@ describe('VidazooBidAdapter', function () { now }); setStorageItem('myKey', 2020); - const {value, created} = getStorageItem('myKey'); + const { value, created } = getStorageItem('myKey'); expect(created).to.be.equal(now); expect(value).to.be.equal(2020); expect(typeof value).to.be.equal('number'); @@ -439,8 +453,8 @@ describe('VidazooBidAdapter', function () { }); it('should parse JSON value', function () { - const data = JSON.stringify({event: 'send'}); - const {event} = tryParseJSON(data); + const data = JSON.stringify({ event: 'send' }); + const { event } = tryParseJSON(data); expect(event).to.be.equal('send'); }); From 64e557abfa36f9387678e7ddeb784091cb4419a7 Mon Sep 17 00:00:00 2001 From: JulieLorin Date: Tue, 29 Nov 2022 16:32:01 +0100 Subject: [PATCH 164/367] PBjs Core : send native targetings for ortb response (#9252) * PBjs Core : send native targetings for ortb response * Add legacy native properties regardless of response mediaType * add a test for addLegacyFieldsIfNeeded * fix lint for test Co-authored-by: Demetrio Girardi --- src/auction.js | 20 ++++- src/native.js | 51 ++++++++----- test/spec/auctionmanager_spec.js | 76 +++++++++++++++++++ test/spec/native_spec.js | 124 +++++++++++++++++-------------- 4 files changed, 193 insertions(+), 78 deletions(-) diff --git a/src/auction.js b/src/auction.js index 6376457c1d6..563eb85e788 100644 --- a/src/auction.js +++ b/src/auction.js @@ -76,7 +76,7 @@ import { timestamp } from './utils.js'; import {getPriceBucketString} from './cpmBucketManager.js'; -import {getNativeTargeting} from './native.js'; +import {getNativeTargeting, toLegacyResponse} from './native.js'; import {getCacheUrl, store} from './videoCache.js'; import {Renderer} from './Renderer.js'; import {config} from './config.js'; @@ -462,9 +462,14 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM handleBidResponse(adUnitCode, bid, (done) => { let bidResponse = getPreparedBidForAuction(bid); - if (bidResponse.mediaType === 'video') { + if (bidResponse.mediaType === VIDEO) { tryAddVideoBid(auctionInstance, bidResponse, done); } else { + if (FEATURES.NATIVE && bidResponse.native != null && typeof bidResponse.native === 'object') { + // NOTE: augment bidResponse.native even if bidResponse.mediaType !== NATIVE; it's possible + // to treat banner responses as native + addLegacyFieldsIfNeeded(bidResponse); + } addBidToAuction(auctionInstance, bidResponse); done(); } @@ -593,6 +598,17 @@ function tryAddVideoBid(auctionInstance, bidResponse, afterBidAdded, {index = au } } +// Native bid response might be in ortb2 format - adds legacy field for backward compatibility +const addLegacyFieldsIfNeeded = (bidResponse) => { + const nativeOrtbRequest = auctionManager.index.getAdUnit(bidResponse)?.nativeOrtbRequest; + const nativeOrtbResponse = bidResponse.native?.ortb + + if (nativeOrtbRequest && nativeOrtbResponse) { + const legacyResponse = toLegacyResponse(nativeOrtbResponse, nativeOrtbRequest); + Object.assign(bidResponse.native, legacyResponse); + } +} + const storeInCache = (batch) => { store(batch.map(entry => entry.bidResponse), function (error, cacheIds) { cacheIds.forEach((cacheId, i) => { diff --git a/src/native.js b/src/native.js index 022ece457f5..25f8c38cb30 100644 --- a/src/native.js +++ b/src/native.js @@ -23,7 +23,7 @@ export const NATIVE_TARGETING_KEYS = Object.keys(CONSTANTS.NATIVE_KEYS).map( key => CONSTANTS.NATIVE_KEYS[key] ); -const IMAGE = { +export const IMAGE = { ortb: { ver: '1.2', assets: [ @@ -385,26 +385,14 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) { return keyValues; } -const getNativeRequest = (bidResponse) => auctionManager.index.getAdUnit(bidResponse)?.nativeOrtbRequest; - -function assetsMessage(data, adObject, keys, {getNativeReq = getNativeRequest} = {}) { +function assetsMessage(data, adObject, keys) { const message = { message: 'assetResponse', adId: data.adId, }; - // Pass to Prebid Universal Creative all assets, the legacy ones + the ortb ones (under ortb property) - const ortbRequest = getNativeReq(adObject); let nativeResp = adObject.native; - const ortbResponse = adObject.native?.ortb; - let legacyResponse = {}; - if (ortbRequest && ortbResponse) { - legacyResponse = toLegacyResponse(ortbResponse, ortbRequest); - nativeResp = { - ...adObject.native, - ...legacyResponse - }; - } + if (adObject.native.ortb) { message.ortb = adObject.native.ortb; } @@ -435,13 +423,13 @@ function assetsMessage(data, adObject, keys, {getNativeReq = getNativeRequest} = * Constructs a message object containing asset values for each of the * requested data keys. */ -export function getAssetMessage(data, adObject, {getNativeReq = getNativeRequest} = {}) { +export function getAssetMessage(data, adObject) { const keys = data.assets.map((k) => getKeyByValue(CONSTANTS.NATIVE_KEYS, k)); - return assetsMessage(data, adObject, keys, {getNativeReq}); + return assetsMessage(data, adObject, keys); } -export function getAllAssetsMessage(data, adObject, {getNativeReq = getNativeRequest} = {}) { - return assetsMessage(data, adObject, null, {getNativeReq}); +export function getAllAssetsMessage(data, adObject) { + return assetsMessage(data, adObject, null); } /** @@ -749,7 +737,7 @@ export function toOrtbNativeResponse(legacyResponse, ortbRequest) { * @param {*} ortbRequest the ortb request, useful to match ids. * @returns an object containing the response in legacy native format: { title: "this is a title", image: ... } */ -function toLegacyResponse(ortbResponse, ortbRequest) { +export function toLegacyResponse(ortbResponse, ortbRequest) { const legacyResponse = {}; const requestAssets = ortbRequest?.assets || []; legacyResponse.clickUrl = ortbResponse.link.url; @@ -764,6 +752,29 @@ function toLegacyResponse(ortbResponse, ortbRequest) { legacyResponse[PREBID_NATIVE_DATA_KEYS_TO_ORTB_INVERSE[NATIVE_ASSET_TYPES_INVERSE[requestAsset.data.type]]] = asset.data.value; } } + + // Handle trackers + legacyResponse.impressionTrackers = []; + let jsTrackers = []; + + if (ortbRequest?.imptrackers) { + legacyResponse.impressionTrackers.push(...ortbRequest.imptrackers); + } + for (const eventTracker of ortbResponse?.eventtrackers || []) { + if (eventTracker.event === TRACKER_EVENTS.impression && eventTracker.method === TRACKER_METHODS.img) { + legacyResponse.impressionTrackers.push(eventTracker.url); + } + if (eventTracker.event === TRACKER_EVENTS.impression && eventTracker.method === TRACKER_METHODS.js) { + jsTrackers.push(eventTracker.url); + } + } + + jsTrackers = jsTrackers.map(url => ``); + if (ortbResponse?.jstracker) { jsTrackers.push(ortbResponse.jstracker); } + if (jsTrackers.length) { + legacyResponse.javascriptTrackers = jsTrackers.join('\n'); + } + return legacyResponse; } diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index 443147f5d20..46350895050 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -22,6 +22,7 @@ import 'modules/debugging/index.js' // some tests look for debugging side effect import {AuctionIndex} from '../../src/auctionIndex.js'; import {expect} from 'chai'; import {deepClone} from '../../src/utils.js'; +import { IMAGE as ortbNativeRequest } from 'src/native.js'; var assert = require('assert'); @@ -1276,6 +1277,81 @@ describe('auctionmanager.js', function () { }); }); + if (FEATURES.NATIVE) { + describe('addBidResponse native', function () { + let makeRequestsStub; + let ajaxStub; + let spec; + let auction; + + beforeEach(function () { + makeRequestsStub = sinon.stub(adapterManager, 'makeBidRequests'); + ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockAjaxBuilder); + + const adUnits = [{ + code: ADUNIT_CODE, + transactionId: ADUNIT_CODE, + bids: [ + {bidder: BIDDER_CODE, params: {placementId: 'id'}}, + ], + nativeOrtbRequest: ortbNativeRequest.ortb, + mediaTypes: { native: { type: 'image' } } + }]; + auction = auctionModule.newAuction({adUnits, adUnitCodes: [ADUNIT_CODE], callback: function() {}, cbTimeout: 3000}); + indexAuctions = [auction]; + const createAuctionStub = sinon.stub(auctionModule, 'newAuction'); + createAuctionStub.returns(auction); + + spec = mockBidder(BIDDER_CODE); + registerBidder(spec); + }); + + afterEach(function () { + ajaxStub.restore(); + auctionModule.newAuction.restore(); + adapterManager.makeBidRequests.restore(); + }); + + it('should add legacy fields to native response', function () { + let nativeBid = mockBid(); + nativeBid.mediaType = 'native'; + nativeBid.native = { + ortb: { + ver: '1.2', + assets: [ + { id: 2, title: { text: 'Sample title' } }, + { id: 4, data: { value: 'Sample body' } }, + { id: 3, data: { value: 'Sample sponsoredBy' } }, + { id: 1, img: { url: 'https://www.example.com/image.png', w: 200, h: 200 } }, + { id: 5, img: { url: 'https://www.example.com/icon.png', w: 32, h: 32 } } + ], + link: { url: 'http://www.click.com' }, + eventtrackers: [ + { event: 1, method: 1, url: 'http://www.imptracker.com' }, + { event: 1, method: 2, url: 'http://www.jstracker.com/file.js' } + ] + } + } + + let bidRequest = mockBidRequest(nativeBid, { mediaType: { native: ortbNativeRequest } }); + makeRequestsStub.returns([bidRequest]); + + spec.interpretResponse.returns(nativeBid); + auction.callBids(); + + const addedBid = auction.getBidsReceived().pop(); + assert.equal(addedBid.native.body, 'Sample body') + assert.equal(addedBid.native.title, 'Sample title') + assert.equal(addedBid.native.sponsoredBy, 'Sample sponsoredBy') + assert.equal(addedBid.native.clickUrl, 'http://www.click.com') + assert.equal(addedBid.native.image, 'https://www.example.com/image.png') + assert.equal(addedBid.native.icon, 'https://www.example.com/icon.png') + assert.equal(addedBid.native.impressionTrackers[0], 'http://www.imptracker.com') + assert.equal(addedBid.native.javascriptTrackers, '') + }); + }); + } + describe('getMediaTypeGranularity', function () { it('video', function () { let mediaTypes = { video: {id: '1'} }; diff --git a/test/spec/native_spec.js b/test/spec/native_spec.js index 23350781a3d..2b7c2b88449 100644 --- a/test/spec/native_spec.js +++ b/test/spec/native_spec.js @@ -5,6 +5,7 @@ import { nativeBidIsValid, getAssetMessage, getAllAssetsMessage, + toLegacyResponse, decorateAdUnitsWithNativeParams, isOpenRTBBidRequestValid, isNativeOpenRTBBidValid, @@ -37,6 +38,7 @@ const bid = { clickTrackers: ['https://tracker.example'], impressionTrackers: ['https://impression.example'], javascriptTrackers: '', + privacyLink: 'https://privacy-link.example', ext: { foo: 'foo-value', baz: 'baz-value', @@ -98,9 +100,18 @@ const ortbBid = { privacy: 'https://privacy-link.example', ver: '1.2' } - }, + } }; +const completeNativeBid = { + adId: '123', + transactionId: 'au', + native: { + ...bid.native, + ...ortbBid.native + } +} + const ortbRequest = { assets: [ { @@ -224,6 +235,14 @@ describe('native.js', function () { expect(targeting.hb_native_baz).to.equal('hb_native_baz:123'); }); + it('sends placeholdes targetings with ortb native response', function () { + const targeting = getNativeTargeting(completeNativeBid); + + expect(targeting[CONSTANTS.NATIVE_KEYS.title]).to.equal('Native Creative'); + expect(targeting[CONSTANTS.NATIVE_KEYS.body]).to.equal('Cool description great stuff'); + expect(targeting[CONSTANTS.NATIVE_KEYS.clickUrl]).to.equal('https://www.link.example'); + }); + it('should only include native targeting keys with values', function () { const adUnit = { transactionId: 'au', @@ -302,6 +321,10 @@ describe('native.js', function () { required: false, sendTargetingKeys: false, }, + privacyLink: { + required: false, + sendTargetingKeys: false, + }, ext: { foo: { required: false, @@ -348,6 +371,7 @@ describe('native.js', function () { CONSTANTS.NATIVE_KEYS.icon, CONSTANTS.NATIVE_KEYS.sponsoredBy, CONSTANTS.NATIVE_KEYS.clickUrl, + CONSTANTS.NATIVE_KEYS.privacyLink, CONSTANTS.NATIVE_KEYS.rendererUrl, ]); @@ -380,6 +404,7 @@ describe('native.js', function () { CONSTANTS.NATIVE_KEYS.icon, CONSTANTS.NATIVE_KEYS.sponsoredBy, CONSTANTS.NATIVE_KEYS.clickUrl, + CONSTANTS.NATIVE_KEYS.privacyLink, ]); expect(bid.native.adTemplate).to.deep.equal( @@ -437,9 +462,9 @@ describe('native.js', function () { adId: '123', }; - const message = getAllAssetsMessage(messageRequest, bid, {getNativeReq: () => null}); + const message = getAllAssetsMessage(messageRequest, bid); - expect(message.assets.length).to.equal(9); + expect(message.assets.length).to.equal(10); expect(message.assets).to.deep.include({ key: 'body', value: bid.native.body, @@ -485,7 +510,7 @@ describe('native.js', function () { adId: '123', }; - const message = getAllAssetsMessage(messageRequest, bidWithUndefinedFields, {getNativeReq: () => null}); + const message = getAllAssetsMessage(messageRequest, bidWithUndefinedFields); expect(message.assets.length).to.equal(4); expect(message.assets).to.deep.include({ @@ -506,16 +531,16 @@ describe('native.js', function () { }); }); - it('creates native all asset message with OpenRTB format', function () { + it('creates native all asset message with complete format', function () { const messageRequest = { message: 'Prebid Native', action: 'allAssetRequest', adId: '123', }; - const message = getAllAssetsMessage(messageRequest, ortbBid, {getNativeReq: () => ortbRequest}); + const message = getAllAssetsMessage(messageRequest, completeNativeBid); - expect(message.assets.length).to.equal(8); + expect(message.assets.length).to.equal(10); expect(message.assets).to.deep.include({ key: 'body', value: bid.native.body, @@ -548,6 +573,14 @@ describe('native.js', function () { key: 'privacyLink', value: ortbBid.native.ortb.privacy, }); + expect(message.assets).to.deep.include({ + key: 'foo', + value: bid.native.ext.foo, + }); + expect(message.assets).to.deep.include({ + key: 'baz', + value: bid.native.ext.baz, + }); }); const SAMPLE_ORTB_REQUEST = toOrtbNativeRequest({ @@ -555,60 +588,39 @@ describe('native.js', function () { body: 'vbody' }); const SAMPLE_ORTB_RESPONSE = { - native: { - ortb: { - link: { - url: 'url' - }, - assets: [ - { - id: 0, - title: { - text: 'vtitle' - } - }, - { - id: 1, - data: { - value: 'vbody' - } - } - ] + link: { + url: 'url' + }, + assets: [ + { + id: 0, + title: { + text: 'vtitle' + } + }, + { + id: 1, + data: { + value: 'vbody' + } } - } + ], + eventtrackers: [ + { event: 1, method: 1, url: 'https://sampleurl.com' }, + { event: 1, method: 2, url: 'https://sampleurljs.com' } + ] } - describe('getAllAssetsMessage', () => { + describe('toLegacyResponse', () => { it('returns assets in legacy format for ortb responses', () => { - const actual = getAllAssetsMessage({}, SAMPLE_ORTB_RESPONSE, {getNativeReq: () => SAMPLE_ORTB_REQUEST}); - expect(actual.assets).to.eql([ - { - key: 'clickUrl', - value: 'url' - }, - { - key: 'title', - value: 'vtitle' - }, - { - key: 'body', - value: 'vbody' - }, - ]) + const actual = toLegacyResponse(SAMPLE_ORTB_RESPONSE, SAMPLE_ORTB_REQUEST); + expect(actual.body).to.equal('vbody'); + expect(actual.title).to.equal('vtitle'); + expect(actual.clickUrl).to.equal('url'); + expect(actual.javascriptTrackers).to.equal(''); + expect(actual.impressionTrackers.length).to.equal(1); + expect(actual.impressionTrackers[0]).to.equal('https://sampleurl.com'); }); }); - describe('getAssetsMessage', () => { - Object.entries({ - 'hb_native_title': {key: 'title', value: 'vtitle'}, - 'hb_native_body': {key: 'body', value: 'vbody'} - }).forEach(([tkey, assetVal]) => { - it(`returns ${tkey} asset in legacy format for ortb responses`, () => { - const actual = getAssetMessage({ - assets: [tkey] - }, SAMPLE_ORTB_RESPONSE, {getNativeReq: () => SAMPLE_ORTB_REQUEST}) - expect(actual.assets).to.eql([assetVal]) - }) - }) - }) }); describe('validate native openRTB', function () { From dd7d8a642598045b620c80236e6a568b3f14d9ba Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 29 Nov 2022 19:23:29 +0100 Subject: [PATCH 165/367] Impactify Bid Adapter: add support for BidFloor (#9277) * Add support of getFloor function * Add support of getFloor function * Add support of getFloor function * Add support of getFloor function * Add unit test for bid floor * Add unit test for bid floor Co-authored-by: Thomas De Stefano --- modules/impactifyBidAdapter.js | 20 ++++++++++++++++++- test/spec/modules/impactifyBidAdapter_spec.js | 13 ++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/modules/impactifyBidAdapter.js b/modules/impactifyBidAdapter.js index 0717cf43741..04f34bdc7d9 100644 --- a/modules/impactifyBidAdapter.js +++ b/modules/impactifyBidAdapter.js @@ -1,7 +1,7 @@ import { deepAccess, deepSetValue, generateUUID } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { config } from '../src/config.js'; -import {ajax} from '../src/ajax.js'; +import { ajax } from '../src/ajax.js'; import { createEidsArray } from './userId/eids.js'; const BIDDER_CODE = 'impactify'; @@ -27,6 +27,18 @@ const getDeviceType = () => { return 2; }; +const getFloor = (bid) => { + const floorInfo = bid.getFloor({ + currency: DEFAULT_CURRENCY, + mediaType: '*', + size: '*' + }); + if (typeof floorInfo === 'object' && floorInfo.currency === DEFAULT_CURRENCY && !isNaN(parseFloat(floorInfo.floor))) { + return parseFloat(floorInfo.floor); + } + return null; +} + const createOpenRtbRequest = (validBidRequests, bidderRequest) => { // Create request and set imp bids inside let request = { @@ -114,6 +126,12 @@ const createOpenRtbRequest = (validBidRequests, bidderRequest) => { if (bid.params.container) { imp.ext.impactify.container = bid.params.container; } + if (typeof bid.getFloor === 'function') { + const floor = getFloor(bid); + if (floor) { + imp.bidfloor = floor; + } + } request.imp.push(imp); }); diff --git a/test/spec/modules/impactifyBidAdapter_spec.js b/test/spec/modules/impactifyBidAdapter_spec.js index 8bb2d089ad8..215972ff450 100644 --- a/test/spec/modules/impactifyBidAdapter_spec.js +++ b/test/spec/modules/impactifyBidAdapter_spec.js @@ -166,6 +166,19 @@ describe('ImpactifyAdapter', function () { } }; + it('should pass bidfloor', function () { + videoBidRequests[0].getFloor = function() { + return { + currency: 'USD', + floor: 1.23, + } + } + + const res = spec.buildRequests(videoBidRequests, videoBidderRequest) + const resData = JSON.parse(res.data) + expect(resData.imp[0].bidfloor).to.equal(1.23) + }); + it('sends video bid request to ENDPOINT via POST', function () { const request = spec.buildRequests(videoBidRequests, videoBidderRequest); expect(request.url).to.equal(ORIGIN + AUCTIONURI); From 29c0d82898c6dbd171fe61814322d6188d91ef86 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Tue, 29 Nov 2022 14:18:57 -0500 Subject: [PATCH 166/367] TTD Bid Adapter: add support for regs.gpp (#9274) * Update ttdBidAdapter.js * Update ttdBidAdapter.js * Update ttdBidAdapter_spec.js * Update ttdBidAdapter_spec.js * Update ttdBidAdapter_spec.js * fix linting * Update ttdBidAdapter_spec.js * Update ttdBidAdapter_spec.js * Update ttdBidAdapter.js * Update ttdBidAdapter_spec.js * Update ttdBidAdapter.js * Update ttdBidAdapter.js * Update ttdBidAdapter.js * Update ttdBidAdapter.js * Update ttdBidAdapter.js * Update ttdBidAdapter.js * Update ttdBidAdapter.js Co-authored-by: Chris Huie --- modules/ttdBidAdapter.js | 4 ++++ test/spec/modules/ttdBidAdapter_spec.js | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/modules/ttdBidAdapter.js b/modules/ttdBidAdapter.js index 56dc44827b7..884c43c438a 100644 --- a/modules/ttdBidAdapter.js +++ b/modules/ttdBidAdapter.js @@ -38,6 +38,10 @@ function getRegs(bidderRequest) { if (config.getConfig('coppa') === true) { regs.coppa = 1; } + if (bidderRequest.ortb2?.regs) { + utils.mergeDeep(regs, bidderRequest.ortb2.regs); + } + return regs; } diff --git a/test/spec/modules/ttdBidAdapter_spec.js b/test/spec/modules/ttdBidAdapter_spec.js index 346f1ef88f6..f45872faec9 100644 --- a/test/spec/modules/ttdBidAdapter_spec.js +++ b/test/spec/modules/ttdBidAdapter_spec.js @@ -400,6 +400,20 @@ describe('ttdBidAdapter', function () { expect(requestBody.regs.coppa).to.equal(1); }); + it('adds gpp consent info to the request', function () { + const ortb2 = { + regs: { + gpp: 'somegppstring', + gpp_sid: [6, 7] + } + }; + let clonedBidderRequest = {...deepClone(baseBidderRequest), ortb2}; + const requestBody = testBuildRequests(baseBannerBidRequests, clonedBidderRequest).data; + config.resetConfig(); + expect(requestBody.regs.gpp).to.equal('somegppstring'); + expect(requestBody.regs.gpp_sid).to.eql([6, 7]); + }); + it('adds schain info to the request', function () { const schain = { 'ver': '1.0', From fa3b66548b91187c837f7112c87bcbcf29e15917 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Tue, 29 Nov 2022 15:58:40 -0500 Subject: [PATCH 167/367] Revert "fix for broken download bundle https://github.com/prebid/prebid.github.io/issues/4177 (#9289)" (#9298) This reverts commit 5a9aaa8ca5bb47393ddfb08b00d1c4e0af5fd850. --- modules/{kueezrtbBidAdapter.js => kueezRtbBidAdapter.js} | 0 modules/{kueezrtbBidAdapter.md => kueezRtbBidAdapter.md} | 0 .../{kueezrtbBidAdapter_spec.js => kueezRtbBidAdapter_spec.js} | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename modules/{kueezrtbBidAdapter.js => kueezRtbBidAdapter.js} (100%) rename modules/{kueezrtbBidAdapter.md => kueezRtbBidAdapter.md} (100%) rename test/spec/modules/{kueezrtbBidAdapter_spec.js => kueezRtbBidAdapter_spec.js} (99%) diff --git a/modules/kueezrtbBidAdapter.js b/modules/kueezRtbBidAdapter.js similarity index 100% rename from modules/kueezrtbBidAdapter.js rename to modules/kueezRtbBidAdapter.js diff --git a/modules/kueezrtbBidAdapter.md b/modules/kueezRtbBidAdapter.md similarity index 100% rename from modules/kueezrtbBidAdapter.md rename to modules/kueezRtbBidAdapter.md diff --git a/test/spec/modules/kueezrtbBidAdapter_spec.js b/test/spec/modules/kueezRtbBidAdapter_spec.js similarity index 99% rename from test/spec/modules/kueezrtbBidAdapter_spec.js rename to test/spec/modules/kueezRtbBidAdapter_spec.js index 70ece966651..f9b2cd41a43 100644 --- a/test/spec/modules/kueezrtbBidAdapter_spec.js +++ b/test/spec/modules/kueezRtbBidAdapter_spec.js @@ -11,7 +11,7 @@ import { setStorageItem, tryParseJSON, getUniqueDealId, -} from 'modules/kueezrtbBidAdapter.js'; +} from 'modules/kueezRtbBidAdapter.js'; import * as utils from 'src/utils.js'; import {version} from 'package.json'; import {useFakeTimers} from 'sinon'; From 4656aa2af869c7556178e23a7229bf8c21cebd36 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Tue, 29 Nov 2022 16:03:10 -0500 Subject: [PATCH 168/367] Revert "AcuityAds adapter: fix issue with download (#9164)" (#9299) This reverts commit 4f21a5bc9e2e4ace066a4d26ca1c9c637c46a477. --- modules/{acuityadsBidAdapter.js => acuityAdsBidAdapter.js} | 0 modules/{acuityadsBidAdapter.md => acuityAdsBidAdapter.md} | 0 ...{acuityadsBidAdapter_spec.js => acuityAdsBidAdapter_spec.js} | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename modules/{acuityadsBidAdapter.js => acuityAdsBidAdapter.js} (100%) rename modules/{acuityadsBidAdapter.md => acuityAdsBidAdapter.md} (100%) rename test/spec/modules/{acuityadsBidAdapter_spec.js => acuityAdsBidAdapter_spec.js} (99%) diff --git a/modules/acuityadsBidAdapter.js b/modules/acuityAdsBidAdapter.js similarity index 100% rename from modules/acuityadsBidAdapter.js rename to modules/acuityAdsBidAdapter.js diff --git a/modules/acuityadsBidAdapter.md b/modules/acuityAdsBidAdapter.md similarity index 100% rename from modules/acuityadsBidAdapter.md rename to modules/acuityAdsBidAdapter.md diff --git a/test/spec/modules/acuityadsBidAdapter_spec.js b/test/spec/modules/acuityAdsBidAdapter_spec.js similarity index 99% rename from test/spec/modules/acuityadsBidAdapter_spec.js rename to test/spec/modules/acuityAdsBidAdapter_spec.js index 2497b435a19..18ea574c1ce 100644 --- a/test/spec/modules/acuityadsBidAdapter_spec.js +++ b/test/spec/modules/acuityAdsBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from '../../../modules/acuityadsBidAdapter'; +import { spec } from '../../../modules/acuityAdsBidAdapter'; import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js'; import { getUniqueIdentifierStr } from '../../../src/utils.js'; From 4f55dbc8c515378a709d1f7bcc34ba2e2d500542 Mon Sep 17 00:00:00 2001 From: kkho339 <119444562+kkho339@users.noreply.github.com> Date: Tue, 29 Nov 2022 13:52:05 -0800 Subject: [PATCH 169/367] Add new size 192x160 (ID: 622) in Rubicon Adapter (#9297) --- modules/rubiconBidAdapter.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index 254799b995d..bd53e9d5104 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -134,7 +134,8 @@ var sizeMap = { 574: '620x891', 576: '610x877', 578: '980x552', - 580: '505x656' + 580: '505x656', + 622: '192x160' }; _each(sizeMap, (item, key) => sizeMap[item] = key); From de18e7ccab23bfa294f25bb4f691a8aaf6636ae0 Mon Sep 17 00:00:00 2001 From: redtram-tech <84892722+redtram-tech@users.noreply.github.com> Date: Wed, 30 Nov 2022 19:10:51 +0200 Subject: [PATCH 170/367] Redtram Bid Adapter : initial adapter release (#9260) * Add Redtram Bid Adapter * add on bidWon test * extend tests * remove convertOrtbRequestToProprietaryNative 9260#pullrequestreview-1196218534 Co-authored-by: Oleh Naimushyn --- modules/redtramBidAdapter.js | 155 ++++++++++++ modules/redtramBidAdapter.md | 33 +++ test/spec/modules/redtramBidAdapter_spec.js | 256 ++++++++++++++++++++ 3 files changed, 444 insertions(+) create mode 100644 modules/redtramBidAdapter.js create mode 100644 modules/redtramBidAdapter.md create mode 100644 test/spec/modules/redtramBidAdapter_spec.js diff --git a/modules/redtramBidAdapter.js b/modules/redtramBidAdapter.js new file mode 100644 index 00000000000..e1dc0e2a148 --- /dev/null +++ b/modules/redtramBidAdapter.js @@ -0,0 +1,155 @@ +import { + isFn, + isStr, + deepAccess, + getWindowTop, + triggerPixel +} 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 = 'redtram'; +const AD_URL = 'https://prebid.redtram.com/pbjs'; +const SYNC_URL = 'https://prebid.redtram.com/sync'; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || + !bid.ttl || !bid.currency || !bid.meta) { + return false; + } + + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + default: + return false; + } +} + +function getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return deepAccess(bid, 'params.bidFloor', 0); + } + + try { + const bidFloor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (_) { + return 0 + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + + isBidRequestValid: (bid) => { + return Boolean(bid.bidId && bid.params && bid.params.placementId); + }, + + buildRequests: (validBidRequests = [], bidderRequest) => { + const winTop = getWindowTop(); + const location = winTop.location; + const placements = []; + + const request = { + deviceWidth: winTop.screen.width, + deviceHeight: winTop.screen.height, + language: (navigator && navigator.language) ? navigator.language.split('-')[0] : '', + 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++) { + const bid = validBidRequests[i]; + const placement = { + placementId: bid.params.placementId, + bidId: bid.bidId, + schain: bid.schain || {}, + bidfloor: getBidFloor(bid) + }; + + if (typeof bid.userId !== 'undefined') { + placement.userId = bid.userId; + } + + const mediaType = bid.mediaTypes; + + if (mediaType && mediaType[BANNER] && mediaType[BANNER].sizes) { + placement.sizes = mediaType[BANNER].sizes; + placement.adFormat = BANNER; + } + + placements.push(placement); + } + + 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)) { + const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : []; + resItem.meta = { ...resItem.meta, advertiserDomains }; + + response.push(resItem); + } + } + return response; + }, + + getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { + let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image'; + let syncUrl = SYNC_URL + `/${syncType}?pbjs=1`; + if (gdprConsent && gdprConsent.consentString) { + if (typeof gdprConsent.gdprApplies === 'boolean') { + syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + syncUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`; + } + } + if (uspConsent && uspConsent.consentString) { + syncUrl += `&ccpa_consent=${uspConsent.consentString}`; + } + + const coppa = config.getConfig('coppa') ? 1 : 0; + syncUrl += `&coppa=${coppa}`; + + return [{ + type: syncType, + url: syncUrl + }]; + }, + + onBidWon: (bid) => { + const cpm = deepAccess(bid, 'adserverTargeting.hb_pb') || ''; + if (isStr(bid.nurl) && bid.nurl !== '') { + bid.nurl = bid.nurl.replace(/\${AUCTION_PRICE}/, cpm); + triggerPixel(bid.nurl); + } + } +}; + +registerBidder(spec); diff --git a/modules/redtramBidAdapter.md b/modules/redtramBidAdapter.md new file mode 100644 index 00000000000..39115502aa7 --- /dev/null +++ b/modules/redtramBidAdapter.md @@ -0,0 +1,33 @@ +# Overview + +``` +Module Name: redtram Bidder Adapter +Module Type: redtram Bidder Adapter +Maintainer: support@redtram.com +``` + +# Description + +Module that connects to redtram demand sources + +# Test Parameters +``` + var adUnits = [ + { + code: 'div-prebid', + mediaTypes:{ + banner: { + sizes: [[300, 250]], + } + }, + bids:[ + { + bidder: 'redtram', + params: { + placementId: '23611' //test, please replace after test + } + } + ] + }, + ]; +``` \ No newline at end of file diff --git a/test/spec/modules/redtramBidAdapter_spec.js b/test/spec/modules/redtramBidAdapter_spec.js new file mode 100644 index 00000000000..e136c37962b --- /dev/null +++ b/test/spec/modules/redtramBidAdapter_spec.js @@ -0,0 +1,256 @@ +import {expect} from 'chai'; +import {spec} from '../../../modules/redtramBidAdapter.js'; +import { BANNER } from '../../../src/mediaTypes.js'; +import * as utils from '../../../src/utils.js'; + +describe('RedtramBidAdapter', function () { + const bid = { + bidId: '23dc19818e5293', + bidder: 'redtram', + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + placementId: 23611, + } + }; + + const bidderRequest = { + refererInfo: { + referer: 'test.com' + } + }; + + describe('isBidRequestValid', function () { + it('Should return true if there are bidId, params and key 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://prebid.redtram.com/pbjs'); + }); + 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', '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.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', 'adFormat', 'sizes', 'schain', 'bidfloor'); + expect(placement.placementId).to.equal(23611); + expect(placement.bidId).to.equal('23dc19818e5293'); + expect(placement.adFormat).to.equal(BANNER); + expect(placement.schain).to.be.an('object'); + expect(placement.sizes).to.be.an('array'); + expect(placement.bidfloor).to.exist.and.to.equal(0); + }); + + 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: '23dc19818e5293', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: {} + }] + }; + 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', 'meta'); + expect(dataItem.requestId).to.equal('23dc19818e5293'); + 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'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should return an empty array if invalid banner response is passed', function () { + const invBanner = { + body: [{ + width: 300, + cpm: 0.4, + ad: 'Test', + requestId: '23dc19818e5293', + 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 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 () { + it('should do nothing on getUserSyncs', function () { + const syncData = spec.getUserSyncs({}, {}, { + consentString: 'ALL', + gdprApplies: true + }, {}); + expect(syncData).to.be.an('array').which.is.not.empty; + expect(syncData[0]).to.be.an('object') + expect(syncData[0].type).to.be.a('string') + expect(syncData[0].type).to.equal('image') + expect(syncData[0].url).to.be.a('string') + expect(syncData[0].url).to.equal('https://prebid.redtram.com/sync/image?pbjs=1&gdpr=1&gdpr_consent=ALL&coppa=0') + }); + }); + + describe('on bidWon', function () { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + it('should replace nurl for banner', function () { + const nurl = 'nurl/?ap=${' + 'AUCTION_PRICE}'; + const bid = { + 'bidderCode': 'redtram', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '5691dd18ba6ab6', + 'requestId': '23dc19818e5293', + 'transactionId': '948c716b-bf64-4303-bcf4-395c2f6a9770', + 'auctionId': 'a6b7c61f-15a9-481b-8f64-e859787e9c07', + 'mediaType': 'banner', + 'source': 'client', + 'ad': "
\n", + 'cpm': 0.68, + 'nurl': nurl, + 'creativeId': 'test', + 'currency': 'USD', + 'dealId': '', + 'meta': { + 'advertiserDomains': [], + 'dchain': { + 'ver': '1.0', + 'complete': 0, + 'nodes': [ + { + 'name': 'redtram' + } + ] + } + }, + 'netRevenue': true, + 'ttl': 120, + 'metrics': {}, + 'adapterCode': 'redtram', + 'originalCpm': 0.68, + 'originalCurrency': 'USD', + 'responseTimestamp': 1668162732297, + 'requestTimestamp': 1668162732292, + 'bidder': 'redtram', + 'adUnitCode': 'div-prebid', + 'timeToRespond': 5, + 'pbLg': '0.50', + 'pbMg': '0.60', + 'pbHg': '0.68', + 'pbAg': '0.65', + 'pbDg': '0.68', + 'pbCg': '', + 'size': '300x250', + 'adserverTargeting': { + 'hb_bidder': 'redtram', + 'hb_adid': '5691dd18ba6ab6', + 'hb_pb': '0.68', + 'hb_size': '300x250', + 'hb_source': 'client', + 'hb_format': 'banner', + 'hb_adomain': '' + }, + 'status': 'rendered', + 'params': [ + { + 'placementId': 23611 + } + ] + }; + spec.onBidWon(bid); + expect(bid.nurl).to.deep.equal('nurl/?ap=0.68'); + }); + }); +}); From 5b13b541ff40cd704e81f630288a89585461fcb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udi=20Talias=20=E2=9A=9B=EF=B8=8F?= Date: Wed, 30 Nov 2022 19:11:23 +0200 Subject: [PATCH 171/367] VidazooBidAdapter: sending storageAllowed flag with request params (#9294) * feat(module): multi size request * fix getUserSyncs added tests * update(module): package-lock.json from master * feat(module): VidazooBidAdapter - send top query params to server * added bid params to request Co-authored-by: roman Co-authored-by: Saar Amrani <89377180+saar120@users.noreply.github.com> Co-authored-by: Saar Amrani --- modules/vidazooBidAdapter.js | 3 +++ test/spec/modules/vidazooBidAdapter_spec.js | 1 + 2 files changed, 4 insertions(+) diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index 39c407ae8a6..e79835b39c0 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -2,6 +2,7 @@ import { _each, deepAccess, parseSizesInput, parseUrl, uniques, isFn } from '../ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { getStorageManager } from '../src/storageManager.js'; +import { bidderSettings } from '../src/bidderSettings.js'; const GVLID = 744; const DEFAULT_SUB_DOMAIN = 'prebid'; @@ -69,6 +70,7 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { const pId = extractPID(params); const subDomain = extractSubDomain(params); const ptrace = getCacheOpt(); + const isStorageAllowed = bidderSettings.get(BIDDER_CODE, 'storageAllowed'); const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid', deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', '')); const cat = deepAccess(bidderRequest, 'ortb2.site.cat', []); @@ -104,6 +106,7 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { res: `${screen.width}x${screen.height}`, schain: schain, ptrace: ptrace, + isStorageAllowed: isStorageAllowed, gpid: gpid, cat: cat, pagecat: pagecat diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index 7c7f27a830b..9c22b41968f 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -198,6 +198,7 @@ describe('VidazooBidAdapter', function () { uqs: getTopWindowQueryParams(), 'ext.param1': 'loremipsum', 'ext.param2': 'dolorsitamet', + isStorageAllowed: true, gpid: '1234567890', cat: ['IAB2'], pagecat: ['IAB2-2'] From 164e374b030f6f8f110ca22f419dccabf8170b1a Mon Sep 17 00:00:00 2001 From: Patrick Loughrey Date: Wed, 30 Nov 2022 12:13:54 -0500 Subject: [PATCH 172/367] Triplelift Adapter: Update referrer logic (#9304) * prioritize topmostlocation * adds test for topmostlocation / referrer * cleanup * delete param after test * TL-32803: Update referrer logic * TL-32803: Update referrer logic Co-authored-by: Nick Llerandi Co-authored-by: nllerandi3lift <75995508+nllerandi3lift@users.noreply.github.com> --- modules/tripleliftBidAdapter.js | 2 +- test/spec/modules/tripleliftBidAdapter_spec.js | 13 +++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/modules/tripleliftBidAdapter.js b/modules/tripleliftBidAdapter.js index 3fdabcfa6d2..7f6ec90c7b9 100644 --- a/modules/tripleliftBidAdapter.js +++ b/modules/tripleliftBidAdapter.js @@ -29,7 +29,7 @@ export const tripleliftAdapterSpec = { tlCall = tryAppendQueryString(tlCall, 'v', '$prebid.version$'); if (bidderRequest && bidderRequest.refererInfo) { - let referrer = bidderRequest?.refererInfo?.topmostLocation || bidderRequest?.refererInfo?.page; + let referrer = bidderRequest.refererInfo.page; tlCall = tryAppendQueryString(tlCall, 'referrer', referrer); } diff --git a/test/spec/modules/tripleliftBidAdapter_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js index 4cab8be7e09..5cfa64184f9 100644 --- a/test/spec/modules/tripleliftBidAdapter_spec.js +++ b/test/spec/modules/tripleliftBidAdapter_spec.js @@ -979,19 +979,12 @@ describe('triplelift adapter', function () { expect(url).to.match(new RegExp('(?:' + prebid.version + ')')) expect(url).to.match(/(?:referrer)/); }); - it('should prioritize topmostLocation for referrer', function () { - bidderRequest.refererInfo.topmostLocation = 'https://topmostlocation.com?foo=bar' + it('should use refererInfo.page for referrer', function () { + bidderRequest.refererInfo.page = 'https://topmostlocation.com?foo=bar' const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); const url = request.url; expect(url).to.match(/(\?|&)referrer=https%3A%2F%2Ftopmostlocation.com%3Ffoo%3Dbar/); - delete bidderRequest.refererInfo.topmostLocation - }); - it('should fall back to page for referrer if topmostLocation is unavailable', function () { - bidderRequest.refererInfo.topmostLocation = null - const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); - const url = request.url; - expect(url).to.match(/(\?|&)referrer=https%3A%2F%2Fexamplereferer.com/); - delete bidderRequest.refererInfo.topmostLocation + delete bidderRequest.refererInfo.page }); it('should return us_privacy param when CCPA info is available', function() { bidderRequest.uspConsent = '1YYY'; From f8976951c1a2f3384c4c6a7cfb04c622017d13e4 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Wed, 30 Nov 2022 18:00:41 +0000 Subject: [PATCH 173/367] Prebid 7.27.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2ed7cf9067e..15582191fc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.27.0-pre", + "version": "7.27.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index d243b650b6d..142dd2d1cdf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.27.0-pre", + "version": "7.27.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 1b4a5a356e74b6c0891e0e4d356f83b1be755d79 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Wed, 30 Nov 2022 18:00:42 +0000 Subject: [PATCH 174/367] Increment version to 7.28.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 15582191fc2..8f5fd96e92a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.27.0", + "version": "7.28.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 142dd2d1cdf..bf52a74513a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.27.0", + "version": "7.28.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 0c71ee25e701b61c8c0e69fda282649350700f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ricardo=20Gielow?= Date: Wed, 30 Nov 2022 14:35:55 -0500 Subject: [PATCH 175/367] ttd Bid Adapter: add regression test topmost domain (#9300) * TTD Adapter use topmost location when available * TTD add use top most location regression test Co-authored-by: Andre Gielow --- test/helpers/refererDetectionHelper.js | 88 ++++++++++++++++++++++++ test/spec/modules/ttdBidAdapter_spec.js | 45 ++++++++++--- test/spec/refererDetection_spec.js | 89 +------------------------ 3 files changed, 125 insertions(+), 97 deletions(-) create mode 100644 test/helpers/refererDetectionHelper.js diff --git a/test/helpers/refererDetectionHelper.js b/test/helpers/refererDetectionHelper.js new file mode 100644 index 00000000000..bdbfb205cdb --- /dev/null +++ b/test/helpers/refererDetectionHelper.js @@ -0,0 +1,88 @@ +/** + * Build a walkable linked list of window-like objects for testing. + * + * @param {Array} urls Array of URL strings starting from the top window. + * @param {string} [topReferrer] + * @param {string} [canonicalUrl] + * @param {boolean} [ancestorOrigins] + * @returns {Object} + */ +export function buildWindowTree(urls, topReferrer = null, canonicalUrl = null, ancestorOrigins = false) { + /** + * Find the origin from a given fully-qualified URL. + * + * @param {string} url The fully qualified URL + * @returns {string|null} + */ + function getOrigin(url) { + const originRegex = new RegExp('^(https?://[^/]+/?)'); + + const result = originRegex.exec(url); + + if (result && result[0]) { + return result[0]; + } + + return null; + } + + const inaccessibles = []; + + let previousWindow, topWindow; + const topOrigin = getOrigin(urls[0]); + + const windowList = urls.map((url, index) => { + const thisOrigin = getOrigin(url), + sameOriginAsPrevious = index === 0 ? true : (getOrigin(urls[index - 1]) === thisOrigin), + sameOriginAsTop = thisOrigin === topOrigin; + + const win = { + location: { + href: url, + }, + document: { + referrer: index === 0 ? topReferrer : urls[index - 1] + } + }; + + if (topWindow == null) { + topWindow = win; + win.document.querySelector = function (selector) { + if (selector === 'link[rel=\'canonical\']') { + return { + href: canonicalUrl + }; + } + return null; + }; + } + + if (sameOriginAsPrevious) { + win.parent = previousWindow; + } else { + win.parent = inaccessibles[inaccessibles.length - 1]; + } + if (ancestorOrigins) { + win.location.ancestorOrigins = urls.slice(0, index).reverse().map(getOrigin); + } + win.top = sameOriginAsTop ? topWindow : inaccessibles[0]; + + const inWin = {parent: inaccessibles[inaccessibles.length - 1], top: inaccessibles[0]}; + if (index === 0) { + inWin.top = inWin; + } + ['document', 'location'].forEach((prop) => { + Object.defineProperty(inWin, prop, { + get: function () { + throw new Error('cross-origin access'); + } + }); + }); + inaccessibles.push(inWin); + previousWindow = win; + + return win; + }); + + return windowList[windowList.length - 1]; +} diff --git a/test/spec/modules/ttdBidAdapter_spec.js b/test/spec/modules/ttdBidAdapter_spec.js index f45872faec9..9869d072657 100644 --- a/test/spec/modules/ttdBidAdapter_spec.js +++ b/test/spec/modules/ttdBidAdapter_spec.js @@ -2,6 +2,9 @@ import { expect } from 'chai'; import { spec } from 'modules/ttdBidAdapter'; import { deepClone } from 'src/utils.js'; import { config } from 'src/config'; +import { detectReferer } from 'src/refererDetection.js'; + +import { buildWindowTree } from '../../helpers/refererDetectionHelper'; describe('ttdBidAdapter', function () { function testBuildRequests(bidRequests, bidderRequestBase) { @@ -200,20 +203,15 @@ describe('ttdBidAdapter', function () { 'bidRequestsCount': 1 }]; + const testWindow = buildWindowTree(['https://www.example.com/test', 'https://www.example.com/other/page', 'https://www.example.com/third/page'], 'https://othersite.com/', 'https://example.com/canonical/page'); + const baseBidderRequestReferer = detectReferer(testWindow)(); const baseBidderRequest = { 'bidderCode': 'ttd', 'auctionId': 'e7b34fa3-8654-424e-8c49-03e509e53d8c', 'bidderRequestId': '18084284054531', 'auctionStart': 1540945362095, 'timeout': 3000, - 'refererInfo': { - 'page': 'https://www.example.com/test', - 'reachedTop': true, - 'numIframes': 0, - 'stack': [ - 'https://www.example.com/test' - ] - }, + 'refererInfo': baseBidderRequestReferer, 'start': 1540945362099, 'doneCbCallCount': 0 }; @@ -291,6 +289,11 @@ describe('ttdBidAdapter', function () { expect(requestBody.site.page).to.equal('https://www.example.com/test'); }); + it('ensure top most location is used', function () { + const requestBody = testBuildRequests(baseBannerBidRequests, baseBidderRequest).data; + expect(requestBody.site.page).to.equal('https://www.example.com/test'); + }); + it('sets the banner pos correctly if sent', function () { let clonedBannerRequests = deepClone(baseBannerBidRequests); clonedBannerRequests[0].mediaTypes.banner.pos = 1; @@ -318,11 +321,35 @@ describe('ttdBidAdapter', function () { } } }; - const requestBody = testBuildRequests(baseBannerBidRequests, {...baseBidderRequest, ortb2}).data; + const baseBidderRequestWithoutRefererDomain = { + ...baseBidderRequest, + refererInfo: { + ...baseBannerBidRequests.referer, + domain: null + } + } + const requestBody = testBuildRequests( + baseBannerBidRequests, {...baseBidderRequestWithoutRefererDomain, ortb2} + ).data; config.resetConfig(); expect(requestBody.site.publisher).to.deep.equal({domain: 'https://foo.bar', id: '13144370'}); }); + it('referer domain overrides first party site data publisher domain', function () { + const ortb2 = { + site: { + publisher: { + domain: 'https://foo.bar', + } + } + }; + const requestBody = testBuildRequests( + baseBannerBidRequests, {...baseBidderRequest, ortb2} + ).data; + config.resetConfig(); + expect(requestBody.site.publisher.domain).to.equal(baseBidderRequest.refererInfo.domain); + }); + it('sets keywords properly if sent', function () { const ortb2 = { site: { diff --git a/test/spec/refererDetection_spec.js b/test/spec/refererDetection_spec.js index f8166a27d85..a0ffc3eddbe 100644 --- a/test/spec/refererDetection_spec.js +++ b/test/spec/refererDetection_spec.js @@ -2,94 +2,7 @@ import {detectReferer, ensureProtocol, parseDomain} from 'src/refererDetection.j import {config} from 'src/config.js'; import {expect} from 'chai'; -/** - * Build a walkable linked list of window-like objects for testing. - * - * @param {Array} urls Array of URL strings starting from the top window. - * @param {string} [topReferrer] - * @param {string} [canonicalUrl] - * @param {boolean} [ancestorOrigins] - * @returns {Object} - */ -function buildWindowTree(urls, topReferrer = null, canonicalUrl = null, ancestorOrigins = false) { - /** - * Find the origin from a given fully-qualified URL. - * - * @param {string} url The fully qualified URL - * @returns {string|null} - */ - function getOrigin(url) { - const originRegex = new RegExp('^(https?://[^/]+/?)'); - - const result = originRegex.exec(url); - - if (result && result[0]) { - return result[0]; - } - - return null; - } - - const inaccessibles = []; - - let previousWindow, topWindow; - const topOrigin = getOrigin(urls[0]); - - const windowList = urls.map((url, index) => { - const thisOrigin = getOrigin(url), - sameOriginAsPrevious = index === 0 ? true : (getOrigin(urls[index - 1]) === thisOrigin), - sameOriginAsTop = thisOrigin === topOrigin; - - const win = { - location: { - href: url, - }, - document: { - referrer: index === 0 ? topReferrer : urls[index - 1] - } - }; - - if (topWindow == null) { - topWindow = win; - win.document.querySelector = function (selector) { - if (selector === 'link[rel=\'canonical\']') { - return { - href: canonicalUrl - }; - } - return null; - }; - } - - if (sameOriginAsPrevious) { - win.parent = previousWindow; - } else { - win.parent = inaccessibles[inaccessibles.length - 1]; - } - if (ancestorOrigins) { - win.location.ancestorOrigins = urls.slice(0, index).reverse().map(getOrigin); - } - win.top = sameOriginAsTop ? topWindow : inaccessibles[0]; - - const inWin = {parent: inaccessibles[inaccessibles.length - 1], top: inaccessibles[0]}; - if (index === 0) { - inWin.top = inWin; - } - ['document', 'location'].forEach((prop) => { - Object.defineProperty(inWin, prop, { - get: function () { - throw new Error('cross-origin access'); - } - }); - }); - inaccessibles.push(inWin); - previousWindow = win; - - return win; - }); - - return windowList[windowList.length - 1]; -} +import { buildWindowTree } from '../helpers/refererDetectionHelper'; describe('Referer detection', () => { afterEach(function () { From 0725ba87275d0f88e534a94d8d4e0489b02c2d29 Mon Sep 17 00:00:00 2001 From: Jeremy Sadwith Date: Wed, 30 Nov 2022 17:39:15 -0500 Subject: [PATCH 176/367] Kargo Adapter: Update referrer logic (#9305) * pageURL pull from topmostLocation * Kargo: Support for client hints (#9) * Starting SUA support * Kargo: Adding support for client hints * Adding tests for sua * Kargo: Update referer logic --- modules/kargoBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index 15d706c0410..2c33c3f61d1 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -231,7 +231,7 @@ export const spec = { _getAllMetadata(bidderRequest, tdid) { return { userIDs: spec._getUserIds(tdid, bidderRequest.uspConsent, bidderRequest.gdprConsent), - pageURL: bidderRequest?.refererInfo?.topmostLocation || bidderRequest?.refererInfo?.page, + pageURL: bidderRequest?.refererInfo?.page, rawCRB: storage.getCookie('krg_crb'), rawCRBLocalStorage: spec._getLocalStorageSafely('krg_crb') }; From b95f26e523b6ec252aa05c0cb0f820a4c13bb903 Mon Sep 17 00:00:00 2001 From: BaronJHYu <254878848@qq.com> Date: Thu, 1 Dec 2022 23:44:47 +0800 Subject: [PATCH 177/367] Discovery Bid Adapter & Mediago Bid Adapter: add support for test request param (#9302) * Mediago Bid Adapter:new adapter * remove console * change spec file to fix CircleCI * change spec file to fix CircleCI * change spec file * Update mediagoBidAdapter.js * Update mediagoBidAdapter.js * rerun CurcleCi * update mediagoBidAdapter * update discoveryBidAdapter * Discovery Bid Adapter : parameter updates * Mediago Bid Adapter : parameter updates * Mediago Bid Adapter : code style format * rerun circleci * rerun circleci * rerun circleci * rerun circleci Co-authored-by: BaronYu --- modules/discoveryBidAdapter.js | 3 +++ modules/mediagoBidAdapter.js | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/discoveryBidAdapter.js b/modules/discoveryBidAdapter.js index fab3920efcc..0c536892716 100644 --- a/modules/discoveryBidAdapter.js +++ b/modules/discoveryBidAdapter.js @@ -277,6 +277,8 @@ function getItems(validBidRequests, bidderRequest) { function getParam(validBidRequests, bidderRequest) { const pubcid = utils.deepAccess(validBidRequests[0], 'crumbs.pubcid'); let isMobile = getDevice() ? 1 : 0; + // input test status by Publisher. more frequently for test true req + let isTest = validBidRequests[0].params.test || 0; let auctionId = getKv(bidderRequest, 'auctionId'); let items = getItems(validBidRequests, bidderRequest); @@ -290,6 +292,7 @@ function getParam(validBidRequests, bidderRequest) { if (items && items.length) { let c = { id: 'pp_hbjs_' + auctionId, + test: +isTest, at: 1, bcat: globals['bcat'], badv: globals['adv'], diff --git a/modules/mediagoBidAdapter.js b/modules/mediagoBidAdapter.js index 514c56061df..16460b195f5 100644 --- a/modules/mediagoBidAdapter.js +++ b/modules/mediagoBidAdapter.js @@ -297,7 +297,8 @@ function getParam(validBidRequests, bidderRequest) { utils.deepAccess(validBidRequests[0], 'userId.sharedid.id') || utils.deepAccess(validBidRequests[0], 'userId.pubcid'); let isMobile = isMobileAndTablet() ? 1 : 0; - let isTest = 0; + // input test status by Publisher. more frequently for test true req + let isTest = validBidRequests[0].params.test || 0; let auctionId = getProperty(bidderRequest, 'auctionId'); let items = getItems(validBidRequests, bidderRequest); From 6b61f97333c24845a4ba187ae5d9c6c8d9b6774c Mon Sep 17 00:00:00 2001 From: Marcin Wrobel Date: Thu, 1 Dec 2022 18:14:38 +0100 Subject: [PATCH 178/367] OpenX Bid Adapter: update documentation about deprecated platform and hint for using floor module (#9308) --- modules/openxBidAdapter.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/modules/openxBidAdapter.md b/modules/openxBidAdapter.md index 28dba424fb2..5ce5a786f7b 100644 --- a/modules/openxBidAdapter.md +++ b/modules/openxBidAdapter.md @@ -15,14 +15,15 @@ Publishers are welcome to test the other adapter and give feedback. Please note # Bid Parameters ## Banner -| Name | Scope | Type | Description | Example -| ---- | ----- | ---- | ----------- | ------- -| `delDomain` or `platform` | required | String | OpenX delivery domain or platform id provided by your OpenX representative. | "PUBLISHER-d.openx.net" or "555not5a-real-plat-form-id0123456789" -| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" -| `customParams` | optional | Object | User-defined targeting key-value pairs. customParams applies to a specific unit. | `{key1: "v1", key2: ["v2","v3"]}` -| `customFloor` | optional | Number | Minimum price in USD. customFloor applies to a specific unit. For example, use the following value to set a $1.50 floor: 1.50

**WARNING:**
Misuse of this parameter can impact revenue | 1.50 -| `doNotTrack` | optional | Boolean | Prevents advertiser from using data for this user.

**WARNING:**
Request-level setting. May impact revenue. | true -| `coppa` | optional | Boolean | Enables Child's Online Privacy Protection Act (COPPA) regulations. | true +| Name | Scope | Type | Description | Example +|---------------------------------| ----- | ---- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------- +| `delDomain` ~~or `platform`~~** | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" +| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" +| `customParams` | optional | Object | User-defined targeting key-value pairs. customParams applies to a specific unit. | `{key1: "v1", key2: ["v2","v3"]}` +| `customFloor` | optional | Number | Minimum price in USD. customFloor applies to a specific unit. For example, use the following value to set a $1.50 floor: 1.50

**WARNING:**
Misuse of this parameter can impact revenue

Note: OpenX suggests using the [Price Floor Module](https://docs.prebid.org/dev-docs/modules/floors.html) instead of customFloor. The Price Floor Module will be prioritized over customFloor if both are present. | 1.50 +| `doNotTrack` | optional | Boolean | Prevents advertiser from using data for this user.

**WARNING:**
Request-level setting. May impact revenue. | true +| `coppa` | optional | Boolean | Enables Child's Online Privacy Protection Act (COPPA) regulations. | true +** platform is deprecated. Please use delDomain instead. If you have any questions please contact your representative. ## Video From 8894d1cd1a55076f2c8feae621fb3f5ad7d2e97b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 22:22:08 -0500 Subject: [PATCH 179/367] Bump decode-uri-component from 0.2.0 to 0.2.2 (#9311) Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2. - [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases) - [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2) --- updated-dependencies: - dependency-name: decode-uri-component dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8f5fd96e92a..f0b0b45a844 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.27.0-pre", + "version": "7.28.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -7986,9 +7986,9 @@ } }, "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, "engines": { "node": ">=0.10" @@ -31388,9 +31388,9 @@ } }, "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true }, "decompress-response": { From a4b4f7be8eb8d52764a32793cc0ef3eeae11d8c9 Mon Sep 17 00:00:00 2001 From: Marcin Wrobel Date: Fri, 2 Dec 2022 04:23:03 +0100 Subject: [PATCH 180/367] OpenX Bid Adapter: fix bid parameters table in documentation (#9310) --- modules/openxBidAdapter.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/openxBidAdapter.md b/modules/openxBidAdapter.md index 5ce5a786f7b..0690bf6b4fc 100644 --- a/modules/openxBidAdapter.md +++ b/modules/openxBidAdapter.md @@ -15,24 +15,24 @@ Publishers are welcome to test the other adapter and give feedback. Please note # Bid Parameters ## Banner -| Name | Scope | Type | Description | Example -|---------------------------------| ----- | ---- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------- -| `delDomain` ~~or `platform`~~** | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" -| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" -| `customParams` | optional | Object | User-defined targeting key-value pairs. customParams applies to a specific unit. | `{key1: "v1", key2: ["v2","v3"]}` -| `customFloor` | optional | Number | Minimum price in USD. customFloor applies to a specific unit. For example, use the following value to set a $1.50 floor: 1.50

**WARNING:**
Misuse of this parameter can impact revenue

Note: OpenX suggests using the [Price Floor Module](https://docs.prebid.org/dev-docs/modules/floors.html) instead of customFloor. The Price Floor Module will be prioritized over customFloor if both are present. | 1.50 -| `doNotTrack` | optional | Boolean | Prevents advertiser from using data for this user.

**WARNING:**
Request-level setting. May impact revenue. | true -| `coppa` | optional | Boolean | Enables Child's Online Privacy Protection Act (COPPA) regulations. | true +| Name | Scope | Type | Description | Example | +|---------------------------------|----------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------| +| `delDomain` ~~or `platform`~~** | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" | +| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" | +| `customParams` | optional | Object | User-defined targeting key-value pairs. customParams applies to a specific unit. | `{key1: "v1", key2: ["v2","v3"]}` | +| `customFloor` | optional | Number | Minimum price in USD. customFloor applies to a specific unit. For example, use the following value to set a $1.50 floor: 1.50

**WARNING:**
Misuse of this parameter can impact revenue

Note: OpenX suggests using the [Price Floor Module](https://docs.prebid.org/dev-docs/modules/floors.html) instead of customFloor. The Price Floor Module is prioritized over customFloor if both are present. | 1.50 | +| `doNotTrack` | optional | Boolean | Prevents advertiser from using data for this user.

**WARNING:**
Request-level setting. May impact revenue. | true | +| `coppa` | optional | Boolean | Enables Child's Online Privacy Protection Act (COPPA) regulations. | true | + ** platform is deprecated. Please use delDomain instead. If you have any questions please contact your representative. ## Video -| Name | Scope | Type | Description | Example -| ---- | ----- | ---- | ----------- | ------- -| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" -| `delDomain` | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" -| `openrtb` | optional | OpenRTB Impression | An OpenRtb Impression with Video subtype properties | `{ imp: [{ video: {mimes: ['video/x-ms-wmv, video/mp4']} }] }` - +| Name | Scope | Type | Description | Example | +|-------------|----------|--------------------|--------------------------------------------------------------|----------------------------------------------------------------| +| `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" | +| `delDomain` | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" | +| `openrtb` | optional | OpenRTB Impression | An OpenRtb Impression with Video subtype properties | `{ imp: [{ video: {mimes: ['video/x-ms-wmv, video/mp4']} }] }` | # Example ```javascript From a0cc68db28632f8bcc5e695105b697dcc6128e99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Dec 2022 07:27:35 -0700 Subject: [PATCH 181/367] Bump tibdex/github-app-token from 1.6.0 to 1.7.0 (#9316) Bumps [tibdex/github-app-token](https://github.com/tibdex/github-app-token) from 1.6.0 to 1.7.0. - [Release notes](https://github.com/tibdex/github-app-token/releases) - [Commits](https://github.com/tibdex/github-app-token/compare/f717b5ecd4534d3c4df4ce9b5c1c2214f0f7cd06...021a2405c7f990db57f5eae5397423dcc554159c) --- updated-dependencies: - dependency-name: tibdex/github-app-token dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/issue_tracker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issue_tracker.yml b/.github/workflows/issue_tracker.yml index 05d08b2b0d7..4a9502e38c1 100644 --- a/.github/workflows/issue_tracker.yml +++ b/.github/workflows/issue_tracker.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Generate token id: generate_token - uses: tibdex/github-app-token@f717b5ecd4534d3c4df4ce9b5c1c2214f0f7cd06 + uses: tibdex/github-app-token@021a2405c7f990db57f5eae5397423dcc554159c with: app_id: ${{ secrets.ISSUE_APP_ID }} private_key: ${{ secrets.ISSUE_APP_PEM }} From 1c63ed92a1435244a2fd08fa491ba22c636165ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udi=20Talias=20=E2=9A=9B=EF=B8=8F?= Date: Tue, 6 Dec 2022 18:06:14 +0200 Subject: [PATCH 182/367] Vidazoo Bid Adapter: support for Video MediaTypes (#9284) * feat(module): multi size request * fix getUserSyncs added tests * update(module): package-lock.json from master * feat(client): added VIDEO media type * feat(client): send mediaTypes to the server * feat(client): added vastXml support * fix(client): vidazoo adapter tests * fix tests * remove console.log from test file * added video tests Co-authored-by: roman --- modules/vidazooBidAdapter.js | 27 +++- test/spec/modules/vidazooBidAdapter_spec.js | 136 +++++++++++++++++++- 2 files changed, 153 insertions(+), 10 deletions(-) diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index e79835b39c0..bb3e4abd838 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -1,6 +1,6 @@ import { _each, deepAccess, parseSizesInput, parseUrl, uniques, isFn } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER } from '../src/mediaTypes.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { getStorageManager } from '../src/storageManager.js'; import { bidderSettings } from '../src/bidderSettings.js'; @@ -59,7 +59,7 @@ function isBidRequestValid(bid) { } function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { - const { params, bidId, userId, adUnitCode, schain } = bid; + const { params, bidId, userId, adUnitCode, schain, mediaTypes } = bid; const { ext } = params; let { bidFloor } = params; const hashUrl = hashCode(topWindowUrl); @@ -105,6 +105,7 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { prebidVersion: '$prebid.version$', res: `${screen.width}x${screen.height}`, schain: schain, + mediaTypes: mediaTypes, ptrace: ptrace, isStorageAllowed: isStorageAllowed, gpid: gpid, @@ -188,11 +189,12 @@ function interpretResponse(serverResponse, request) { try { results.forEach(result => { - const { creativeId, ad, price, exp, width, height, currency, advertiserDomains } = result; + const { creativeId, ad, price, exp, width, height, currency, advertiserDomains, mediaType = BANNER } = result; if (!ad || !price) { return; } - output.push({ + + const response = { requestId: bidId, cpm: price, width: width, @@ -201,11 +203,22 @@ function interpretResponse(serverResponse, request) { currency: currency || CURRENCY, netRevenue: true, ttl: exp || TTL_SECONDS, - ad: ad, meta: { advertiserDomains: advertiserDomains || [] } - }) + }; + + if (mediaType === BANNER) { + Object.assign(response, { + ad: ad, + }); + } else { + Object.assign(response, { + vastXml: ad, + mediaType: VIDEO + }); + } + output.push(response); }); return output; } catch (e) { @@ -322,7 +335,7 @@ export const spec = { code: BIDDER_CODE, version: BIDDER_VERSION, gvlid: GVLID, - supportedMediaTypes: [BANNER], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid, buildRequests, interpretResponse, diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index 9c22b41968f..40aa7641330 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -17,6 +17,7 @@ import { import * as utils from 'src/utils.js'; import { version } from 'package.json'; import { useFakeTimers } from 'sinon'; +import { BANNER, VIDEO } from '../../../src/mediaTypes'; const SUB_DOMAIN = 'openrtb'; @@ -39,6 +40,7 @@ const BID = { 'bidderRequestId': '1fdb5ff1b6eaa7', 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'mediaTypes': [BANNER], 'ortb2Imp': { 'ext': { 'gpid': '1234567890' @@ -46,6 +48,38 @@ const BID = { } }; +const VIDEO_BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560', + 'bidderRequestId': '12a8ae9ada9c13', + 'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee', + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '635509f7ff6642d368cb9837', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1 + }, + 'sizes': [[545, 307]], + 'mediaTypes': { + 'video': { + 'playerSize': [[545, 307]], + 'context': 'instream', + 'mimes': [ + 'video/mp4', + 'application/javascript' + ], + 'protocols': [2, 3, 5, 6], + 'maxduration': 60, + 'minduration': 0, + 'startdelay': 0, + 'linearity': 1, + 'api': [2], + 'placement': 1 + } + } +} + const BIDDER_REQUEST = { 'gdprConsent': { 'consentString': 'consent_string', @@ -86,6 +120,23 @@ const SERVER_RESPONSE = { } }; +const VIDEO_SERVER_RESPONSE = { + body: { + 'cid': '635509f7ff6642d368cb9837', + 'results': [{ + 'ad': '', + 'advertiserDomains': ['vidazoo.com'], + 'exp': 60, + 'width': 545, + 'height': 307, + 'mediaType': 'video', + 'creativeId': '12610997325162499419', + 'price': 2, + 'cookies': [] + }] + } +} + const REQUEST = { data: { width: 300, @@ -124,6 +175,11 @@ describe('VidazooBidAdapter', function () { it('exists and is a string', function () { expect(adapter.code).to.exist.and.to.be.a('string'); }); + + it('exists and contains media types', function () { + expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2); + expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]); + }); }); describe('validate bid requests', function () { @@ -168,7 +224,59 @@ describe('VidazooBidAdapter', function () { sandbox.stub(Date, 'now').returns(1000); }); - it('should build request for each size', function () { + it('should build video request', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`, + data: { + adUnitCode: '63550ad1ff6642d368cba59dh5884270560', + bidFloor: 0.1, + bidId: '2d52001cabd527', + bidderVersion: adapter.version, + cat: ['IAB2'], + pagecat: ['IAB2-2'], + cb: 1000, + dealId: 1, + gdpr: 1, + gdprConsent: 'consent_string', + usPrivacy: 'consent_string', + gpid: '', + prebidVersion: version, + ptrace: '1000', + publisherId: '59ac17c192832d0011283fe3', + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + res: `${window.top.screen.width}x${window.top.screen.height}`, + schain: VIDEO_BID.schain, + sessionId: '', + sizes: ['545x307'], + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + uqs: getTopWindowQueryParams(), + mediaTypes: { + video: { + api: [2], + context: 'instream', + linearity: 1, + maxduration: 60, + mimes: [ + 'video/mp4', + 'application/javascript' + ], + minduration: 0, + placement: 1, + playerSize: [[545, 307]], + protocols: [2, 3, 5, 6], + startdelay: 0 + } + } + } + }); + }); + + it('should build banner request for each size', function () { const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); const requests = adapter.buildRequests([BID], BIDDER_REQUEST); expect(requests).to.have.length(1); @@ -187,7 +295,7 @@ describe('VidazooBidAdapter', function () { bidId: '2d52001cabd527', adUnitCode: 'div-gpt-ad-12345-0', publisherId: '59ac17c192832d0011283fe3', - dealId: 1, + dealId: 2, sessionId: '', uniqueDealId: `${hashUrl}_${Date.now().toString()}`, bidderVersion: adapter.version, @@ -195,6 +303,7 @@ describe('VidazooBidAdapter', function () { schain: BID.schain, ptrace: '1000', res: `${window.top.screen.width}x${window.top.screen.height}`, + mediaTypes: [BANNER], uqs: getTopWindowQueryParams(), 'ext.param1': 'loremipsum', 'ext.param2': 'dolorsitamet', @@ -211,6 +320,7 @@ describe('VidazooBidAdapter', function () { sandbox.restore(); }); }); + describe('getUserSyncs', function () { it('should have valid user sync with iframeEnabled', function () { const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); @@ -255,7 +365,7 @@ describe('VidazooBidAdapter', function () { expect(responses).to.be.empty; }); - it('should return an array of interpreted responses', function () { + it('should return an array of interpreted banner responses', function () { const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST); expect(responses).to.have.length(1); expect(responses[0]).to.deep.equal({ @@ -274,6 +384,26 @@ describe('VidazooBidAdapter', function () { }); }); + it('should return an array of interpreted video responses', function () { + const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 2, + width: 545, + height: 307, + mediaType: 'video', + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 60, + vastXml: '', + meta: { + advertiserDomains: ['vidazoo.com'] + } + }); + }); + it('should take default TTL', function () { const serverResponse = utils.deepClone(SERVER_RESPONSE); delete serverResponse.body.results[0].exp; From a0e6e6bec2e14a1e7c0bae4fb0b13913ef70fed1 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 6 Dec 2022 11:37:47 -0700 Subject: [PATCH 183/367] Vidazoo bid adapter: fix failing test (#9318) --- test/spec/modules/vidazooBidAdapter_spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index 40aa7641330..2ddb65469af 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -255,6 +255,7 @@ describe('VidazooBidAdapter', function () { sizes: ['545x307'], uniqueDealId: `${hashUrl}_${Date.now().toString()}`, uqs: getTopWindowQueryParams(), + isStorageAllowed: true, mediaTypes: { video: { api: [2], From 4515eb343d2ff348fc3965d064ebdd63f40a2061 Mon Sep 17 00:00:00 2001 From: Wiem Zine El Abidine Date: Tue, 6 Dec 2022 22:12:55 +0100 Subject: [PATCH 184/367] Live Intent User ID Submodule: Bump live-connect version (#9317) * update with live-connect last change * set globalVarName * not use globalVarName * use live-connect proper version * comment * use yalc version and adjust the initializer * adjust getInitializer * use a proper lc version --- modules/liveIntentIdSystem.js | 3 +-- package-lock.json | 14 +++++++------- package.json | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/modules/liveIntentIdSystem.js b/modules/liveIntentIdSystem.js index 724bf5ece6a..de70b0eaccd 100644 --- a/modules/liveIntentIdSystem.js +++ b/modules/liveIntentIdSystem.js @@ -10,7 +10,6 @@ import { submodule } from '../src/hook.js'; import { LiveConnect } from 'live-connect-js/esm/initializer.js'; import { gdprDataHandler, uspDataHandler } from '../src/adapterManager.js'; import { getStorageManager } from '../src/storageManager.js'; -import { MinimalLiveConnect } from 'live-connect-js/esm/minimal-live-connect.js'; const MODULE_NAME = 'liveIntentId'; export const storage = getStorageManager({gvlid: null, moduleName: MODULE_NAME}); @@ -140,7 +139,7 @@ export const liveIntentIdSubmodule = { this.moduleMode = mode }, getInitializer() { - return this.moduleMode === 'minimal' ? MinimalLiveConnect : LiveConnect + return (liveConnectConfig, storage, calls) => LiveConnect(liveConnectConfig, storage, calls, this.moduleMode) }, /** diff --git a/package-lock.json b/package-lock.json index f0b0b45a844..f73e700aa42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "express": "^4.15.4", "fun-hooks": "^0.9.9", "just-clone": "^1.0.2", - "live-connect-js": "2.4.0" + "live-connect-js": "3.0.1" }, "devDependencies": { "@babel/eslint-parser": "^7.16.5", @@ -16229,9 +16229,9 @@ "dev": true }, "node_modules/live-connect-js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-2.4.0.tgz", - "integrity": "sha512-MSBLKfnXoxH+pqwji/Mf8yZu3VZMq4tnNfwMw7NTWN5a+TBM6f0RWgwui1YMA3nHmMhX/nzxxsso0SkyKcF0fA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-3.0.1.tgz", + "integrity": "sha512-rwB0IQfuKPJM+I96nLyq8Utr3LkQ7Z/iuq/xKlWDckQRJLYyWkk7F7yaavf/VsjazzLK2dpJeXGijoDkK4Vz8g==", "dependencies": { "tiny-hashes": "1.0.1" }, @@ -37868,9 +37868,9 @@ "dev": true }, "live-connect-js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-2.4.0.tgz", - "integrity": "sha512-MSBLKfnXoxH+pqwji/Mf8yZu3VZMq4tnNfwMw7NTWN5a+TBM6f0RWgwui1YMA3nHmMhX/nzxxsso0SkyKcF0fA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-3.0.1.tgz", + "integrity": "sha512-rwB0IQfuKPJM+I96nLyq8Utr3LkQ7Z/iuq/xKlWDckQRJLYyWkk7F7yaavf/VsjazzLK2dpJeXGijoDkK4Vz8g==", "requires": { "tiny-hashes": "1.0.1" } diff --git a/package.json b/package.json index bf52a74513a..7bbe18037b4 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "express": "^4.15.4", "fun-hooks": "^0.9.9", "just-clone": "^1.0.2", - "live-connect-js": "2.4.0" + "live-connect-js": "3.0.1" }, "optionalDependencies": { "fsevents": "^2.3.2" From a247abc624f0acd3a5bc6af9ebb785d8555f0ab2 Mon Sep 17 00:00:00 2001 From: Vic R <103455651+victorlassomarketing@users.noreply.github.com> Date: Wed, 7 Dec 2022 12:16:37 -0800 Subject: [PATCH 185/367] ox update (#9309) --- modules/lassoBidAdapter.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/lassoBidAdapter.js b/modules/lassoBidAdapter.js index da48bc460c7..fafaa4dd9dc 100644 --- a/modules/lassoBidAdapter.js +++ b/modules/lassoBidAdapter.js @@ -54,7 +54,7 @@ export const spec = { return { method: 'GET', - url: getBidRequestUrl(aimXR), + url: getBidRequestUrl(aimXR, bidRequest.params), data: payload, options: { withCredentials: true @@ -113,11 +113,15 @@ export const spec = { supportedMediaTypes: [BANNER] } -function getBidRequestUrl(aimXR) { +function getBidRequestUrl(aimXR, params) { + let path = '/request'; + if (params && params.dtc) { + path = '/dtc-request'; + } if (!aimXR) { - return GET_IUD_URL + ENDPOINT_URL + '/request'; + return GET_IUD_URL + ENDPOINT_URL + path; } - return ENDPOINT_URL + '/request' + return ENDPOINT_URL + path; } function getDeviceData() { From 2a90f5165b19b6a5e8ab01be76b2e19da69f97cc Mon Sep 17 00:00:00 2001 From: Damyan Date: Thu, 8 Dec 2022 10:26:56 +0200 Subject: [PATCH 186/367] AdHash bid adapter: update to support latest version (#9286) * AdHash Bidder Adapter: minor changes We're operating on a com TLD now. Added publisher in URL for easier routing. * Implemented brand safety Implemented brand safety checks * Fix for GDPR consent Removing the extra information as request data becomes too big and is sometimes truncated * Ad fraud prevention formula changed Ad fraud prevention formula changed to support negative values as well as linear distribution of article length * AdHash brand safety additions Adding starts-with and ends-with rules that will help us with languages such as German where a single word can be written in multiple ways depending on the gender and grammatical case. * AdHash brand safety updates Added support for Cyrillic characters. Added support for bidderURL parameter. Fixed score multiplier from 500 to 1000. * AdHash Analytics adapter * Support for recent ads Support for recent ads which gives us the option to do frequency and recency capping. * Fix for timestamp * PUB-222 Added logic for measuring the fill rate (fallbacks) for Prebid impressions * Unit tests for the analytics adapter Added unit tests for the analytics adapter * Removed export causing errors Removed an unneeded export of a const that was causing errors with the analytics adapter * Added globalScript parameter * PUB-227 Support for non-latin and non-cyrillic symbols * GEN-964 - Brand safety now checks the page URL for bad words. No ad is shown if there is at least one match. - Repeating code is optimized and moved to helper function - Multi-language support for brand safety * GEN-1025 Sending the needed ad density data to the bidder * Removing the analytics adaptor * Fix for regexp match * Version change * MINOR Code review changes Co-authored-by: NikolayMGeorgiev Co-authored-by: Ventsislav Saraminev Co-authored-by: Dimitar Kalenderov --- modules/adhashBidAdapter.js | 145 ++++++++++++++++----- modules/adhashBidAdapter.md | 4 +- test/spec/modules/adhashBidAdapter_spec.js | 76 +++++++++-- 3 files changed, 181 insertions(+), 44 deletions(-) diff --git a/modules/adhashBidAdapter.js b/modules/adhashBidAdapter.js index 977d161b214..33a85a81525 100644 --- a/modules/adhashBidAdapter.js +++ b/modules/adhashBidAdapter.js @@ -1,10 +1,12 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {includes} from '../src/polyfill.js'; -import {BANNER} from '../src/mediaTypes.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { includes } from '../src/polyfill.js'; +import { BANNER } from '../src/mediaTypes.js'; -const VERSION = '1.0'; +const VERSION = '3.2'; const BAD_WORD_STEP = 0.1; const BAD_WORD_MIN = 0.2; +const ADHASH_BIDDER_CODE = 'adhash'; /** * Function that checks the page where the ads are being served for brand safety. @@ -54,43 +56,92 @@ function brandSafety(badWords, maxScore) { return positive ? result : -result; }; + /** + * Checks what rule will match in the given array with words + * @param {string} rule rule type (full, partial, starts, ends, regexp) + * @param {string} decodedWord decoded word + * @param {array} wordsToMatch array to find a match + * @returns {object|boolean} matched rule and occurances. If nothing is matched returns false + */ + const wordsMatchedWithRule = function (rule, decodedWord, wordsToMatch) { + if (rule === 'full' && wordsToMatch && wordsToMatch.includes(decodedWord)) { + return { rule, occurances: wordsToMatch.filter(element => element === decodedWord).length }; + } else if (rule === 'partial' && wordsToMatch && wordsToMatch.some(element => element.indexOf(decodedWord) > -1)) { + return { rule, occurances: wordsToMatch.filter(element => element.indexOf(decodedWord) > -1).length }; + } else if (rule === 'starts' && wordsToMatch && wordsToMatch.some(word => word.startsWith(decodedWord))) { + return { rule, occurances: wordsToMatch.filter(element => element.startsWith(decodedWord)).length }; + } else if (rule === 'ends' && wordsToMatch && wordsToMatch.some(word => word.endsWith(decodedWord))) { + return { rule, occurances: wordsToMatch.filter(element => element.endsWith(decodedWord)).length }; + } else if (rule === 'regexp' && wordsToMatch && wordsToMatch.some(element => element.match(new RegExp(decodedWord, 'i')))) { + return { rule, occurances: wordsToMatch.filter(element => element.match(new RegExp(decodedWord, 'i'))).length }; + } + return false; + }; + // Default parameters if the bidder is unable to send some of them badWords = badWords || []; maxScore = parseInt(maxScore) || 10; try { let score = 0; + const decodedUrl = decodeURI(window.top.location.href.substring(window.top.location.origin.length)); + const wordsAndNumbersInUrl = decodedUrl + .replaceAll(/[-,\._/\?=&#%]/g, ' ') + .replaceAll(/\s\s+/g, ' ') + .toLowerCase() + .trim(); const content = window.top.document.body.innerText.toLowerCase(); - const words = content.trim().split(/\s+/).length; + const contentWords = content.trim().split(/\s+/).length; + // \p{L} matches a single unicode code point in the category 'letter'. Matches any kind of letter from any language. + const regexp = new RegExp('[\\p{L}]+', 'gu'); + const words = content.match(regexp); + const wordsInUrl = wordsAndNumbersInUrl.match(regexp); + for (const [word, rule, points] of badWords) { - if (rule === 'full' && new RegExp('\\b' + rot13(word) + '\\b', 'i').test(content)) { - const occurances = content.match(new RegExp('\\b' + rot13(word) + '\\b', 'g')).length; - score += scoreCalculator(points, occurances); - } else if (rule === 'partial' && content.indexOf(rot13(word.toLowerCase())) > -1) { - const occurances = content.match(new RegExp(rot13(word), 'g')).length; - score += scoreCalculator(points, occurances); + const decodedWord = rot13(word.toLowerCase()); + + // Checks the words in the url of the page only for negative words. Don't serve any ad when at least one match is found + if (points > 0) { + const matchedRuleInUrl = wordsMatchedWithRule(rule, decodedWord, wordsInUrl); + if (matchedRuleInUrl.rule) { + return false; + } + } + + // Check if site content's words match any of our brand safety rules + const matchedRule = wordsMatchedWithRule(rule, decodedWord, words); + if (matchedRule.rule === 'full') { + score += scoreCalculator(points, matchedRule.occurances); + } else if (matchedRule.rule === 'partial') { + score += scoreCalculator(points, matchedRule.occurances); + } else if (matchedRule.rule === 'starts') { + score += scoreCalculator(points, matchedRule.occurances); + } else if (matchedRule.rule === 'ends') { + score += scoreCalculator(points, matchedRule.occurances); + } else if (matchedRule.rule === 'regexp') { + score += scoreCalculator(points, matchedRule.occurances); } } - return score < maxScore * words / 500; + return score < (maxScore * contentWords) / 1000; } catch (e) { return true; } } export const spec = { - code: 'adhash', - url: 'https://bidder.adhash.com/rtb?version=' + VERSION + '&prebid=true', + code: ADHASH_BIDDER_CODE, supportedMediaTypes: [ BANNER ], isBidRequestValid: (bid) => { try { - const { publisherId, platformURL } = bid.params; + const { publisherId, platformURL, bidderURL } = bid.params; return ( includes(Object.keys(bid.mediaTypes), BANNER) && typeof publisherId === 'string' && publisherId.length === 42 && typeof platformURL === 'string' && - platformURL.length >= 13 + platformURL.length >= 13 && + (!bidderURL || bidderURL.indexOf('https://') === 0) ); } catch (error) { return false; @@ -98,24 +149,51 @@ export const spec = { }, buildRequests: (validBidRequests, bidderRequest) => { + const storage = getStorageManager({ bidderCode: ADHASH_BIDDER_CODE }); const { gdprConsent } = bidderRequest; - const { url } = spec; const bidRequests = []; - let referrer = ''; - if (bidderRequest && bidderRequest.refererInfo) { - // TODO: is 'page' the right value here? - referrer = bidderRequest.refererInfo.page; - } - for (var i = 0; i < validBidRequests.length; i++) { - var index = Math.floor(Math.random() * validBidRequests[i].sizes.length); - var size = validBidRequests[i].sizes[index].join('x'); + const body = document.body; + const html = document.documentElement; + const pageHeight = Math.max( + body.scrollHeight, + body.offsetHeight, + html.clientHeight, + html.scrollHeight, + html.offsetHeight + ); + const pageWidth = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth); + + for (let i = 0; i < validBidRequests.length; i++) { + const bidderURL = validBidRequests[i].params.bidderURL || 'https://bidder.adhash.com'; + const url = `${bidderURL}/rtb?version=${VERSION}&prebid=true`; + const index = Math.floor(Math.random() * validBidRequests[i].sizes.length); + const size = validBidRequests[i].sizes[index].join('x'); + + let recentAds = []; + if (storage.localStorageIsEnabled()) { + const prefix = validBidRequests[i].params.prefix || 'adHash'; + recentAds = JSON.parse(storage.getDataFromLocalStorage(prefix + 'recentAds') || '[]'); + } + + // Needed for the ad density calculation + var adHeight = validBidRequests[i].sizes[index][1]; + var adWidth = validBidRequests[i].sizes[index][0]; + if (!window.adsCount) { + window.adsCount = 0; + } + if (!window.adsTotalSurface) { + window.adsTotalSurface = 0; + } + window.adsTotalSurface += adHeight * adWidth; + window.adsCount++; + bidRequests.push({ method: 'POST', url: url + '&publisher=' + validBidRequests[i].params.publisherId, bidRequest: validBidRequests[i], data: { timezone: new Date().getTimezoneOffset() / 60, - location: referrer, + location: bidderRequest.refererInfo ? bidderRequest.refererInfo.topmostLocation : '', publisherId: validBidRequests[i].params.publisherId, size: { screenWidth: window.screen.width, @@ -131,10 +209,14 @@ export const spec = { position: validBidRequests[i].adUnitCode }], blockedCreatives: [], - currentTimestamp: new Date().getTime(), - recentAds: [], + currentTimestamp: (new Date().getTime() / 1000) | 0, + recentAds: recentAds, GDPRApplies: gdprConsent ? gdprConsent.gdprApplies : null, - GDPR: gdprConsent ? gdprConsent.consentString : null + GDPR: gdprConsent ? gdprConsent.consentString : null, + servedAdsCount: window.adsCount, + adsTotalSurface: window.adsTotalSurface, + pageHeight: pageHeight, + pageWidth: pageWidth }, options: { withCredentials: false, @@ -157,7 +239,11 @@ export const spec = { } const publisherURL = JSON.stringify(request.bidRequest.params.platformURL); + const bidderURL = request.bidRequest.params.bidderURL || 'https://bidder.adhash.com'; const oneTimeId = request.bidRequest.adUnitCode + Math.random().toFixed(16).replace('0.', '.'); + const globalScript = !request.bidRequest.params.globalScript + ? `` + : ''; const bidderResponse = JSON.stringify({ responseText: JSON.stringify(responseBody) }); const requestData = JSON.stringify(request.data); @@ -165,8 +251,7 @@ export const spec = { requestId: request.bidRequest.bidId, cpm: responseBody.creatives[0].costEUR, ad: - `
- + `
${globalScript} `, width: request.bidRequest.sizes[0][0], height: request.bidRequest.sizes[0][1], diff --git a/modules/adhashBidAdapter.md b/modules/adhashBidAdapter.md index 4ee6ed3dc83..acca5a1e651 100644 --- a/modules/adhashBidAdapter.md +++ b/modules/adhashBidAdapter.md @@ -3,7 +3,7 @@ ``` Module Name: AdHash Bidder Adapter Module Type: Bidder Adapter -Maintainer: damyan@adhash.org +Maintainer: damyan@adhash.com ``` # Description @@ -14,8 +14,6 @@ Here is what you need for Prebid integration with AdHash: 3. Use the Publisher ID and Platform URL as parameters in params. Please note that a number of AdHash functionalities are not supported in the Prebid.js integration: -* Cookie-less frequency and recency capping; -* Audience segments; * Price floors and passback tags, as they are not needed in the Prebid.js setup; * Reservation for direct deals only, as bids are evaluated based on their price. diff --git a/test/spec/modules/adhashBidAdapter_spec.js b/test/spec/modules/adhashBidAdapter_spec.js index 40bf354c4d9..4ea525c59d5 100644 --- a/test/spec/modules/adhashBidAdapter_spec.js +++ b/test/spec/modules/adhashBidAdapter_spec.js @@ -60,6 +60,12 @@ describe('adhashBidAdapter', function () { bid.params.platformURL = 'https://'; expect(spec.isBidRequestValid(bid)).to.equal(false); }); + + it('should return false when bidderURL is present but not https://', function () { + const bid = { ...validBid }; + bid.params.bidderURL = 'http://example.com/'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); }); describe('buildRequests', function () { @@ -73,11 +79,11 @@ describe('adhashBidAdapter', function () { it('should build the request correctly', function () { const result = spec.buildRequests( [ bidRequest ], - { gdprConsent: { gdprApplies: true, consentString: 'example' }, refererInfo: { referer: 'http://example.com/' } } + { gdprConsent: { gdprApplies: true, consentString: 'example' }, refererInfo: { topmostLocation: 'https://example.com/path.html' } } ); expect(result.length).to.equal(1); expect(result[0].method).to.equal('POST'); - expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=1.0&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); + expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=3.2&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); expect(result[0].bidRequest).to.equal(bidRequest); expect(result[0].data).to.have.property('timezone'); expect(result[0].data).to.have.property('location'); @@ -93,7 +99,7 @@ describe('adhashBidAdapter', function () { const result = spec.buildRequests([ bidRequest ], { gdprConsent: { gdprApplies: true, consentString: 'example' } }); expect(result.length).to.equal(1); expect(result[0].method).to.equal('POST'); - expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=1.0&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); + expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=3.2&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb'); expect(result[0].bidRequest).to.equal(bidRequest); expect(result[0].data).to.have.property('timezone'); expect(result[0].data).to.have.property('location'); @@ -127,9 +133,15 @@ describe('adhashBidAdapter', function () { creatives: [{ costEUR: 1.234 }], advertiserDomains: 'adhash.com', badWords: [ - ['onqjbeq1', 'full', 1], - ['onqjbeq2', 'partial', 1], + ['onqjbeq', 'full', 1], + ['onqjbeqo', 'partial', 1], ['tbbqjbeq', 'full', -1], + ['fgnegf', 'starts', 1], + ['raqf', 'ends', 1], + ['kkk[no]lll', 'regexp', 1], + ['дума', 'full', 1], + ['старт', 'starts', 1], + ['край', 'ends', 1], ], maxScore: 2 } @@ -155,42 +167,84 @@ describe('adhashBidAdapter', function () { it('should return empty array when there are bad words (full)', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text badWord1 badWord1 example badWord1 text' + ' word'.repeat(493); + return 'example text badword badword example badword text' + ' word'.repeat(993); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (full cyrillic)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text дума дума example дума text' + ' текст'.repeat(993); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); }); it('should return empty array when there are bad words (partial)', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text partialBadWord2 badword2 example BadWord2text' + ' word'.repeat(494); + return 'example text partialbadwordb badwordb example badwordbtext' + ' word'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (starts)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text startsWith starts text startsAgain' + ' word'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (starts cyrillic)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text стартТекст старт text стартТекст' + ' дума'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (ends)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text wordEnds ends text anotherends' + ' word'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (ends cyrillic)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text ДругКрай край text ощеединкрай' + ' дума'.repeat(994); + }); + expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); + }); + + it('should return empty array when there are bad words (regexp)', function () { + bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { + return 'example text xxxayyy zzxxxAyyyzz text xxxbyyy' + ' word'.repeat(994); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(0); }); it('should return non-empty array when there are not enough bad words (full)', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text badWord1 badWord1 example text' + ' word'.repeat(494); + return 'example text badword badword example text' + ' word'.repeat(994); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(1); }); it('should return non-empty array when there are not enough bad words (partial)', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text partialBadWord2 example' + ' word'.repeat(496); + return 'example text partialbadwordb example' + ' word'.repeat(996); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(1); }); it('should return non-empty array when there are no-bad word matches', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text partialBadWord1 example text' + ' word'.repeat(495); + return 'example text partialbadword example text' + ' word'.repeat(995); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(1); }); it('should return non-empty array when there are bad words and good words', function () { bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() { - return 'example text badWord1 badWord1 example badWord1 goodWord goodWord ' + ' word'.repeat(492); + return 'example text badword badword example badword goodWord goodWord ' + ' word'.repeat(992); }); expect(spec.interpretResponse(serverResponse, request).length).to.equal(1); }); From 6236e3f3b068c6ba3920115dd4a20df5e1385ebd Mon Sep 17 00:00:00 2001 From: Carlos Felix Date: Thu, 8 Dec 2022 08:09:35 -0600 Subject: [PATCH 187/367] Add source and version parameters to the 33across ID request (#9319) --- modules/33acrossIdSystem.js | 3 +++ test/spec/modules/33acrossIdSystem_spec.js | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/33acrossIdSystem.js b/modules/33acrossIdSystem.js index 3763fee5124..5e07fe9523d 100644 --- a/modules/33acrossIdSystem.js +++ b/modules/33acrossIdSystem.js @@ -13,6 +13,7 @@ import { uspDataHandler } from '../src/adapterManager.js'; const MODULE_NAME = '33acrossId'; const API_URL = 'https://lexicon.33across.com/v1/envelope'; const AJAX_TIMEOUT = 10000; +const CALLER_NAME = 'pbjs'; function getEnvelope(response) { if (!response.succeeded) { @@ -36,6 +37,8 @@ function calculateQueryStringParams(pid, gdprConsentData) { const params = { pid, gdpr: Number(gdprApplies), + src: CALLER_NAME, + ver: '$prebid.version$' }; if (uspString) { diff --git a/test/spec/modules/33acrossIdSystem_spec.js b/test/spec/modules/33acrossIdSystem_spec.js index 8198bd75381..765b320f925 100644 --- a/test/spec/modules/33acrossIdSystem_spec.js +++ b/test/spec/modules/33acrossIdSystem_spec.js @@ -43,7 +43,10 @@ describe('33acrossIdSystem', () => { expect(request.method).to.equal('GET'); expect(request.withCredentials).to.be.true; - expect(request.url).to.contain('https://lexicon.33across.com/v1/envelope?pid=12345'); + + const regExp = new RegExp('https://lexicon.33across.com/v1/envelope\\?pid=12345&gdpr=\\d&src=pbjs&ver=$prebid.version$'); + + expect(request.url).to.match(regExp); expect(completeCallback.calledOnceWithExactly('foo')).to.be.true; }); From 1b4d83c112e157a3ed1702e5f068b85cf8cce401 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 8 Dec 2022 07:32:14 -0700 Subject: [PATCH 188/367] Prebid Core: ORTB 2.5 translation utilities (#9263) * ORTB 2.5 spec definition * ORTB 2.5 translation * Only test translation of native reqs if FEATURES.NATIVE is set --- libraries/ortb2.5StrictTranslator/dsl.js | 54 +++ libraries/ortb2.5StrictTranslator/spec.js | 81 ++++ .../ortb2.5StrictTranslator/translator.js | 37 ++ libraries/ortb2.5Translator/translator.js | 82 ++++ test/spec/ortb2.5StrictTranslator/dsl_spec.js | 137 +++++++ .../spec/ortb2.5StrictTranslator/spec_spec.js | 358 ++++++++++++++++++ .../translator_spec.js | 16 + .../spec/ortb2.5Translator/translator_spec.js | 64 ++++ 8 files changed, 829 insertions(+) create mode 100644 libraries/ortb2.5StrictTranslator/dsl.js create mode 100644 libraries/ortb2.5StrictTranslator/spec.js create mode 100644 libraries/ortb2.5StrictTranslator/translator.js create mode 100644 libraries/ortb2.5Translator/translator.js create mode 100644 test/spec/ortb2.5StrictTranslator/dsl_spec.js create mode 100644 test/spec/ortb2.5StrictTranslator/spec_spec.js create mode 100644 test/spec/ortb2.5StrictTranslator/translator_spec.js create mode 100644 test/spec/ortb2.5Translator/translator_spec.js diff --git a/libraries/ortb2.5StrictTranslator/dsl.js b/libraries/ortb2.5StrictTranslator/dsl.js new file mode 100644 index 00000000000..8f9fc79feeb --- /dev/null +++ b/libraries/ortb2.5StrictTranslator/dsl.js @@ -0,0 +1,54 @@ +export const ERR_TYPE = 0; // field has wrong type (only objects, enums, and arrays of objects or enums are checked) +export const ERR_UNKNOWN_FIELD = 1; // field is not defined in ORTB 2.5 spec +export const ERR_ENUM = 2; // field is an enum and its value is not one of those listed in the ORTB 2.5 spec + +// eslint-disable-next-line symbol-description +export const extend = Symbol(); + +export function Obj(primitiveFields, spec = {}) { + const scan = (path, parent, field, value, onError) => { + if (value == null || typeof value !== 'object') { + onError(ERR_TYPE, path, parent, field, value); + return; + } + Object.entries(value).forEach(([k, v]) => { + if (v == null) return; + const kpath = path == null ? k : `${path}.${k}`; + if (spec.hasOwnProperty(k)) { + spec[k](kpath, value, k, v, onError); + return; + } + if (k !== 'ext' && !primitiveFields.includes(k)) { + onError(ERR_UNKNOWN_FIELD, kpath, value, k, v); + } + }); + }; + scan[extend] = (extraPrimitives, specOverride = {}) => + Obj(primitiveFields.concat(extraPrimitives), Object.assign({}, spec, specOverride)); + return scan; +} + +export const ID = Obj(['id']); +export const Named = ID[extend](['name']); + +export function Arr(def) { + return (path, parent, field, value, onError) => { + if (!Array.isArray(value)) { + onError(ERR_TYPE, path, parent, field, value); + } else { + value.forEach((item, i) => def(`${path}.${i}`, value, i, item, onError)); + } + }; +} + +export function IntEnum(min, max) { + return (path, parent, field, value, onError) => { + const errno = (() => { + if (typeof value !== 'number') return ERR_TYPE; + if (isNaN(value) || value > max || value < min) return ERR_ENUM; + })(); + if (errno != null) { + onError(errno, path, parent, field, value); + } + }; +} diff --git a/libraries/ortb2.5StrictTranslator/spec.js b/libraries/ortb2.5StrictTranslator/spec.js new file mode 100644 index 00000000000..0ffb17a2e72 --- /dev/null +++ b/libraries/ortb2.5StrictTranslator/spec.js @@ -0,0 +1,81 @@ +import {Arr, extend, ID, IntEnum, Named, Obj} from './dsl.js'; + +const CatDomain = Named[extend](['cat', 'domain']); +const Segment = Named[extend](['value']); +const Data = Named[extend]([], { + segment: Arr(Segment) +}); +const Content = ID[extend](['episode', 'title', 'series', 'season', 'artist', 'genre', 'album', 'isrc', 'url', 'cat', 'contentrating', 'userrating', 'keywords', 'livestream', 'sourcerelationship', 'len', 'language', 'embeddable'], { + producer: CatDomain, + data: Arr(Data), + prodq: IntEnum(0, 3), + videoquality: IntEnum(0, 3), + context: IntEnum(1, 7), + qagmediarating: IntEnum(1, 3), +}); + +const Client = CatDomain[extend](['sectioncat', 'pagecat', 'privacypolicy', 'keywords'], { + publisher: CatDomain, content: Content, +}); +const Site = Client[extend](['page', 'ref', 'search', 'mobile']); +const App = Client[extend](['bundle', 'storeurl', 'ver', 'paid']); + +const Geo = Obj(['lat', 'lon', 'accuracy', 'lastfix', 'country', 'region', 'regionfips104', 'metro', 'city', 'zip', 'utcoffset'], { + type: IntEnum(1, 3), + ipservice: IntEnum(1, 4) +}); +const Device = Obj(['ua', 'dnt', 'lmt', 'ip', 'ipv6', 'make', 'model', 'os', 'osv', 'hwv', 'h', 'w', 'ppi', 'pxratio', 'js', 'geofetch', 'flashver', 'language', 'carrier', 'mccmnc', 'ifa', 'didsha1', 'didmd5', 'dpidsha1', 'dpidmd5', 'macsha1', 'macmd5'], { + geo: Geo, devicetype: IntEnum(1, 7), connectiontype: IntEnum(0, 6) +}); +const User = ID[extend](['buyeruid', 'yob', 'gender', 'keywords', 'customdata'], { + geo: Geo, data: Arr(Data), +}); + +const Floorable = ID[extend](['bidfloor', 'bidfloorcur']); +const Deal = Floorable[extend](['at', 'wseat', 'wadomain']); +const Pmp = Obj(['private_auction'], { + deals: Arr(Deal), +}); +const Format = Obj(['w', 'h', 'wratio', 'hratio', 'wmin']); +const MediaType = Obj(['mimes'], { + api: Arr(IntEnum(1, 6)), battr: Arr(IntEnum(1, 17)) +}); +const Banner = MediaType[extend](['id', 'w', 'h', 'wmax', 'hmax', 'hmin', 'wmin', 'topframe', 'vcm'], { + format: Arr(Format), btype: Arr(IntEnum(1, 4)), pos: IntEnum(0, 7), expdir: Arr(IntEnum(1, 5)) +}); +const Native = MediaType[extend](['request', 'ver']); +const RichMediaType = MediaType[extend](['minduration', 'maxduration', 'startdelay', 'sequence', 'maxextended', 'minbitrate', 'maxbitrate'], { + protocols: Arr(IntEnum(1, 10)), + delivery: Arr(IntEnum(1, 3)), + companionad: Arr(Banner), + companiontype: Arr(IntEnum(1, 3)), +}); +/* +const Audio = RichMediaType[extend](['maxseq', 'stitched'], { + feed: IntEnum(1, 3), nvol: IntEnum(0, 4), +}); + */ +const Video = RichMediaType[extend](['w', 'h', 'skip', 'skipmin', 'skipafter', 'boxingallowed'], { + pos: IntEnum(0, 7), + protocol: IntEnum(1, 10), + placement: IntEnum(1, 5), + linearity: IntEnum(1, 2), + playbackmethod: Arr(IntEnum(1, 6)), + playbackend: IntEnum(1, 3), +}); +const Metric = Obj(['type', 'value', 'vendor']); +const Imp = (() => { + const spec = { + metric: Arr(Metric), banner: Banner, video: Video, pmp: Pmp, + }; + if (FEATURES.NATIVE) { + spec.native = Native; + } + return Floorable[extend](['displaymanager', 'displaymanagerver', 'instl', 'tagid', 'clickbrowser', 'secure', 'iframebuster', 'exp'], spec); +})(); + +const Regs = Obj(['coppa']); +const Source = Obj(['fd', 'tid', 'pchain']); +export const BidRequest = ID[extend](['test', 'at', 'tmax', 'wseat', 'bseat', 'allimps', 'cur', 'wlang', 'bcat', 'badv', 'bapp'], { + imp: Arr(Imp), site: Site, app: App, device: Device, user: User, source: Source, regs: Regs +}); diff --git a/libraries/ortb2.5StrictTranslator/translator.js b/libraries/ortb2.5StrictTranslator/translator.js new file mode 100644 index 00000000000..c6f651e2476 --- /dev/null +++ b/libraries/ortb2.5StrictTranslator/translator.js @@ -0,0 +1,37 @@ +import {BidRequest} from './spec.js'; +import {logWarn} from '../../src/utils.js'; +import {toOrtb25} from '../ortb2.5Translator/translator.js'; + +function deleteField(errno, path, obj, field, value) { + logWarn(`${path} is not valid ORTB 2.5, field will be removed from request:`, value); + Array.isArray(obj) ? obj.splice(field, 1) : delete obj[field]; +} + +/** + * Translates an ortb request to 2.5, and removes from the result any field that is: + * - not defined in the 2.5 spec, or + * - defined as an enum, but has a value that is not listed in the 2.5 spec. + * + * `ortb2` is modified in place and returned. + * + * Note that using this utility will cause your adapter to pull in an additional ~3KB after minification. + * If possible, consider making your endpoint tolerant to unrecognized or invalid fields instead. + * + * + * @param ortb2 ORTB request + * @param translator translation function. The default moves 2.x fields that have a known standard location in 2.5. + * See the `ortb2.5Translator` library. + * @param onError a function invoked once for each field that is not valid according to the 2.5 spec; it takes + * (errno, path, obj, field, value), where: + * - errno is an error code (defined in dsl.js) + * - path is the JSON path of the offending field, for example `regs.gdpr` + * - obj is the object containing the offending field, for example `ortb2.regs` + * - field is the field name, for example `'gdpr'` + * - value is `obj[field]`. + * The default logs a warning and deletes the offending field. + */ +export function toOrtb25Strict(ortb2, translator = toOrtb25, onError = deleteField) { + ortb2 = translator(ortb2); + BidRequest(null, null, null, ortb2, onError); + return ortb2; +} diff --git a/libraries/ortb2.5Translator/translator.js b/libraries/ortb2.5Translator/translator.js new file mode 100644 index 00000000000..1afad516ef0 --- /dev/null +++ b/libraries/ortb2.5Translator/translator.js @@ -0,0 +1,82 @@ +import {deepAccess, deepSetValue, logError} from '../../src/utils.js'; + +export const EXT_PROMOTIONS = [ + 'source.schain', + 'regs.gdpr', + 'regs.us_privacy', + 'regs.gpp', + 'user.consent', + 'user.eids' +]; + +export function splitPath(path) { + const parts = path.split('.'); + const prefix = parts.slice(0, parts.length - 1).join('.'); + const field = parts[parts.length - 1]; + return [prefix, field]; +} + +/** + * @param sourcePath a JSON path such as `regs.us_privacy` + * @param dest {function(String, String): String} a function taking (prefix, field) and returning a destination path; + * for example, ('regs', 'us_privacy') => 'regs.ext.us_privacy' + * @return {(function({}): (function(): void|undefined))|*} a function that takes an object and, if it contains + * sourcePath, copies its contents to destinationPath, returning a function that deletes the original sourcePath. + */ +export function moveRule(sourcePath, dest = (prefix, field) => `${prefix}.ext.${field}`) { + const [prefix, field] = splitPath(sourcePath); + dest = dest(prefix, field); + return (ortb2) => { + const obj = deepAccess(ortb2, prefix); + if (obj?.[field] != null) { + deepSetValue(ortb2, dest, obj[field]); + return () => delete obj[field]; + } + }; +} + +function kwarrayRule(section) { + // move 2.6 `kwarray` into 2.5 comma-separated `keywords`. + return (ortb2) => { + const kwarray = ortb2[section]?.kwarray; + if (kwarray != null) { + let kw = (ortb2[section].keywords || '').split(','); + if (Array.isArray(kwarray)) kw.push(...kwarray); + ortb2[section].keywords = kw.join(','); + return () => delete ortb2[section].kwarray; + } + }; +} + +export const DEFAULT_RULES = Object.freeze([ + ...EXT_PROMOTIONS.map((f) => moveRule(f)), + ...['app', 'content', 'site', 'user'].map(kwarrayRule) +]); + +/** + * Factory for ORTB 2.5 translation functions. + * + * @param deleteFields if true, the translation function will remove fields that have been translated (transferred somewhere else within the request) + * @param rules translation rules; an array of functions of the type returned by `moveRule` + * @return {function({}): {}} a translation function that takes an ORTB object, modifies it in place, and returns it. + */ +export function ortb25Translator(deleteFields = true, rules = DEFAULT_RULES) { + return function (ortb2) { + rules.forEach(f => { + try { + const deleter = f(ortb2); + if (typeof deleter === 'function' && deleteFields) deleter(); + } catch (e) { + logError('Error translating request to ORTB 2.5', e); + } + }) + return ortb2; + } +} + +/** + * Translate an ortb request to version 2.5 by moving 2.6 (and later) fields that have a standardized 2.5 extension. + * + * The request is modified in place and returned. + */ +export const toOrtb25 = ortb25Translator(); diff --git a/test/spec/ortb2.5StrictTranslator/dsl_spec.js b/test/spec/ortb2.5StrictTranslator/dsl_spec.js new file mode 100644 index 00000000000..c9b4575bcd2 --- /dev/null +++ b/test/spec/ortb2.5StrictTranslator/dsl_spec.js @@ -0,0 +1,137 @@ +import {Arr, ERR_ENUM, ERR_TYPE, ERR_UNKNOWN_FIELD, IntEnum, Obj} from '../../../libraries/ortb2.5StrictTranslator/dsl.js'; +import {deepClone} from '../../../src/utils.js'; + +describe('DSL', () => { + const spec = (() => { + const inner = Obj(['p21', 'p22'], { + enum: IntEnum(10, 20), + enumArray: Arr(IntEnum(10, 20)) + }); + return Obj(['p11', 'p12'], { + inner, + innerArray: Arr(inner) + }); + })(); + + let onError; + + function scan(obj) { + spec(null, null, null, obj, onError); + } + + beforeEach(() => { + onError = sinon.stub(); + }); + + it('checks object type', () => { + scan(null); + sinon.assert.calledWith(onError, ERR_TYPE, null, null, null, null); + }); + it('ignores known fields and ext', () => { + scan({p11: 1, p12: 2, ext: {e1: 1, e2: 2}}); + sinon.assert.notCalled(onError); + }); + it('detects unknown fields', () => { + const obj = {p11: 1, unk: 2}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_UNKNOWN_FIELD, 'unk', obj, 'unk', 2); + }); + describe('when nested', () => { + describe('directly', () => { + it('detects unknown fields', () => { + const obj = {inner: {p21: 1, unk: 2}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_UNKNOWN_FIELD, 'inner.unk', obj.inner, 'unk', 2); + }); + it('accepts enum values in range', () => { + scan({inner: {enum: 12}}); + sinon.assert.notCalled(onError); + }); + [Infinity, NaN, -Infinity].forEach(val => { + it(`does not accept ${val} in enum`, () => { + const obj = {inner: {enum: val}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_ENUM, 'inner.enum', obj.inner, 'enum', val); + }); + }); + it('accepts arrays of enums that are in range', () => { + scan({inner: {enumArray: [12, 13]}}); + sinon.assert.notCalled(onError); + }) + it('detects enum values out of range', () => { + const obj = {inner: {enum: -1}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_ENUM, 'inner.enum', obj.inner, 'enum', -1); + }); + it('detects enum values that are not numbers', () => { + const obj = {inner: {enum: 'err'}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_TYPE, 'inner.enum', obj.inner, 'enum', 'err'); + }) + it('detects arrays of enums that are out of range', () => { + const obj = {inner: {enumArray: [12, 13, -1, 14]}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_ENUM, 'inner.enumArray.2', obj.inner.enumArray, 2, -1); + }); + it('detects when enum arrays are not arrays', () => { + const obj = {inner: {enumArray: 'err'}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_TYPE, 'inner.enumArray', obj.inner, 'enumArray', 'err'); + }); + it('detects items within enum arrays that are not numbers', () => { + const obj = {inner: {enumArray: [12, 'err', 13]}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_TYPE, 'inner.enumArray.1', obj.inner.enumArray, 1, 'err'); + }) + }); + describe('into arrays', () => { + it('detects if inner array is not an array', () => { + const obj = {innerArray: 'err', inner: {p21: 1}}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_TYPE, 'innerArray', obj, 'innerArray', 'err'); + }); + it('detects when elements of inner array are not objects', () => { + const obj = {innerArray: [{p21: 1}, 'err', {ext: {r: 1}}]}; + scan(obj); + sinon.assert.calledOnce(onError); + sinon.assert.calledWith(onError, ERR_TYPE, 'innerArray.1', obj.innerArray, 1, 'err'); + }); + const oos = { + innerArray: [ + {p22: 2, unk: 3, enumArray: [-1, 12, 'err']}, + {p21: 1, enum: -1, ext: {e: 1}}, + ] + }; + it('detects invalid properties within inner array', () => { + const obj = deepClone(oos); + scan(obj); + sinon.assert.calledWith(onError, ERR_UNKNOWN_FIELD, 'innerArray.0.unk', obj.innerArray[0], 'unk', 3); + sinon.assert.calledWith(onError, ERR_ENUM, 'innerArray.0.enumArray.0', obj.innerArray[0].enumArray, 0, -1); + sinon.assert.calledWith(onError, ERR_TYPE, 'innerArray.0.enumArray.2', obj.innerArray[0].enumArray, 2, 'err'); + sinon.assert.calledWith(onError, ERR_ENUM, 'innerArray.1.enum', obj.innerArray[1], 'enum', -1); + }); + it('can remove all invalid properties during scan', () => { + onError.callsFake((errno, path, obj, field) => { + Array.isArray(obj) ? obj.splice(field, 1) : delete obj[field]; + }); + const obj = deepClone(oos); + scan(obj); + expect(obj).to.eql({ + innerArray: [ + {p22: 2, enumArray: [12]}, + {p21: 1, ext: {e: 1}} + ] + }); + }) + }) + }) +}); diff --git a/test/spec/ortb2.5StrictTranslator/spec_spec.js b/test/spec/ortb2.5StrictTranslator/spec_spec.js new file mode 100644 index 00000000000..a54b551bf61 --- /dev/null +++ b/test/spec/ortb2.5StrictTranslator/spec_spec.js @@ -0,0 +1,358 @@ +import {BidRequest} from '../../../libraries/ortb2.5StrictTranslator/spec.js'; + +// sample requests taken from ORTB 2.5 spec: https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf +const SAMPLE_REQUESTS = [ + { + 'id': '80ce30c53c16e6ede735f123ef6e32361bfc7b22', + 'at': 1, + 'cur': ['USD'], + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.03, + 'banner': { + 'h': 250, 'w': 300, 'pos': 0 + } + } + ], + 'site': { + 'id': '102855', + 'cat': ['IAB3-1'], + 'domain': 'www.foobar.com', + 'page': 'http://www.foobar.com/1234.html ', + 'publisher': { + 'id': '8953', + 'name': 'foobar.com', + 'cat': ['IAB3-1'], + 'domain': 'foobar.com' + } + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', + 'ip': '123.145.167.10' + }, + 'user': { + 'id': '55816b39711f9b5acf3b90e313ed29e51665623f' + } + }, + { + 'id': '123456789316e6ede735f123ef6e32361bfc7b22', + 'at': 2, + 'cur': ['USD'], + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.03, + 'iframebuster': ['vendor1.com', 'vendor2.com'], + 'banner': { + 'h': 250, + 'w': 300, + 'pos': 0, + 'battr': [13], + 'expdir': [2, 4] + } + } + ], + 'site': { + 'id': '102855', + 'cat': ['IAB3-1'], + 'domain': 'www.foobar.com', + 'page': 'http://www.foobar.com/1234.html', + 'publisher': { + 'id': '8953', + 'name': 'foobar.com', + 'cat': ['IAB3-1'], + 'domain': 'foobar.com' + } + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', + 'ip': '123.145.167.10' + }, + 'user': { + 'id': '55816b39711f9b5acf3b90e313ed29e51665623f', + 'buyeruid': '545678765467876567898765678987654', + 'data': [ + { + 'id': '6', + 'name': 'Data Provider 1', + 'segment': [ + { + 'id': '12341318394918', 'name': 'auto intenders' + }, + { + 'id': '1234131839491234', 'name': 'auto enthusiasts' + }, + { + 'id': '23423424', + 'name': 'data-provider1-age', + 'value': '30-40' + } + ] + } + ] + } + }, + { + 'id': 'IxexyLDIIk', + 'at': 2, + 'bcat': ['IAB25', 'IAB7-39', 'IAB8-18', 'IAB8-5', 'IAB9-9'], + 'badv': ['apple.com', 'go-text.me', 'heywire.com'], + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.5, + 'instl': 0, + 'tagid': 'agltb3B1Yi1pbmNyDQsSBFNpdGUY7fD0FAw', + 'banner': { + 'w': 728, + 'h': 90, + 'pos': 1, + 'btype': [4], + 'battr': [14], + 'api': [3] + } + } + ], + 'app': { + 'id': 'agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA', + 'name': 'Yahoo Weather', + 'cat': ['IAB15', 'IAB15-10'], + 'ver': '1.0.2', + 'bundle': '12345', + 'storeurl': 'https://itunes.apple.com/id628677149', + 'publisher': { + 'id': 'agltb3B1Yi1pbmNyDAsSA0FwcBiJkfTUCV', + 'name': 'yahoo', + 'domain': 'www.yahoo.com' + } + }, + 'device': { + 'dnt': 0, + 'ua': 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3', + 'ip': '123.145.167.189', + 'ifa': 'AA000DFE74168477C70D291f574D344790E0BB11', + 'carrier': 'VERIZON', + 'language': 'en', + 'make': 'Apple', + 'model': 'iPhone', + 'os': 'iOS', + 'osv': '6.1', + 'js': 1, + 'connectiontype': 3, + 'devicetype': 1, + 'geo': { + 'lat': 35.012345, + 'lon': -115.12345, + 'country': 'USA', + 'metro': '803', + 'region': 'CA', + 'city': 'Los Angeles', + 'zip': '90049' + } + }, + 'user': { + 'id': 'ffffffd5135596709273b3a1a07e466ea2bf4fff', + 'yob': 1984, + 'gender': 'M' + } + }, + { + 'id': '1234567893', + 'at': 2, + 'tmax': 120, + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.03, + 'video': { + 'w': 640, + 'h': 480, + 'pos': 1, + 'startdelay': 0, + 'minduration': 5, + 'maxduration': 30, + 'maxextended': 30, + 'minbitrate': 300, + 'maxbitrate': 1500, + 'api': [1, 2], + 'protocols': [2, 3], + 'mimes': [ + 'video/x-flv', + 'video/mp4', + 'application/x-shockwave-flash', + 'application/javascript' + ], + 'linearity': 1, + 'boxingallowed': 1, + 'playbackmethod': [1, 3], + 'delivery': [2], + 'battr': [13, 14], + 'companionad': [ + { + 'id': '1234567893-1', + 'w': 300, + 'h': 250, + 'pos': 1, + 'battr': [13, 14], + 'expdir': [2, 4] + }, + { + 'id': '1234567893-2', + 'w': 728, + 'h': 90, + 'pos': 1, + 'battr': [13, 14] + } + ], + 'companiontype': [1, 2] + } + } + ], + 'site': { + 'id': '1345135123', + 'name': 'Site ABCD', + 'domain': 'siteabcd.com', + 'cat': ['IAB2-1', 'IAB2-2'], + 'page': 'http://siteabcd.com/page.htm', + 'ref': 'http://referringsite.com/referringpage.htm', + 'privacypolicy': 1, + 'publisher': { + 'id': 'pub12345', 'name': 'Publisher A' + }, + 'content': { + 'id': '1234567', + 'series': 'All About Cars', + 'season': '2', + 'episode': 23, + 'title': 'Car Show', + 'cat': ['IAB2-2'], + 'keywords': 'keyword-a,keyword-b,keyword-c' + } + }, + 'device': { + 'ip': '64.124.253.1', + 'ua': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16', + 'os': 'OS X', + 'flashver': '10.1', + 'js': 1 + }, + 'user': { + 'id': '456789876567897654678987656789', + 'buyeruid': '545678765467876567898765678987654', + 'data': [ + { + 'id': '6', + 'name': 'Data Provider 1', + 'segment': [ + { + 'id': '12341318394918', 'name': 'auto intenders' + }, + { + 'id': '1234131839491234', 'name': 'auto enthusiasts' + } + ] + } + ] + } + }, + { + 'id': '80ce30c53c16e6ede735f123ef6e32361bfc7b22', + 'at': 1, + 'cur': ['USD'], + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.03, + 'banner': { + 'h': 250, 'w': 300, 'pos': 0 + }, + 'pmp': { + 'private_auction': 1, + 'deals': [ + { + 'id': 'AB-Agency1-0001', + 'at': 1, + 'bidfloor': 2.5, + 'wseat': ['Agency1'] + }, + { + 'id': 'XY-Agency2-0001', + 'at': 2, + 'bidfloor': 2, + 'wseat': ['Agency2'] + } + ] + } + } + ], + 'site': { + 'id': '102855', + 'domain': 'www.foobar.com', + 'cat': ['IAB3-1'], + 'page': 'http://www.foobar.com/1234.html', + 'publisher': { + 'id': '8953', + 'name': 'foobar.com', + 'cat': ['IAB3-1'], + 'domain': 'foobar.com' + } + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', + 'ip': '123.145.167.10' + }, + 'user': { + 'id': '55816b39711f9b5acf3b90e313ed29e51665623f' + } + }, +]; + +if (FEATURES.NATIVE) { + SAMPLE_REQUESTS.push({ + 'id': '80ce30c53c16e6ede735f123ef6e32361bfc7b22', + 'at': 1, + 'cur': ['USD'], + 'imp': [ + { + 'id': '1', + 'bidfloor': 0.03, + 'native': { + 'request': '{"native":{"ver":"1.0","assets":[ ... ]}}', + 'ver': '1.0', + 'api': [3], + 'battr': [13, 14] + } + } + ], + 'site': { + 'id': '102855', + 'cat': ['IAB3-1'], + 'domain': 'www.foobar.com', + 'page': 'http://www.foobar.com/1234.html ', + 'publisher': { + 'id': '8953', + 'name': 'foobar.com', + 'cat': ['IAB3-1'], + 'domain': 'foobar.com' + } + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', + 'ip': '123.145.167.10' + }, + 'user': { + 'id': '55816b39711f9b5acf3b90e313ed29e51665623f' + } + }); +} + +describe('BidRequest spec', () => { + SAMPLE_REQUESTS.forEach((req, i) => { + it(`accepts sample #${i}`, () => { + const onError = sinon.stub(); + BidRequest(null, null, null, req, onError); + sinon.assert.notCalled(onError); + }); + }); +}); diff --git a/test/spec/ortb2.5StrictTranslator/translator_spec.js b/test/spec/ortb2.5StrictTranslator/translator_spec.js new file mode 100644 index 00000000000..4bda3d96235 --- /dev/null +++ b/test/spec/ortb2.5StrictTranslator/translator_spec.js @@ -0,0 +1,16 @@ +import {toOrtb25Strict} from '../../../libraries/ortb2.5StrictTranslator/translator.js'; + +describe('toOrtb25Strict', () => { + let translator; + beforeEach(() => { + translator = sinon.stub().callsFake((o) => o); + }) + it('uses provided translator', () => { + translator.reset(); + translator.callsFake(() => ({id: 'test'})); + expect(toOrtb25Strict(null, translator)).to.eql({id: 'test'}); + }); + it('removes fields out of spec', () => { + expect(toOrtb25Strict({unk: 'field', imp: ['err', {}]}, translator)).to.eql({imp: [{}]}); + }); +}); diff --git a/test/spec/ortb2.5Translator/translator_spec.js b/test/spec/ortb2.5Translator/translator_spec.js new file mode 100644 index 00000000000..db20a8f59be --- /dev/null +++ b/test/spec/ortb2.5Translator/translator_spec.js @@ -0,0 +1,64 @@ +import {EXT_PROMOTIONS, moveRule, splitPath, toOrtb25} from '../../../libraries/ortb2.5Translator/translator.js'; +import {deepAccess, deepClone, deepSetValue} from '../../../src/utils.js'; + +describe('ORTB 2.5 translation', () => { + describe('moveRule', () => { + const rule = moveRule('f1.f2.f3', (prefix, field) => `${prefix}.m1.m2.${field}`); + + function applyRule(rule, obj, del = true) { + obj = deepClone(obj); + const deleter = rule(obj); + if (typeof deleter === 'function' && del) { + deleter(); + } + return obj; + } + + it('returns undef when field is not present', () => { + expect(rule({})).to.eql(undefined); + }); + it('can copy field', () => { + expect(applyRule(rule, {f1: {f2: {f3: 'value'}}}, false)).to.eql({ + f1: { + f2: { + f3: 'value', + m1: {m2: {f3: 'value'}} + } + } + }); + }); + it('can move field', () => { + expect(applyRule(rule, {f1: {f2: {f3: 'value'}}}, true)).to.eql({f1: {f2: {m1: {m2: {f3: 'value'}}}}}); + }); + }); + describe('toOrtb25', () => { + EXT_PROMOTIONS.forEach(path => { + const newPath = (() => { + const [prefix, field] = splitPath(path); + return `${prefix}.ext.${field}`; + })(); + + it(`moves ${path} to ${newPath}`, () => { + const obj = {}; + deepSetValue(obj, path, 'val'); + toOrtb25(obj); + expect(deepAccess(obj, path)).to.eql(undefined); + expect(deepAccess(obj, newPath)).to.eql('val'); + }); + }); + it('moves kwarray into keywords', () => { + expect(toOrtb25({app: {keywords: 'k1,k2', kwarray: ['ka1', 'ka2']}})).to.eql({app: {keywords: 'k1,k2,ka1,ka2'}}); + }); + it('does not choke if kwarray is not an array', () => { + expect(toOrtb25({site: {keywords: 'k1,k2', kwarray: 'err'}})).to.eql({site: {keywords: 'k1,k2'}}); + }); + it('does not choke if keywords is not a string', () => { + expect(toOrtb25({user: {keywords: {}, kwarray: ['ka1', 'ka2']}})).to.eql({ + user: { + keywords: {}, + kwarray: ['ka1', 'ka2'] + } + }); + }); + }); +}); From 4346aa82264a08c7f135fd2de4acb06285c1868e Mon Sep 17 00:00:00 2001 From: Jason Quaccia Date: Thu, 8 Dec 2022 09:25:07 -0800 Subject: [PATCH 189/367] Prebid Core: Addition of Optional Category Targeting Key (#9268) * addition of category optional targeting * removed console log statements * console.log statements for debugging * updated tests * formatting changes * added pbs test --- src/auction.js | 12 ++++++++++- src/constants.json | 3 ++- test/spec/auctionmanager_spec.js | 34 +++++++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/auction.js b/src/auction.js index 563eb85e788..87397b0dc15 100644 --- a/src/auction.js +++ b/src/auction.js @@ -828,6 +828,16 @@ export const getAdvertiserDomain = () => { } } +/** + * This function returns a function to get the primary category id from bid response meta + * @returns {function} + */ +export const getPrimaryCatId = () => { + return (bid) => { + return (bid.meta && bid.meta.primaryCatId) ? bid.meta.primaryCatId : ''; + } +} + // factory for key value objs function createKeyVal(key, value) { return { @@ -853,6 +863,7 @@ function defaultAdserverTargeting() { createKeyVal(TARGETING_KEYS.SOURCE, 'source'), createKeyVal(TARGETING_KEYS.FORMAT, 'mediaType'), createKeyVal(TARGETING_KEYS.ADOMAIN, getAdvertiserDomain()), + createKeyVal(TARGETING_KEYS.ACAT, getPrimaryCatId()), ] } @@ -865,7 +876,6 @@ function defaultAdserverTargeting() { export function getStandardBidderSettings(mediaType, bidderCode) { const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS; const standardSettings = Object.assign({}, bidderSettings.settingsFor(null)); - if (!standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) { standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = defaultAdserverTargeting(); } diff --git a/src/constants.json b/src/constants.json index 30ade5fccbe..e33d65f3fb1 100644 --- a/src/constants.json +++ b/src/constants.json @@ -76,7 +76,8 @@ "UUID": "hb_uuid", "CACHE_ID": "hb_cache_id", "CACHE_HOST": "hb_cache_host", - "ADOMAIN": "hb_adomain" + "ADOMAIN": "hb_adomain", + "ACAT": "hb_acat" }, "DEFAULT_TARGETING_KEYS": { "BIDDER": "hb_bidder", diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index 46350895050..e1ecf801aa3 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -186,7 +186,8 @@ describe('auctionmanager.js', function () { source: 'client', mediaType: 'banner', meta: { - advertiserDomains: ['adomain'] + advertiserDomains: ['adomain'], + primaryCatId: 'IAB-test' } }; @@ -200,6 +201,7 @@ describe('auctionmanager.js', function () { expected[ CONSTANTS.TARGETING_KEYS.SOURCE ] = bid.source; expected[ CONSTANTS.TARGETING_KEYS.FORMAT ] = bid.mediaType; expected[ CONSTANTS.TARGETING_KEYS.ADOMAIN ] = bid.meta.advertiserDomains[0]; + expected[ CONSTANTS.TARGETING_KEYS.ACAT ] = bid.meta.primaryCatId; if (bid.mediaType === 'video') { expected[ CONSTANTS.TARGETING_KEYS.UUID ] = bid.videoCacheKey; expected[ CONSTANTS.TARGETING_KEYS.CACHE_ID ] = bid.videoCacheKey; @@ -290,6 +292,12 @@ describe('auctionmanager.js', function () { val: function (bidResponse) { return bidResponse.meta.advertiserDomains[0]; } + }, + { + key: CONSTANTS.TARGETING_KEYS.ACAT, + val: function (bidResponse) { + return bidResponse.meta.primaryCatId; + } } ] @@ -367,6 +375,12 @@ describe('auctionmanager.js', function () { val: function (bidResponse) { return bidResponse.meta.advertiserDomains[0]; } + }, + { + key: CONSTANTS.TARGETING_KEYS.ACAT, + val: function (bidResponse) { + return bidResponse.meta.primaryCatId; + } } ] @@ -455,6 +469,24 @@ describe('auctionmanager.js', function () { assert.deepEqual(response, expected); }); + it('Should set targeting as expecting when pbs is enabled', function () { + config.setConfig({ + s2sConfig: { + accountId: '1', + enabled: true, + defaultVendor: 'appnexus', + bidders: ['appnexus'], + timeout: 1000, + adapter: 'prebidServer' + } + }); + + $$PREBID_GLOBAL$$.bidderSettings = {}; + let expected = getDefaultExpected(bid); + let response = getKeyValueTargetingPairs(bid.bidderCode, bid); + assert.deepEqual(response, expected); + }); + it('Custom bidCpmAdjustment for one bidder and inherit standard but doesn\'t use standard bidCpmAdjustment', function () { $$PREBID_GLOBAL$$.bidderSettings = { From f5f276bb827d5b81b12b2c62e405bb11768690e5 Mon Sep 17 00:00:00 2001 From: ahmadlob <109217988+ahmadlob@users.noreply.github.com> Date: Thu, 8 Dec 2022 19:54:43 +0200 Subject: [PATCH 190/367] Taboola Bid Adapter: Fixing Accepting Bid Floor Mechanism (#9279) * use-convention-for-bidfloor-extraction * use-convention-for-bidfloor-extraction * add-unit-tests --- modules/taboolaBidAdapter.js | 27 ++++++++++---- test/spec/modules/taboolaBidAdapter_spec.js | 39 +++++++++++++++++++++ 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/modules/taboolaBidAdapter.js b/modules/taboolaBidAdapter.js index 9bd42651796..670d28ab64e 100644 --- a/modules/taboolaBidAdapter.js +++ b/modules/taboolaBidAdapter.js @@ -170,15 +170,28 @@ function getSiteProperties({publisherId, bcat = []}, refererInfo) { function getImps(validBidRequests) { return validBidRequests.map((bid, id) => { - const {tagId, bidfloor = null, bidfloorcur = CURRENCY} = bid.params; - - return { + const {tagId} = bid.params; + const imp = { id: id + 1, banner: getBanners(bid), - tagid: tagId, - bidfloor, - bidfloorcur, - }; + tagid: tagId + } + if (typeof bid.getFloor === 'function') { + const floorInfo = bid.getFloor({ + currency: CURRENCY, + mediaType: BANNER, + size: '*' + }); + if (typeof floorInfo === 'object' && floorInfo.currency === CURRENCY && !isNaN(parseFloat(floorInfo.floor))) { + imp.bidfloor = parseFloat(floorInfo.floor); + imp.bidfloorcur = CURRENCY; + } + } else { + const {bidfloor = null, bidfloorcur = CURRENCY} = bid.params; + imp.bidfloor = bidfloor; + imp.bidfloorcur = bidfloorcur; + } + return imp; }); } diff --git a/test/spec/modules/taboolaBidAdapter_spec.js b/test/spec/modules/taboolaBidAdapter_spec.js index c0b16ac40fc..5bde75cd0b6 100644 --- a/test/spec/modules/taboolaBidAdapter_spec.js +++ b/test/spec/modules/taboolaBidAdapter_spec.js @@ -167,6 +167,45 @@ describe('Taboola Adapter', function () { expect(resData.imp[0].bidfloorcur).to.deep.equal('EUR'); }); + it('should pass bid floor', function () { + const bidRequest = { + ...defaultBidRequest, + params: {...commonBidRequest.params}, + getFloor: function() { + return { + currency: 'USD', + floor: 2.7, + } + } + }; + const res = spec.buildRequests([bidRequest], commonBidderRequest); + const resData = JSON.parse(res.data); + expect(resData.imp[0].bidfloor).to.deep.equal(2.7); + expect(resData.imp[0].bidfloorcur).to.deep.equal('USD'); + }); + + it('should pass bid floor even if they is a bid floor param', function () { + const optionalParams = { + bidfloor: 0.25, + bidfloorcur: 'EUR' + }; + + const bidRequest = { + ...defaultBidRequest, + params: {...commonBidRequest.params, ...optionalParams}, + getFloor: function() { + return { + currency: 'USD', + floor: 2.7, + } + } + }; + const res = spec.buildRequests([bidRequest], commonBidderRequest); + const resData = JSON.parse(res.data); + expect(resData.imp[0].bidfloor).to.deep.equal(2.7); + expect(resData.imp[0].bidfloorcur).to.deep.equal('USD'); + }); + it('should pass bidder timeout', function () { const bidderRequest = { ...commonBidderRequest, From 69a0f6a2be7a9d8eea7c3d0e742b9284eef0bba8 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 8 Dec 2022 19:04:28 +0000 Subject: [PATCH 191/367] Prebid 7.28.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f73e700aa42..d6484617a3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.28.0-pre", + "version": "7.28.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 7bbe18037b4..8d9b6a119df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.28.0-pre", + "version": "7.28.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From d4b449f19a3326a752b5d87df2ea9b05669bf1d5 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 8 Dec 2022 19:04:28 +0000 Subject: [PATCH 192/367] Increment version to 7.29.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d6484617a3b..006b8bcdcab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.28.0", + "version": "7.29.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 8d9b6a119df..5ee4cb728b1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.28.0", + "version": "7.29.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From bf5b15f4e532bc6a519185c8520b3368139c2b31 Mon Sep 17 00:00:00 2001 From: Bill Newman Date: Fri, 9 Dec 2022 12:58:53 +0200 Subject: [PATCH 193/367] Colossus Bid Adapter: update user sync (#9327) * add video&native traffic colossus ssp * Native obj validation * Native obj validation #2 * Added size field in requests * fixed test * fix merge conflicts * move to 3.0 * move to 3.0 * fix IE11 new URL issue * fix IE11 new URL issue * fix IE11 new URL issue * https for 3.0 * add https test * add ccp and schain features * fix test * sync with upstream, fix conflicts * Update colossussspBidAdapter.js remove commented code * Update colossussspBidAdapter.js lint fix * identity extensions * identity extensions * fix * fix * fix * fix * fix * add tests for user ids * fix * fix * fix * fix * fix * fix * fix * add gdpr support * add gdpr support * id5id support * Update colossussspBidAdapter.js add bidfloor parameter * Update colossussspBidAdapter.js check bidfloor * Update colossussspBidAdapter.js * Update colossussspBidAdapter.js * Update colossussspBidAdapter.js * Update colossussspBidAdapter_spec.js * use floor module * Revert "use floor module" This reverts commit f0c5c248627567e669d8eed4f2bb9a26a857e2ad. * use floor module * update to 5v * fix * add uid2 and bidFloor support * fix * add pbadslot support * fix conflicts * add onBidWon * refactor * add test for onBidWon() * fix * add group_id * Trigger circleci * fix * update user sync * fix window.location * fix test * updates * fix conflict * fix * updates * remove traffic param * add transactionId to request data for colossusssp adapter * Send tid in placements array * update user sync * updated tests * remove changes package-lock file * fix Co-authored-by: Vladislav Isaiko Co-authored-by: Aiholkin Co-authored-by: Mykhailo Yaremchuk --- modules/colossussspBidAdapter.js | 2 +- test/spec/modules/colossussspBidAdapter_spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/colossussspBidAdapter.js b/modules/colossussspBidAdapter.js index c1560680a6e..75e73ffda89 100644 --- a/modules/colossussspBidAdapter.js +++ b/modules/colossussspBidAdapter.js @@ -214,7 +214,7 @@ export const spec = { }, getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { - let syncType = syncOptions.iframeEnabled ? 'html' : 'hms.gif'; + let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image'; let syncUrl = G_URL_SYNC + `/${syncType}?pbjs=1`; if (gdprConsent && gdprConsent.consentString) { if (typeof gdprConsent.gdprApplies === 'boolean') { diff --git a/test/spec/modules/colossussspBidAdapter_spec.js b/test/spec/modules/colossussspBidAdapter_spec.js index 8b06868390a..71e94f0da32 100644 --- a/test/spec/modules/colossussspBidAdapter_spec.js +++ b/test/spec/modules/colossussspBidAdapter_spec.js @@ -299,8 +299,8 @@ describe('ColossussspAdapter', 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('hms.gif'); - expect(userSync[0].url).to.be.equal('https://sync.colossusssp.com/hms.gif?pbjs=1&gdpr=0&gdpr_consent=xxx&ccpa_consent=1YN-&coppa=0'); + expect(userSync[0].type).to.be.equal('image'); + expect(userSync[0].url).to.be.equal('https://sync.colossusssp.com/image?pbjs=1&gdpr=0&gdpr_consent=xxx&ccpa_consent=1YN-&coppa=0'); }); }); }); From 374aa26d592edc6906e8dc1f780d5fe1b2708148 Mon Sep 17 00:00:00 2001 From: pm-azhar-mulla <75726247+pm-azhar-mulla@users.noreply.github.com> Date: Tue, 13 Dec 2022 00:51:09 +0530 Subject: [PATCH 194/367] PubMatic Analytics Adapter:added parameters in logger call (#9328) * Logging floor related params in loger * Adding au and mt parameters in logger and tracker call * Added extra check Co-authored-by: pm-azhar-mulla Co-authored-by: pm-priyanka-deshmane --- modules/pubmaticAnalyticsAdapter.js | 43 ++++++++++++++- .../modules/pubmaticAnalyticsAdapter_spec.js | 52 ++++++++++++++++++- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/modules/pubmaticAnalyticsAdapter.js b/modules/pubmaticAnalyticsAdapter.js index c8dc7cef15d..cae94f6fe7b 100755 --- a/modules/pubmaticAnalyticsAdapter.js +++ b/modules/pubmaticAnalyticsAdapter.js @@ -30,6 +30,11 @@ const DEFAULT_PUBLISHER_ID = 0; const DEFAULT_PROFILE_ID = 0; const DEFAULT_PROFILE_VERSION_ID = 0; const enc = window.encodeURIComponent; +const MEDIATYPE = { + BANNER: 0, + VIDEO: 1, + NATIVE: 2 +} /// /////////// VARIABLES ////////////// let publisherId = DEFAULT_PUBLISHER_ID; // int: mandatory @@ -89,6 +94,7 @@ function copyRequiredBidDetails(bid) { 'status', () => NO_BID, // default a bid to NO_BID until response is recieved or bid is timed out 'finalSource as source', 'params', + 'floorData', 'adUnit', () => pick(bid, [ 'adUnitCode', 'transactionId', @@ -153,6 +159,7 @@ function parseBidResponse(bid) { 'bidId', 'mediaType', 'params', + 'floorData', 'mi', 'regexPattern', () => bid.regexPattern || undefined, 'partnerImpId', // partner impression ID @@ -243,17 +250,28 @@ function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid) { 'af': bid.bidResponse ? (bid.bidResponse.mediaType || undefined) : undefined, 'ocpm': bid.bidResponse ? (bid.bidResponse.originalCpm || 0) : 0, 'ocry': bid.bidResponse ? (bid.bidResponse.originalCurrency || CURRENCY_USD) : CURRENCY_USD, - 'piid': bid.bidResponse ? (bid.bidResponse.partnerImpId || EMPTY_STRING) : EMPTY_STRING + 'piid': bid.bidResponse ? (bid.bidResponse.partnerImpId || EMPTY_STRING) : EMPTY_STRING, + 'frv': (s2sBidders.indexOf(bid.bidder) > -1) ? undefined : (bid.bidResponse ? (bid.bidResponse.floorData ? bid.bidResponse.floorData.floorRuleValue : undefined) : undefined) }); }); return partnerBids; }, []) } +function getAdUnitAdFormats(adUnit) { + var af = adUnit ? Object.keys(adUnit.mediaTypes || {}).map(format => MEDIATYPE[format.toUpperCase()]) : []; + return af; +} + +function getAdUnit(adUnits, adUnitId) { + return adUnits.filter(adUnit => (adUnit.divID && adUnit.divID == adUnitId) || (adUnit.code == adUnitId))[0]; +} + function executeBidsLoggerCall(e, highestCpmBids) { let auctionId = e.auctionId; let referrer = config.getConfig('pageUrl') || cache.auctions[auctionId].referer || ''; let auctionCache = cache.auctions[auctionId]; + let floorData = auctionCache.floorData; let outputObj = { s: [] }; let pixelURL = END_POINT_BID_LOGGER; @@ -283,12 +301,21 @@ function executeBidsLoggerCall(e, highestCpmBids) { return 0; })(); + if (floorData) { + outputObj['fmv'] = floorData.floorRequestData ? floorData.floorRequestData.modelVersion || undefined : undefined; + outputObj['ft'] = floorData.floorResponseData ? (floorData.floorResponseData.enforcements.enforceJS == false ? 0 : 1) : undefined; + } + outputObj.s = Object.keys(auctionCache.adUnitCodes).reduce(function(slotsArray, adUnitId) { let adUnit = auctionCache.adUnitCodes[adUnitId]; + let origAdUnit = getAdUnit(auctionCache.origAdUnits, adUnitId) || {}; let slotObject = { 'sn': adUnitId, + 'au': origAdUnit.adUnitId || adUnitId, + 'mt': getAdUnitAdFormats(origAdUnit), 'sz': adUnit.dimensions.map(e => e[0] + 'x' + e[1]), - 'ps': gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestCpmBids.filter(bid => bid.adUnitCode === adUnitId)) + 'ps': gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestCpmBids.filter(bid => bid.adUnitCode === adUnitId)), + 'fskp': floorData ? (floorData.floorRequestData ? (floorData.floorRequestData.skipped == false ? 0 : 1) : undefined) : undefined, }; slotsArray.push(slotObject); return slotsArray; @@ -318,6 +345,7 @@ function executeBidWonLoggerCall(auctionId, adUnitId) { } const adapterName = getAdapterNameForAlias(winningBid.adapterCode || winningBid.bidder); + let origAdUnit = getAdUnit(cache.auctions[auctionId].origAdUnits, adUnitId) || {}; let pixelURL = END_POINT_WIN_BID_LOGGER; pixelURL += 'pubid=' + publisherId; pixelURL += '&purl=' + enc(config.getConfig('pageUrl') || cache.auctions[auctionId].referer || ''); @@ -327,6 +355,7 @@ function executeBidWonLoggerCall(auctionId, adUnitId) { pixelURL += '&pid=' + enc(profileId); pixelURL += '&pdvid=' + enc(profileVersionId); pixelURL += '&slot=' + enc(adUnitId); + pixelURL += '&au=' + enc(origAdUnit.adUnitId || adUnitId); pixelURL += '&pn=' + enc(adapterName); pixelURL += '&bc=' + enc(winningBid.bidderCode || winningBid.bidder); pixelURL += '&en=' + enc(winningBid.bidResponse.bidPriceUSD); @@ -358,6 +387,8 @@ function auctionInitHandler(args) { 'bidderDonePendingCount', () => args.bidderRequests.length, ]); cacheEntry.adUnitCodes = {}; + cacheEntry.floorData = {}; + cacheEntry.origAdUnits = args.adUnits; cacheEntry.referer = args.bidderRequests[0].refererInfo.topmostLocation; cache.auctions[args.auctionId] = cacheEntry; } @@ -372,6 +403,9 @@ function bidRequestedHandler(args) { }; } cache.auctions[args.auctionId].adUnitCodes[bid.adUnitCode].bids[bid.bidId] = [copyRequiredBidDetails(bid)]; + if (bid.floorData) { + cache.auctions[args.auctionId].floorData['floorRequestData'] = bid.floorData; + } }) } @@ -386,6 +420,11 @@ function bidResponseHandler(args) { bid = copyRequiredBidDetails(args); cache.auctions[args.auctionId].adUnitCodes[args.adUnitCode].bids[args.requestId].push(bid); } + + if (args.floorData) { + cache.auctions[args.auctionId].floorData['floorResponseData'] = args.floorData; + } + bid.adId = args.adId; bid.source = formatSource(bid.source || args.source); setBidStatus(bid, args); diff --git a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js index fa4519c84e1..4ad048fef9a 100755 --- a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js @@ -68,6 +68,14 @@ const BID = { 'hb_size': '640x480', 'hb_source': 'server' }, + 'floorData': { + 'cpmAfterAdjustments': 6.3, + 'enforcements': {'enforceJS': true, 'enforcePBS': false, 'floorDeals': false, 'bidAdjustment': true}, + 'floorCurrency': 'USD', + 'floorRule': 'banner', + 'floorRuleValue': 1.1, + 'floorValue': 1.1 + }, getStatusCode() { return 1; } @@ -200,7 +208,18 @@ const MOCK = { 'bidId': '3bd4ebb1c900e2', 'seatBidId': 'aaaa-bbbb-cccc-dddd', 'bidderRequestId': '1be65d7958826a', - 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa' + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa', + 'floorData': { + 'fetchStatus': 'success', + 'floorMin': undefined, + 'floorProvider': 'pubmatic', + 'location': 'fetch', + 'modelTimestamp': undefined, + 'modelVersion': 'floorModelTest', + 'modelWeight': undefined, + 'skipRate': 0, + 'skipped': false + } } ], 'auctionStart': 1519149536560, @@ -343,10 +362,13 @@ describe('pubmatic analytics adapter', function () { expect(data.orig).to.equal('www.test.com'); expect(data.tst).to.equal(1519767016); expect(data.tgid).to.equal(15); + expect(data.fmv).to.equal('floorModelTest'); + expect(data.ft).to.equal(1); 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].fskp).to.equal(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); @@ -370,8 +392,10 @@ describe('pubmatic analytics adapter', function () { 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'); + expect(data.s[0].ps[0].frv).to.equal(undefined); // slot 2 expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); + expect(data.s[1].fskp).to.equal(0); 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); @@ -397,6 +421,7 @@ describe('pubmatic analytics adapter', function () { 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'); + expect(data.s[1].ps[0].frv).to.equal(undefined); // tracker slot1 let firstTracker = requests[0].url; @@ -446,11 +471,14 @@ describe('pubmatic analytics adapter', function () { let data = getLoggerJsonFromRequest(request.requestBody); expect(data.pubid).to.equal('9999'); expect(data.pid).to.equal('1111'); + expect(data.fmv).to.equal('floorModelTest'); + expect(data.ft).to.equal(1); 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].fskp).to.equal(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); @@ -464,6 +492,7 @@ describe('pubmatic analytics adapter', function () { 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'); + expect(data.s[1].ps[0].frv).to.equal(undefined); // tracker slot1 let firstTracker = requests[0].url; expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt'); @@ -515,6 +544,8 @@ describe('pubmatic analytics adapter', function () { 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.fmv).to.equal('floorModelTest'); + expect(data.ft).to.equal(1); expect(data.s).to.be.an('array'); expect(data.s.length).to.equal(2); // slot 1 @@ -563,6 +594,7 @@ describe('pubmatic analytics adapter', function () { 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].fskp).to.equal(0); 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); @@ -586,6 +618,7 @@ describe('pubmatic analytics adapter', function () { 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'); + expect(data.s[1].ps[0].frv).to.equal(undefined); }); it('Logger: post-timeout check without bid response', function() { @@ -643,6 +676,7 @@ describe('pubmatic analytics adapter', function () { 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].fskp).to.equal(0); 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); @@ -667,6 +701,7 @@ describe('pubmatic analytics adapter', function () { 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'); + expect(data.s[1].ps[0].frv).to.equal(undefined); }); it('Logger: currency conversion check', function() { @@ -748,6 +783,7 @@ describe('pubmatic analytics adapter', function () { expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999'); let data = getLoggerJsonFromRequest(request.requestBody); expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); + expect(data.s[1].fskp).to.equal(0); 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); @@ -772,6 +808,7 @@ describe('pubmatic analytics adapter', function () { 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'); + expect(data.s[1].ps[0].frv).to.equal(undefined); expect(data.dvc).to.deep.equal({'plt': 2}); // respective tracker slot let firstTracker = requests[1].url; @@ -829,6 +866,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].ocpm).to.equal(1.52); expect(data.s[1].ps[0].ocry).to.equal('USD'); expect(data.dvc).to.deep.equal({'plt': 1}); + expect(data.s[1].ps[0].frv).to.equal(undefined); // respective tracker slot let firstTracker = requests[1].url; expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt'); @@ -856,6 +894,7 @@ describe('pubmatic analytics adapter', function () { expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999'); let data = getLoggerJsonFromRequest(request.requestBody); expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); + expect(data.s[1].fskp).to.equal(0); 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); @@ -880,6 +919,7 @@ describe('pubmatic analytics adapter', function () { 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'); + expect(data.s[1].ps[0].frv).to.equal(undefined); // respective tracker slot let firstTracker = requests[1].url; expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt'); @@ -979,11 +1019,14 @@ describe('pubmatic analytics adapter', function () { expect(data.orig).to.equal('www.test.com'); expect(data.tst).to.equal(1519767016); expect(data.tgid).to.equal(15); + expect(data.fmv).to.equal('floorModelTest'); + expect(data.ft).to.equal(1); 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].fskp).to.equal(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); @@ -1007,9 +1050,11 @@ describe('pubmatic analytics adapter', function () { 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'); + expect(data.s[0].ps[0].frv).to.equal(1.1); // slot 2 expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); + expect(data.s[1].fskp).to.equal(0); 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); @@ -1035,6 +1080,7 @@ describe('pubmatic analytics adapter', function () { 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'); + expect(data.s[1].ps[0].frv).to.equal(undefined); // tracker slot1 let firstTracker = requests[0].url; @@ -1091,11 +1137,14 @@ describe('pubmatic analytics adapter', function () { expect(data.orig).to.equal('www.test.com'); expect(data.tst).to.equal(1519767016); expect(data.tgid).to.equal(15); + expect(data.fmv).to.equal('floorModelTest'); + expect(data.ft).to.equal(1); 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].fskp).to.equal(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); @@ -1119,6 +1168,7 @@ describe('pubmatic analytics adapter', function () { 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'); + expect(data.s[0].ps[0].frv).to.equal(1.1); // slot 2 expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); From 05d32b281cd1d2d7c1fe49509b1503d59b9c8af2 Mon Sep 17 00:00:00 2001 From: Malkov Mikhail Date: Mon, 12 Dec 2022 22:59:03 +0300 Subject: [PATCH 195/367] Nextmillenium bid adapter: Collection of statistics data (#9265) * changed name company * changed name company in test * Added processing of a new group_id parameter * Added processing of a new group_id parameter * changed check parameters * fixed lint remarks * added test * fixed bug - lint * changed test * changed test - 2 * fixed bug - adapter * added logic for getting ad impressions * Collecting timeouts data * Collecting resaponses and no_bids data * changed a name function * added event bidRequested * added event bidRequested * added function initialization events * fixed bug * save * added tests * Added processing of the disabledSendingStatisticData parameter, which disables sending statistics data * changed the name of the variables --- modules/nextMillenniumBidAdapter.js | 125 +++++++++++++++- .../modules/nextMillenniumBidAdapter_spec.js | 133 ++++++++++++++++++ 2 files changed, 257 insertions(+), 1 deletion(-) diff --git a/modules/nextMillenniumBidAdapter.js b/modules/nextMillenniumBidAdapter.js index 802a8ac25b0..cf732d343e5 100644 --- a/modules/nextMillenniumBidAdapter.js +++ b/modules/nextMillenniumBidAdapter.js @@ -14,6 +14,7 @@ import { import CONSTANTS from '../src/constants.json'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import {config} from '../src/config.js'; import * as events from '../src/events.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; @@ -22,6 +23,7 @@ import { getRefererInfo } from '../src/refererDetection.js'; const BIDDER_CODE = 'nextMillennium'; const ENDPOINT = 'https://pbs.nextmillmedia.com/openrtb2/auction'; const TEST_ENDPOINT = 'https://test.pbs.nextmillmedia.com/openrtb2/auction'; +const REPORT_ENDPOINT = 'https://report2.hb.brainlyads.com/statistics/metric'; const SYNC_ENDPOINT = 'https://cookies.nextmillmedia.com/sync?'; const TIME_TO_LIVE = 360; const VIDEO_PARAMS = [ @@ -29,11 +31,14 @@ const VIDEO_PARAMS = [ 'playbackmethod', 'protocols', 'startdelay' ]; +const sendingDataStatistic = initSendingDataStatistic(); +events.on(CONSTANTS.EVENTS.AUCTION_INIT, auctionInitHandler); + const EXPIRENCE_WURL = 20 * 60000; const wurlMap = {}; +cleanWurl(); events.on(CONSTANTS.EVENTS.BID_WON, bidWonHandler); -cleanWurl(); export const spec = { code: BIDDER_CODE, @@ -135,6 +140,7 @@ export const spec = { const urlParameters = parseUrl(getWindowTop().location.href).search; const isTest = urlParameters['pbs'] && urlParameters['pbs'] === 'test'; + const params = bid.params; requests.push({ method: 'POST', @@ -146,6 +152,7 @@ export const spec = { }, bidId, + params, auctionId, }); }); @@ -160,6 +167,7 @@ export const spec = { _each(response.seatbid, (resp) => { _each(resp.bid, (bid) => { const requestId = bidRequest.bidId; + const params = bidRequest.params; const auctionId = bidRequest.auctionId; const wurl = deepAccess(bid, 'ext.prebid.events.win'); addWurl({auctionId, requestId, wurl}); @@ -168,6 +176,7 @@ export const spec = { const bidResponse = { requestId, + params, cpm: bid.price, width: bid.w, height: bid.h, @@ -217,6 +226,41 @@ export const spec = { return pixels; }, + + getUrlPixelMetric(eventName, bid) { + const bidder = bid.bidder || bid.bidderCode; + if (bidder != BIDDER_CODE) return; + + let params; + if (bid.params) { + params = Array.isArray(bid.params) ? bid.params : [bid.params]; + } else { + if (Array.isArray(bid.bids)) params = bid.bids.map(bidI => bidI.params); + }; + + if (!params.length) return; + + const placementIdsArray = []; + const groupIdsArray = []; + params.forEach(paramsI => { + if (paramsI.group_id) { + groupIdsArray.push(paramsI.group_id); + } else { + if (paramsI.placement_id) placementIdsArray.push(paramsI.placement_id); + }; + }); + + const placementIds = (placementIdsArray.length && `&placements=${placementIdsArray.join(';')}`) || ''; + const groupIds = (groupIdsArray.length && `&groups=${groupIdsArray.join(';')}`) || ''; + + if (!(groupIds || placementIds)) { + return; + }; + + const url = `${REPORT_ENDPOINT}?event=${eventName}&bidder=${bidder}&source=pbjs${groupIds}${placementIds}`; + + return url; + }, }; function getAdEl(bid) { @@ -338,6 +382,10 @@ function bidWonHandler(bid) { }; } +function auctionInitHandler() { + sendingDataStatistic.initEvents(); +} + function cleanWurl() { const dateNow = Date.now(); Object.keys(wurlMap).forEach(key => { @@ -349,4 +397,79 @@ function cleanWurl() { setTimeout(cleanWurl, 60000); } +function initSendingDataStatistic() { + class SendingDataStatistic { + eventNames = [ + CONSTANTS.EVENTS.BID_TIMEOUT, + CONSTANTS.EVENTS.BID_RESPONSE, + CONSTANTS.EVENTS.BID_REQUESTED, + CONSTANTS.EVENTS.NO_BID, + ]; + + disabledSending = false; + enabledSending = false; + eventHendlers = {}; + + initEvents() { + this.disabledSending = !!config.getBidderConfig()?.nextMillennium?.disabledSendingStatisticData; + if (this.disabledSending) { + this.removeEvents(); + } else { + this.createEvents(); + }; + } + + createEvents() { + if (this.enabledSending) return; + + this.enabledSending = true; + for (let eventName of this.eventNames) { + if (!this.eventHendlers[eventName]) { + this.eventHendlers[eventName] = this.eventHandler(eventName); + }; + + events.on(eventName, this.eventHendlers[eventName]); + }; + } + + removeEvents() { + if (!this.enabledSending) return; + + this.enabledSending = false; + for (let eventName of this.eventNames) { + if (!this.eventHendlers[eventName]) continue; + + events.off(eventName, this.eventHendlers[eventName]); + }; + } + + eventHandler(eventName) { + const eventHandlerFunc = this.getEventHandler(eventName); + if (eventName == CONSTANTS.EVENTS.BID_TIMEOUT) { + return bids => { + if (this.disabledSending || !Array.isArray(bids)) return; + + for (let bid of bids) { + eventHandlerFunc(bid); + }; + } + }; + + return eventHandlerFunc; + } + + getEventHandler(eventName) { + return bid => { + if (this.disabledSending) return; + + const url = spec.getUrlPixelMetric(eventName, bid); + if (!url) return; + triggerPixel(url); + }; + } + }; + + return new SendingDataStatistic(); +} + registerBidder(spec); diff --git a/test/spec/modules/nextMillenniumBidAdapter_spec.js b/test/spec/modules/nextMillenniumBidAdapter_spec.js index 2b5ae801489..3094c1349f7 100644 --- a/test/spec/modules/nextMillenniumBidAdapter_spec.js +++ b/test/spec/modules/nextMillenniumBidAdapter_spec.js @@ -276,4 +276,137 @@ describe('nextMillenniumBidAdapterTests', function() { expect(bid.height).to.equal(250); expect(bid.currency).to.equal('USD'); }); + + it('Check function of getting URL for sending statistics data', function() { + const dataForTests = [ + { + eventName: 'bidRequested', + bid: { + bidderCode: 'appnexus', + bids: [{bidder: 'appnexus', params: {}}], + }, + + expected: undefined, + }, + + { + eventName: 'bidRequested', + bid: { + bidderCode: 'appnexus', + bids: [{bidder: 'appnexus', params: {placement_id: '807'}}], + }, + + expected: undefined, + }, + + { + eventName: 'bidRequested', + bid: { + bidderCode: 'nextMillennium', + bids: [{bidder: 'nextMillennium', params: {placement_id: '807'}}], + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidRequested&bidder=nextMillennium&source=pbjs&placements=807', + }, + + { + eventName: 'bidRequested', + bid: { + bidderCode: 'nextMillennium', + bids: [ + {bidder: 'nextMillennium', params: {placement_id: '807'}}, + {bidder: 'nextMillennium', params: {placement_id: '111'}}, + ], + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidRequested&bidder=nextMillennium&source=pbjs&placements=807;111', + }, + + { + eventName: 'bidRequested', + bid: { + bidderCode: 'nextMillennium', + bids: [{bidder: 'nextMillennium', params: {placement_id: '807', group_id: '123'}}], + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidRequested&bidder=nextMillennium&source=pbjs&groups=123', + }, + + { + eventName: 'bidRequested', + bid: { + bidderCode: 'nextMillennium', + bids: [ + {bidder: 'nextMillennium', params: {placement_id: '807', group_id: '123'}}, + {bidder: 'nextMillennium', params: {group_id: '456'}}, + {bidder: 'nextMillennium', params: {placement_id: '222'}}, + ], + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidRequested&bidder=nextMillennium&source=pbjs&groups=123;456&placements=222', + }, + + { + eventName: 'bidResponse', + bid: { + bidderCode: 'appnexus', + }, + + expected: undefined, + }, + + { + eventName: 'bidResponse', + bid: { + bidderCode: 'nextMillennium', + params: {placement_id: '807'}, + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidResponse&bidder=nextMillennium&source=pbjs&placements=807', + }, + + { + eventName: 'noBid', + bid: { + bidder: 'appnexus', + }, + + expected: undefined, + }, + + { + eventName: 'noBid', + bid: { + bidder: 'nextMillennium', + params: {placement_id: '807'}, + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=noBid&bidder=nextMillennium&source=pbjs&placements=807', + }, + + { + eventName: 'bidTimeout', + bid: { + bidder: 'appnexus', + }, + + expected: undefined, + }, + + { + eventName: 'bidTimeout', + bid: { + bidder: 'nextMillennium', + params: {placement_id: '807'}, + }, + + expected: 'https://report2.hb.brainlyads.com/statistics/metric?event=bidTimeout&bidder=nextMillennium&source=pbjs&placements=807', + }, + ]; + + for (let {eventName, bid, expected} of dataForTests) { + const url = spec.getUrlPixelMetric(eventName, bid); + expect(url).to.equal(expected); + }; + }) }); From c1a193a116086583054fff46af67d0dbb386277f Mon Sep 17 00:00:00 2001 From: Karim Mourra Date: Mon, 12 Dec 2022 15:18:21 -0500 Subject: [PATCH 196/367] Video Module: Ad Queueing (#9226) * adds queue coordinator * tests module * test setAdTag * tests integration * updates examples * documents the event * loads get queued always * updates tests * decouples register from init * updates tests * Revert "updates tests" This reverts commit 1616dfad2bba34a10b3f20fb5680baea7ce11fa1. * updates tests --- .../videoModule/jwplayer/bidMarkedAsUsed.html | 6 +- .../videoModule/jwplayer/eventListeners.html | 7 +- .../jwplayer/gamAdServerMediation.html | 6 +- .../videoModule/jwplayer/mediaMetadata.html | 3 +- .../videoModule/jwplayer/playlist.html | 3 +- .../videoModule/videojs/bidMarkedAsUsed.html | 5 +- .../videoModule/videojs/eventListeners.html | 4 + .../videojs/gamAdServerMediation.html | 3 +- .../videoModule/videojs/playlist.html | 4 +- .../constants/{enums.js => constants.js} | 2 + libraries/video/constants/events.js | 1 + libraries/video/shared/helpers.js | 5 + libraries/video/shared/parentModule.js | 1 - modules/jwplayerVideoProvider.js | 2 +- modules/videoModule/adQueue.js | 63 +++++++ modules/videoModule/addingSubmodule.md | 7 + modules/videoModule/coreVideo.js | 6 + modules/videoModule/index.js | 35 ++-- modules/videojsVideoProvider.js | 2 +- test/spec/modules/videoModule/adQueue_spec.js | 172 ++++++++++++++++++ test/spec/modules/videoModule/pbVideo_spec.js | 34 ++-- .../videoModule/shared/parentModule_spec.js | 1 - .../submodules/jwplayerVideoProvider_spec.js | 2 +- 23 files changed, 325 insertions(+), 49 deletions(-) rename libraries/video/constants/{enums.js => constants.js} (65%) create mode 100644 libraries/video/shared/helpers.js create mode 100644 modules/videoModule/adQueue.js create mode 100644 test/spec/modules/videoModule/adQueue_spec.js diff --git a/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html b/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html index 542cab4202e..044b4295e67 100644 --- a/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html +++ b/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html @@ -76,10 +76,6 @@ console.log('player setup failed: ', e); }); - pbjs.onEvent('videoPlaybackRequest', (e) => { - pbjs.requestBids(adUnits); - }); - pbjs.onEvent('videoBidError', e => { console.log('An Ad Error came from a Bid: ', e); }); @@ -87,6 +83,8 @@ pbjs.onEvent('videoBidImpression', e => { console.log('An Ad Impression came from a Bid: ', e); }); + + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/jwplayer/eventListeners.html b/integrationExamples/videoModule/jwplayer/eventListeners.html index b4f5aaa5443..0b43ff44d6c 100644 --- a/integrationExamples/videoModule/jwplayer/eventListeners.html +++ b/integrationExamples/videoModule/jwplayer/eventListeners.html @@ -87,7 +87,6 @@ pbjs.onEvent('videoPlaybackRequest', (e) => { console.log('videos pb playbackRequest: ', e); - pbjs.requestBids(adUnits); }); pbjs.onEvent('videoAutostartBlocked', (e) => { @@ -222,6 +221,10 @@ console.log('videos pb auction ad load attempt: ', e); }); + pbjs.onEvent('videoAuctionAdLoadQueued', (e) => { + console.log('videos pb auction ad load queued: ', e); + }); + pbjs.onEvent('videoAuctionAdLoadAttempt', event => { console.log('The Video Module is attempting to load an ad into the player! \n', event); }); @@ -233,6 +236,8 @@ pbjs.onEvent('videoBidError', event => { console.log('The ad error resulted from a bid! \n', event); }); + + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html b/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html index 4612d03f336..296a3265bd1 100644 --- a/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html +++ b/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html @@ -94,10 +94,6 @@ console.log('player setup failed: ', e); }); - pbjs.onEvent('videoPlaybackRequest', (e) => { - pbjs.requestBids(adUnits); - }); - pbjs.onEvent('videoAdRequest', (e) => { console.log('videos pb ad request: ', e); }); @@ -109,6 +105,8 @@ pbjs.onEvent('videoBidImpression', e => { console.log('An Ad Impression came from a Bid: ', e); }); + + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/jwplayer/mediaMetadata.html b/integrationExamples/videoModule/jwplayer/mediaMetadata.html index 97e35c4de0d..815f5c4d6d7 100644 --- a/integrationExamples/videoModule/jwplayer/mediaMetadata.html +++ b/integrationExamples/videoModule/jwplayer/mediaMetadata.html @@ -56,7 +56,6 @@ pbjs.onEvent('videoSetupComplete', e => { console.log('player setup complete: ', e); - pbjs.requestBids(adUnits); }); pbjs.onEvent('videoSetupFailed', e => { @@ -66,6 +65,8 @@ pbjs.onEvent('videoContentLoaded', (e) => { console.log('videos pb contentLoaded: ', e); }); + + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/jwplayer/playlist.html b/integrationExamples/videoModule/jwplayer/playlist.html index eb9a9b12700..b77a1ec05fc 100644 --- a/integrationExamples/videoModule/jwplayer/playlist.html +++ b/integrationExamples/videoModule/jwplayer/playlist.html @@ -97,7 +97,6 @@ // request a bid when media is loaded pbjs.onEvent('videoContentLoaded', (e) => { console.log('videos pb contentLoaded: ', e); - pbjs.requestBids(adUnits); }); pbjs.onEvent('videoComplete', (e) => { @@ -107,6 +106,8 @@ pbjs.onEvent('videoPlaylistComplete', (e) => { console.log('videos pb playlistComplete: ', e); }); + + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html b/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html index 3c21130e8f5..b645a58a4fc 100644 --- a/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html +++ b/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html @@ -101,10 +101,6 @@ console.log('player setup failed: ', e); }); - pbjs.onEvent('videoContentLoaded', (e) => { - pbjs.requestBids(adUnits); - }); - pbjs.onEvent('videoBidError', e => { console.log('An Ad Error came from a Bid: ', e); }); @@ -113,6 +109,7 @@ console.log('An Ad Impression came from a Bid: ', e); }); + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/videojs/eventListeners.html b/integrationExamples/videoModule/videojs/eventListeners.html index 63de878715f..16edaf4da41 100644 --- a/integrationExamples/videoModule/videojs/eventListeners.html +++ b/integrationExamples/videoModule/videojs/eventListeners.html @@ -209,6 +209,10 @@ console.log('videos pb auction ad load attempt: ', e); }); + pbjs.onEvent('videoAuctionAdLoadQueued', (e) => { + console.log('videos pb auction ad load queued: ', e); + }); + pbjs.onEvent('videoAuctionAdLoadAbort', (e) => { console.log('videos pb auction ad load attempt: ', e); }); diff --git a/integrationExamples/videoModule/videojs/gamAdServerMediation.html b/integrationExamples/videoModule/videojs/gamAdServerMediation.html index 72deba861bf..9efd77e9681 100644 --- a/integrationExamples/videoModule/videojs/gamAdServerMediation.html +++ b/integrationExamples/videoModule/videojs/gamAdServerMediation.html @@ -96,8 +96,6 @@ pbjs.addAdUnits(adUnits); - pbjs.requestBids(adUnits); - pbjs.onEvent('videoSetupComplete', e => { // Load media with its Metadata when the video player is done instantiating. videojs('player').loadMedia({ @@ -125,6 +123,7 @@ console.log('An Ad Impression came from a Bid: ', e); }); + pbjs.requestBids(adUnits); }); diff --git a/integrationExamples/videoModule/videojs/playlist.html b/integrationExamples/videoModule/videojs/playlist.html index a9354e06c83..a9e3d1bc99b 100644 --- a/integrationExamples/videoModule/videojs/playlist.html +++ b/integrationExamples/videoModule/videojs/playlist.html @@ -126,15 +126,15 @@ console.log('videos pb playlist: ', e); }); - // request a bid when media is loaded pbjs.onEvent('videoContentLoaded', (e) => { console.log('videos pb contentLoaded: ', e); - pbjs.requestBids(adUnits); }); pbjs.onEvent('videoComplete', (e) => { console.log('videos pb complete: ', e); }); + + pbjs.requestBids(adUnits); }); diff --git a/libraries/video/constants/enums.js b/libraries/video/constants/constants.js similarity index 65% rename from libraries/video/constants/enums.js rename to libraries/video/constants/constants.js index b0755020580..55e3785ccc2 100644 --- a/libraries/video/constants/enums.js +++ b/libraries/video/constants/constants.js @@ -1,3 +1,5 @@ +export const videoKey = 'video'; + export const PLAYBACK_MODE = { VOD: 0, LIVE: 1, diff --git a/libraries/video/constants/events.js b/libraries/video/constants/events.js index 5be594b1b48..b7932adf621 100644 --- a/libraries/video/constants/events.js +++ b/libraries/video/constants/events.js @@ -52,6 +52,7 @@ export const allVideoEvents = [ ]; export const AUCTION_AD_LOAD_ATTEMPT = 'auctionAdLoadAttempt'; +export const AUCTION_AD_LOAD_QUEUED = 'auctionAdLoadQueued'; export const AUCTION_AD_LOAD_ABORT = 'auctionAdLoadAbort'; export const BID_IMPRESSION = 'bidImpression'; export const BID_ERROR = 'bidError'; diff --git a/libraries/video/shared/helpers.js b/libraries/video/shared/helpers.js new file mode 100644 index 00000000000..1b87f3bf1f3 --- /dev/null +++ b/libraries/video/shared/helpers.js @@ -0,0 +1,5 @@ +import { videoKey } from '../constants/constants.js' + +export function getExternalVideoEventName(eventName) { + return videoKey + eventName.replace(/^./, eventName[0].toUpperCase()); +} diff --git a/libraries/video/shared/parentModule.js b/libraries/video/shared/parentModule.js index e96113fd894..06c71ebd75b 100644 --- a/libraries/video/shared/parentModule.js +++ b/libraries/video/shared/parentModule.js @@ -72,7 +72,6 @@ export function SubmoduleBuilder(submoduleDirectory_, sharedUtils_) { } const submodule = submoduleFactory(config, sharedUtils); - submodule && submodule.init && submodule.init(); return submodule; } diff --git a/modules/jwplayerVideoProvider.js b/modules/jwplayerVideoProvider.js index d606e8121a7..379d8063c42 100644 --- a/modules/jwplayerVideoProvider.js +++ b/modules/jwplayerVideoProvider.js @@ -7,7 +7,7 @@ import { AUTOSTART_BLOCKED, PLAY_ATTEMPT_FAILED, CONTENT_LOADED, PLAY, PAUSE, BUFFER, TIME, SEEK_START, SEEK_END, MUTE, VOLUME, RENDITION_UPDATE, ERROR, COMPLETE, PLAYLIST_COMPLETE, FULLSCREEN, PLAYER_RESIZE, VIEWABLE, CAST } from '../libraries/video/constants/events.js'; -import { PLAYBACK_MODE } from '../libraries/video/constants/enums.js'; +import { PLAYBACK_MODE } from '../libraries/video/constants/constants.js'; import stateFactory from '../libraries/video/shared/state.js'; import { JWPLAYER_VENDOR } from '../libraries/video/constants/vendorCodes.js'; import { getEventHandler } from '../libraries/video/shared/eventHandler.js'; diff --git a/modules/videoModule/adQueue.js b/modules/videoModule/adQueue.js new file mode 100644 index 00000000000..a6da3752f6e --- /dev/null +++ b/modules/videoModule/adQueue.js @@ -0,0 +1,63 @@ +import { AD_BREAK_END, AUCTION_AD_LOAD_ATTEMPT, AUCTION_AD_LOAD_QUEUED, SETUP_COMPLETE } from '../../libraries/video/constants/events.js' +import { getExternalVideoEventName } from '../../libraries/video/shared/helpers.js' + +export function AdQueueCoordinator(videoCore, pbEvents) { + const storage = {}; + + function registerProvider(divId) { + storage[divId] = []; + videoCore.onEvents([SETUP_COMPLETE], onSetupComplete, divId); + } + + function queueAd(adTagUrl, divId, options) { + const queue = storage[divId]; + if (queue) { + queue.push({adTagUrl, options}); + triggerEvent(AUCTION_AD_LOAD_QUEUED, adTagUrl, options); + } else { + loadAd(divId, adTagUrl, options); + } + } + + return { + registerProvider, + queueAd + }; + + function onSetupComplete(eventName, eventPayload) { + const divId = eventPayload.divId; + videoCore.offEvents([SETUP_COMPLETE], onSetupComplete, divId); + loadQueuedAd(divId); + } + + function onAdBreakEnd(eventName, eventPayload) { + loadQueuedAd(eventPayload.divId); + } + + function loadQueuedAd(divId) { + videoCore.offEvents([AD_BREAK_END], onAdBreakEnd, divId); + const adQueue = storage[divId]; + if (!adQueue) { + return; + } + + if (!adQueue.length) { + delete storage[divId]; + return; + } + + const queuedAd = adQueue.shift(); + videoCore.onEvents([AD_BREAK_END], onAdBreakEnd, divId); + loadAd(divId, queuedAd.adTagUrl, queuedAd.options); + } + + function loadAd(divId, adTagUrl, options) { + triggerEvent(AUCTION_AD_LOAD_ATTEMPT, adTagUrl, options); + videoCore.setAdTagUrl(adTagUrl, divId, options); + } + + function triggerEvent(eventName, adTagUrl, options) { + const payload = Object.assign({ adTagUrl }, options); + pbEvents.emit(getExternalVideoEventName(eventName), payload); + } +} diff --git a/modules/videoModule/addingSubmodule.md b/modules/videoModule/addingSubmodule.md index 874718be1a7..2f880fdef3a 100644 --- a/modules/videoModule/addingSubmodule.md +++ b/modules/videoModule/addingSubmodule.md @@ -481,6 +481,13 @@ No additional params. | adTagUrl | string | The URL for the ad tag associated with the given ad event | | adUnitCode | string | Unique identifier that was used when creating the ad unit. | +###### AUCTION_AD_LOAD_QUEUED + +| argument name | type | description | +| ------------- | ---- | ----------- | +| adTagUrl | string | The URL for the ad tag associated with the given ad event | +| adUnitCode | string | Unique identifier that was used when creating the ad unit. | + ###### AUCTION_AD_LOAD_ABORT | argument name | type | description | diff --git a/modules/videoModule/coreVideo.js b/modules/videoModule/coreVideo.js index c06482b0b36..ce66acc2b02 100644 --- a/modules/videoModule/coreVideo.js +++ b/modules/videoModule/coreVideo.js @@ -127,6 +127,11 @@ export function VideoCore(parentModule_) { } catch (e) {} } + function initProvider(divId) { + const submodule = parentModule.getSubmodule(divId); + submodule && submodule.init && submodule.init(); + } + /** * @name VideoCore#getOrtbVideo * @summary Obtains the oRTB Video params for a player's current video session. @@ -208,6 +213,7 @@ export function VideoCore(parentModule_) { return { registerProvider, + initProvider, getOrtbVideo, getOrtbContent, setAdTagUrl, diff --git a/modules/videoModule/index.js b/modules/videoModule/index.js index 33ce3248d91..fb3c621918d 100644 --- a/modules/videoModule/index.js +++ b/modules/videoModule/index.js @@ -5,23 +5,31 @@ import { mergeDeep } from '../../src/utils.js'; import { getGlobal } from '../../src/prebidGlobal.js'; import CONSTANTS from '../../src/constants.json'; import { - videoEvents, AUCTION_AD_LOAD_ATTEMPT, AD_IMPRESSION, AD_ERROR, BID_IMPRESSION, BID_ERROR, AUCTION_AD_LOAD_ABORT + videoEvents, + AUCTION_AD_LOAD_ATTEMPT, + AD_IMPRESSION, + AD_ERROR, + BID_IMPRESSION, + BID_ERROR, + AUCTION_AD_LOAD_ABORT, + AUCTION_AD_LOAD_QUEUED } from '../../libraries/video/constants/events.js' import { PLACEMENT } from '../../libraries/video/constants/ortb.js'; +import { videoKey } from '../../libraries/video/constants/constants.js' import { videoCoreFactory } from './coreVideo.js'; import { gamSubmoduleFactory } from './gamAdServerSubmodule.js'; import { videoImpressionVerifierFactory } from './videoImpressionVerifier.js'; - -const videoKey = 'video'; +import { AdQueueCoordinator } from './adQueue.js'; +import { getExternalVideoEventName } from '../../libraries/video/shared/helpers.js' const allVideoEvents = Object.keys(videoEvents).map(eventKey => videoEvents[eventKey]); -events.addEvents(allVideoEvents.concat([AUCTION_AD_LOAD_ATTEMPT, AUCTION_AD_LOAD_ABORT, BID_IMPRESSION, BID_ERROR]).map(getExternalVideoEventName)); +events.addEvents(allVideoEvents.concat([AUCTION_AD_LOAD_ATTEMPT, AUCTION_AD_LOAD_QUEUED, AUCTION_AD_LOAD_ABORT, BID_IMPRESSION, BID_ERROR]).map(getExternalVideoEventName)); /** * This module adds User Video support to prebid.js * @module modules/videoModule */ -export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvents_, gamAdServerFactory_, videoImpressionVerifierFactory_) { +export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvents_, gamAdServerFactory_, videoImpressionVerifierFactory_, adQueueCoordinator_) { const videoCore = videoCore_; const getConfig = getConfig_; const pbGlobal = pbGlobal_; @@ -29,6 +37,7 @@ export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvent const pbEvents = pbEvents_; const videoEvents = videoEvents_; const gamAdServerFactory = gamAdServerFactory_; + const adQueueCoordinator = adQueueCoordinator_; let gamSubmodule; let mainContentDivId; let contentEnrichmentEnabled = true; @@ -40,10 +49,13 @@ export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvent videoImpressionVerifier = videoImpressionVerifierFactory(!!cache); getConfig(videoKey, ({ video }) => { video.providers.forEach(provider => { + const divId = provider.divId; videoCore.registerProvider(provider); + adQueueCoordinator.registerProvider(divId); + videoCore.initProvider(divId); videoCore.onEvents(videoEvents, (type, payload) => { pbEvents.emit(getExternalVideoEventName(type), payload); - }, provider.divId); + }, divId); const adServerConfig = provider.adServer; if (!gamSubmodule && adServerConfig) { @@ -199,9 +211,7 @@ export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvent // options: adXml, winner, adUnitCode, function loadAdTag(adTagUrl, divId, options) { - const payload = Object.assign({ adTagUrl }, options); - pbEvents.emit(getExternalVideoEventName(AUCTION_AD_LOAD_ATTEMPT), payload); - videoCore.setAdTagUrl(adTagUrl, divId, options); + adQueueCoordinator.queueAd(adTagUrl, divId, options); } function triggerVideoBidEvent(eventName, adEventPayload) { @@ -230,15 +240,12 @@ export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvent export function pbVideoFactory() { const videoCore = videoCoreFactory(); + const adQueueCoordinator = AdQueueCoordinator(videoCore, events); const pbGlobal = getGlobal(); - const pbVideo = PbVideo(videoCore, config.getConfig, pbGlobal, events, allVideoEvents, gamSubmoduleFactory, videoImpressionVerifierFactory); + const pbVideo = PbVideo(videoCore, config.getConfig, pbGlobal, events, allVideoEvents, gamSubmoduleFactory, videoImpressionVerifierFactory, adQueueCoordinator); pbVideo.init(); pbGlobal.videoModule = pbVideo; return pbVideo; } -function getExternalVideoEventName(eventName) { - return videoKey + eventName.replace(/^./, eventName[0].toUpperCase()); -} - pbVideoFactory(); diff --git a/modules/videojsVideoProvider.js b/modules/videojsVideoProvider.js index a142e0fbb84..cc17758bd72 100644 --- a/modules/videojsVideoProvider.js +++ b/modules/videojsVideoProvider.js @@ -11,7 +11,7 @@ import { import { VIDEO_JS_VENDOR } from '../libraries/video/constants/vendorCodes.js'; import { submodule } from '../src/hook.js'; import stateFactory from '../libraries/video/shared/state.js'; -import { PLAYBACK_MODE } from '../libraries/video/constants/enums.js'; +import { PLAYBACK_MODE } from '../libraries/video/constants/constants.js'; import { getEventHandler } from '../libraries/video/shared/eventHandler.js'; /* diff --git a/test/spec/modules/videoModule/adQueue_spec.js b/test/spec/modules/videoModule/adQueue_spec.js new file mode 100644 index 00000000000..4002e0b6dcc --- /dev/null +++ b/test/spec/modules/videoModule/adQueue_spec.js @@ -0,0 +1,172 @@ +import { expect } from 'chai'; +import { AdQueueCoordinator } from '../../../../modules/videoModule/adQueue.js'; +import { AD_BREAK_END, SETUP_COMPLETE } from '../../../../libraries/video/constants/events.js' + +const testId = 'testId'; +describe('Ad Queue Coordinator', function () { + const mockVideoCoreFactory = function () { + return { + onEvents: sinon.spy(), + offEvents: sinon.spy(), + setAdTagUrl: sinon.spy(), + } + }; + + const mockEventsFactory = function () { + return { + emit: sinon.spy() + }; + }; + + describe('Before Provider Setup Complete', function () { + it('should push ad to queue', function () { + const mockVideoCore = mockVideoCoreFactory(); + const mockEvents = mockEventsFactory(); + const coordinator = AdQueueCoordinator(mockVideoCore, mockEvents); + coordinator.registerProvider(testId); + coordinator.queueAd('testAdTag', testId, { param: {} }); + + expect(mockEvents.emit.calledOnce).to.be.true; + let emitArgs = mockEvents.emit.firstCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadQueued'); + expect(mockVideoCore.setAdTagUrl.called).to.be.false; + }); + }); + + describe('After Provider Setup Complete', function () { + it('should load from ad queue', function () { + const mockVideoCore = mockVideoCoreFactory(); + const mockEvents = mockEventsFactory(); + let setupComplete; + mockVideoCore.onEvents = function(events, callback, id) { + if (events[0] === SETUP_COMPLETE && id === testId) { + setupComplete = callback; + } + }; + const coordinator = AdQueueCoordinator(mockVideoCore, mockEvents); + coordinator.registerProvider(testId); + coordinator.queueAd('testAdTag', testId, { param: {} }); + + expect(mockEvents.emit.calledOnce).to.be.true; + let emitArgs = mockEvents.emit.firstCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadQueued'); + + setupComplete('', { divId: testId }); + expect(mockEvents.emit.calledTwice).to.be.true; + emitArgs = mockEvents.emit.secondCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadAttempt'); + expect(mockVideoCore.setAdTagUrl.calledOnce).to.be.true; + }); + + it('should load ads without queueing', function () { + const mockVideoCore = mockVideoCoreFactory(); + const mockEvents = mockEventsFactory(); + let setupComplete; + mockVideoCore.onEvents = function(events, callback, id) { + if (events[0] === SETUP_COMPLETE && id === testId) { + setupComplete = callback; + } + }; + const coordinator = AdQueueCoordinator(mockVideoCore, mockEvents); + coordinator.registerProvider(testId); + + setupComplete('', { divId: testId }); + + coordinator.queueAd('testAdTag', testId, { param: {} }); + expect(mockEvents.emit.calledOnce).to.be.true; + let emitArgs = mockEvents.emit.firstCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadAttempt'); + expect(mockVideoCore.setAdTagUrl.calledOnce).to.be.true; + }); + }); + + describe('On Ad Break End', function () { + it('should load from queue', function () { + const mockVideoCore = mockVideoCoreFactory(); + const mockEvents = mockEventsFactory(); + let setupComplete; + let adBreakEnd; + + mockVideoCore.onEvents = function(events, callback, id) { + if (events[0] === SETUP_COMPLETE && id === testId) { + setupComplete = callback; + } + + if (events[0] === AD_BREAK_END && id === testId) { + adBreakEnd = callback; + } + }; + + const coordinator = AdQueueCoordinator(mockVideoCore, mockEvents); + coordinator.registerProvider(testId); + coordinator.queueAd('testAdTag', testId); + coordinator.queueAd('testAdTag2', testId); + coordinator.queueAd('testAdTag3', testId); + + mockEvents.emit.resetHistory(); + + setupComplete('', { divId: testId }); + + expect(mockEvents.emit.calledOnce).to.be.true; + let emitArgs = mockEvents.emit.firstCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadAttempt'); + expect(mockVideoCore.setAdTagUrl.calledOnce).to.be.true; + let setAdTagArgs = mockVideoCore.setAdTagUrl.firstCall.args; + expect(setAdTagArgs[0]).to.be.equal('testAdTag'); + + adBreakEnd('', { divId: testId }); + + expect(mockEvents.emit.calledTwice).to.be.true; + emitArgs = mockEvents.emit.secondCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadAttempt'); + expect(mockVideoCore.setAdTagUrl.calledTwice).to.be.true; + setAdTagArgs = mockVideoCore.setAdTagUrl.secondCall.args; + expect(setAdTagArgs[0]).to.be.equal('testAdTag2'); + + adBreakEnd('', { divId: testId }); + + expect(mockEvents.emit.calledThrice).to.be.true; + emitArgs = mockEvents.emit.thirdCall.args; + expect(emitArgs[0]).to.be.equal('videoAuctionAdLoadAttempt'); + expect(mockVideoCore.setAdTagUrl.calledThrice).to.be.true; + setAdTagArgs = mockVideoCore.setAdTagUrl.thirdCall.args; + expect(setAdTagArgs[0]).to.be.equal('testAdTag3'); + + adBreakEnd('', { divId: testId }); + + expect(mockEvents.emit.calledThrice).to.be.true; + expect(mockVideoCore.setAdTagUrl.calledThrice).to.be.true; + }); + + it('should stop responding to AdBreakEnd when queue is empty', function () { + const mockVideoCore = mockVideoCoreFactory(); + let setupComplete; + let adBreakEnd; + + mockVideoCore.onEvents = function(events, callback, id) { + if (events[0] === SETUP_COMPLETE && id === testId) { + setupComplete = callback; + } + + if (events[0] === AD_BREAK_END && id === testId) { + adBreakEnd = callback; + } + }; + + const coordinator = AdQueueCoordinator(mockVideoCore, mockEventsFactory()); + coordinator.registerProvider(testId); + coordinator.queueAd('testAdTag', testId); + coordinator.queueAd('testAdTag2', testId); + coordinator.queueAd('testAdTag3', testId); + + setupComplete('', { divId: testId }); + adBreakEnd('', { divId: testId }); + adBreakEnd('', { divId: testId }); + expect(mockVideoCore.setAdTagUrl.calledThrice).to.be.true; + adBreakEnd('', { divId: testId }); + expect(mockVideoCore.setAdTagUrl.calledThrice).to.be.true; + adBreakEnd('', { divId: testId }); + expect(mockVideoCore.setAdTagUrl.calledThrice).to.be.true; + }); + }); +}); diff --git a/test/spec/modules/videoModule/pbVideo_spec.js b/test/spec/modules/videoModule/pbVideo_spec.js index cfd34ebd706..41780a007dd 100644 --- a/test/spec/modules/videoModule/pbVideo_spec.js +++ b/test/spec/modules/videoModule/pbVideo_spec.js @@ -14,12 +14,15 @@ let gamSubmoduleMock; let gamSubmoduleFactoryMock; let videoImpressionVerifierFactoryMock; let videoImpressionVerifierMock; +let adQueueCoordinatorMock; +let adQueueCoordinatorFactoryMock; function resetTestVars() { ortbVideoMock = {}; ortbContentMock = {}; videoCoreMock = { registerProvider: sinon.spy(), + initProvider: sinon.spy(), onEvents: sinon.spy(), getOrtbVideo: () => ortbVideoMock, getOrtbContent: () => ortbContentMock, @@ -54,9 +57,16 @@ function resetTestVars() { }; videoImpressionVerifierFactoryMock = () => videoImpressionVerifierMock; + + adQueueCoordinatorMock = { + registerProvider: sinon.spy(), + queueAd: sinon.spy() + }; + + adQueueCoordinatorFactoryMock = () => adQueueCoordinatorMock; } -let pbVideoFactory = (videoCore, getConfig, pbGlobal, pbEvents, videoEvents, gamSubmoduleFactory, videoImpressionVerifierFactory) => { +let pbVideoFactory = (videoCore, getConfig, pbGlobal, pbEvents, videoEvents, gamSubmoduleFactory, videoImpressionVerifierFactory, adQueueCoordinator) => { const pbVideo = PbVideo( videoCore || videoCoreMock, getConfig || getConfigMock, @@ -64,7 +74,8 @@ let pbVideoFactory = (videoCore, getConfig, pbGlobal, pbEvents, videoEvents, gam pbEvents || pbEventsMock, videoEvents || videoEventsMock, gamSubmoduleFactory || gamSubmoduleFactoryMock, - videoImpressionVerifierFactory || videoImpressionVerifierFactoryMock + videoImpressionVerifierFactory || videoImpressionVerifierFactoryMock, + adQueueCoordinator || adQueueCoordinatorMock ); pbVideo.init(); return pbVideo; @@ -207,6 +218,7 @@ describe('Prebid Video', function () { beforeEach(() => { gamSubmoduleMock.getAdTagUrl.resetHistory(); videoCoreMock.setAdTagUrl.resetHistory(); + adQueueCoordinatorMock.queueAd.resetHistory(); }); let beforeBidRequestCallback; @@ -250,10 +262,10 @@ describe('Prebid Video', function () { pbVideoFactory(null, getConfig, pbGlobal, pbEvents, null, gamSubmoduleFactory); beforeBidRequestCallback(() => {}, {}); auctionEndCallback(auctionResults); - expect(videoCoreMock.setAdTagUrl.calledOnce).to.be.true; - expect(videoCoreMock.setAdTagUrl.args[0][0]).to.be.equal(expectedAdTag); - expect(videoCoreMock.setAdTagUrl.args[0][1]).to.be.equal(expectedDivId); - expect(videoCoreMock.setAdTagUrl.args[0][2]).to.have.property('adUnitCode', expectedAdUnitCode); + expect(adQueueCoordinatorMock.queueAd.calledOnce).to.be.true; + expect(adQueueCoordinatorMock.queueAd.args[0][0]).to.be.equal(expectedAdTag); + expect(adQueueCoordinatorMock.queueAd.args[0][1]).to.be.equal(expectedDivId); + expect(adQueueCoordinatorMock.queueAd.args[0][2]).to.have.property('adUnitCode', expectedAdUnitCode); }); it('should load ad tag from highest bid when ad server is not configured', function () { @@ -275,11 +287,11 @@ describe('Prebid Video', function () { pbVideoFactory(null, () => ({ providers: [] }), pbGlobal, pbEvents); beforeBidRequestCallback(() => {}, {}); auctionEndCallback(auctionResults); - expect(videoCoreMock.setAdTagUrl.calledOnce).to.be.true; - expect(videoCoreMock.setAdTagUrl.args[0][0]).to.be.equal(expectedVastUrl); - expect(videoCoreMock.setAdTagUrl.args[0][1]).to.be.equal(expectedDivId); - expect(videoCoreMock.setAdTagUrl.args[0][2]).to.have.property('adUnitCode', expectedAdUnitCode); - expect(videoCoreMock.setAdTagUrl.args[0][2]).to.have.property('adXml', expectedVastXml); + expect(adQueueCoordinatorMock.queueAd.calledOnce).to.be.true; + expect(adQueueCoordinatorMock.queueAd.args[0][0]).to.be.equal(expectedVastUrl); + expect(adQueueCoordinatorMock.queueAd.args[0][1]).to.be.equal(expectedDivId); + expect(adQueueCoordinatorMock.queueAd.args[0][2]).to.have.property('adUnitCode', expectedAdUnitCode); + expect(adQueueCoordinatorMock.queueAd.args[0][2]).to.have.property('adXml', expectedVastXml); }); }); diff --git a/test/spec/modules/videoModule/shared/parentModule_spec.js b/test/spec/modules/videoModule/shared/parentModule_spec.js index 1e8e7fda380..e3e4cfb7f3f 100644 --- a/test/spec/modules/videoModule/shared/parentModule_spec.js +++ b/test/spec/modules/videoModule/shared/parentModule_spec.js @@ -62,7 +62,6 @@ describe('Submodule Builder', function () { it('should instantiate the submodule, when supported', function () { const submodule = submoduleBuilder.build(vendorCode2); - expect(initSpy.calledOnce).to.be.true; expect(submodule).to.be.equal(submodule2); }); diff --git a/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js b/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js index 399c115b820..4377e989851 100644 --- a/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js +++ b/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js @@ -14,7 +14,7 @@ import { SETUP_COMPLETE, SETUP_FAILED, PLAY, AD_IMPRESSION, videoEvents } from 'libraries/video/constants/events.js'; -import { PLAYBACK_MODE } from 'libraries/video/constants/enums.js'; +import { PLAYBACK_MODE } from 'libraries/video/constants/constants.js'; function getPlayerMock() { return makePlayerFactoryMock({ From 182f08e314cb1d7ab9a5fc6cf86ed0179684474b Mon Sep 17 00:00:00 2001 From: Mikael Lundin Date: Tue, 13 Dec 2022 16:06:14 +0100 Subject: [PATCH 197/367] Adnuntius Bid Adapter: native added (#9330) * package lock fix. * Add dimensions to prebid. * Adnuntius Bid Adapter. Added native as a media type. --- modules/adnuntiusBidAdapter.js | 41 +++++- test/spec/modules/adnuntiusBidAdapter_spec.js | 122 ++++++++++++++++++ 2 files changed, 160 insertions(+), 3 deletions(-) diff --git a/modules/adnuntiusBidAdapter.js b/modules/adnuntiusBidAdapter.js index 0ae8411c073..5ad5436e732 100644 --- a/modules/adnuntiusBidAdapter.js +++ b/modules/adnuntiusBidAdapter.js @@ -1,5 +1,5 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; import { isStr, deepAccess, logInfo } from '../src/utils.js'; import { config } from '../src/config.js'; import { getStorageManager } from '../src/storageManager.js'; @@ -8,6 +8,7 @@ const BIDDER_CODE = 'adnuntius'; const ENDPOINT_URL = 'https://ads.adnuntius.delivery/i'; const GVLID = 855; const DEFAULT_VAST_VERSION = 'vast4' +const DEFAULT_NATIVE = 'native' const checkSegment = function (segment) { if (isStr(segment)) return segment; @@ -27,6 +28,32 @@ const getSegmentsFromOrtb = function (ortb2) { return segments } +function createNative(ad) { + const native = {}; + const assets = ad.assets + native.title = ad.text.title.content; + native.image = { + url: assets.image.cdnId, + height: assets.image.height, + width: assets.image.width, + }; + if (assets.icon) { + native.icon = { + url: assets.icon.cdnId, + height: assets.icon.height, + width: assets.icon.width, + }; + } + + native.sponsoredBy = ad.text.sponsoredBy?.content || ''; + native.body = ad.text.body?.content || ''; + native.cta = ad.text.cta?.content || ''; + native.clickUrl = ad.destinationUrls.destination || ''; + native.impressionTrackers = ad.impressionTrackingUrls || [ad.renderedPixel]; + + return native; +} + const handleMeta = function () { const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }) let adnMeta = null @@ -46,7 +73,7 @@ const getUsi = function (meta, ortb2, bidderRequest) { export const spec = { code: BIDDER_CODE, gvlid: GVLID, - supportedMediaTypes: [BANNER, VIDEO], + supportedMediaTypes: [BANNER, VIDEO, NATIVE], isBidRequestValid: function (bid) { return !!(bid.bidId || (bid.params.member && bid.params.invCode)); }, @@ -82,6 +109,10 @@ export const spec = { network += '_video' } + if (bid.mediaTypes && bid.mediaTypes.native) { + network += '_native' + } + bidRequests[network] = bidRequests[network] || []; bidRequests[network].push(bid); @@ -99,6 +130,7 @@ export const spec = { const network = networkKeys[j]; const networkRequest = [...request] if (network.indexOf('_video') > -1) { networkRequest.push('tt=' + DEFAULT_VAST_VERSION) } + if (network.indexOf('_native') > -1) { networkRequest.push('tt=' + DEFAULT_NATIVE) } requests.push({ method: 'POST', url: ENDPOINT_URL + '?' + networkRequest.join('&'), @@ -137,7 +169,10 @@ export const spec = { if (adUnit.vastXml) { adResponse[adUnit.targetId].vastXml = adUnit.vastXml - adResponse[adUnit.targetId].mediaType = 'video' + adResponse[adUnit.targetId].mediaType = VIDEO + } else if (ad.assets && ad.assets.image && ad.text && ad.text.title && ad.text.body && ad.destinationUrls && ad.destinationUrls.destination) { + adResponse[adUnit.targetId].native = createNative(ad); + adResponse[adUnit.targetId].mediaType = NATIVE; } else { adResponse[adUnit.targetId].ad = adUnit.html } diff --git a/test/spec/modules/adnuntiusBidAdapter_spec.js b/test/spec/modules/adnuntiusBidAdapter_spec.js index 2d5ea630f0f..ee585862800 100644 --- a/test/spec/modules/adnuntiusBidAdapter_spec.js +++ b/test/spec/modules/adnuntiusBidAdapter_spec.js @@ -71,6 +71,30 @@ describe('adnuntiusBidAdapter', function () { } ] + const nativeBidderRequest = [ + { + bidId: '123', + bidder: 'adnuntius', + params: { + auId: '8b6bc', + network: 'adnuntius', + }, + mediaTypes: { + native: { + title: { + required: true + }, + image: { + required: true + }, + body: { + required: true + } + } + }, + } + ] + const singleBidRequest = { bid: [ { @@ -83,6 +107,10 @@ describe('adnuntiusBidAdapter', function () { bid: videoBidderRequest } + const nativeBidRequest = { + bid: nativeBidderRequest + } + const serverResponse = { body: { 'adUnits': [ @@ -209,6 +237,83 @@ describe('adnuntiusBidAdapter', function () { ] } } + const serverNativeResponse = { + body: { + 'adUnits': [ + { + 'auId': '000000000008b6bc', + 'targetId': '123', + '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/K9rfXC6wJvgVuy4Fbt5P8oEEGXme9ZaP8BNDzz3OMGQ.jpg', + 'width': '300', + 'height': '250' + } + }, + 'text': { + 'body': { + 'content': 'Testing Native ad from Adnuntius', + 'length': '32', + 'minLength': '0', + 'maxLength': '100' + }, + 'title': { + 'content': 'Native Ad', + 'length': '9', + 'minLength': '5', + 'maxLength': '100' + } + }, + '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' + }, + + ] + }, + { + 'auId': '000000000008b6bc', + 'targetId': '456', + 'matchedAdCount': 0, + 'responseId': 'adn-rsp-1460129238', + } + ] + } + } describe('inherited functions', function () { it('exists and is a function', function () { @@ -426,4 +531,21 @@ describe('adnuntiusBidAdapter', function () { expect(interpretedResponse[0].vastXml).to.equal(serverVideoResponse.body.adUnits[0].vastXml); }); }); + describe('interpretNativeResponse', function () { + it('should return valid response when passed valid server response', function () { + const interpretedResponse = spec.interpretResponse(serverNativeResponse, nativeBidRequest); + const ad = serverNativeResponse.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.bid.currency); + expect(interpretedResponse[0].netRevenue).to.equal(false); + expect(interpretedResponse[0].meta).to.have.property('advertiserDomains'); + expect(interpretedResponse[0].meta.advertiserDomains).to.have.lengthOf(1); + expect(interpretedResponse[0].meta.advertiserDomains[0]).to.equal('google.com'); + expect(interpretedResponse[0].native.body).to.equal(serverNativeResponse.body.adUnits[0].ads[0].text.body.content); + }); + }); }); From d646c55ced9f8ee6f596df1cd717e72b1c0ebcd7 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 13 Dec 2022 12:53:41 -0700 Subject: [PATCH 198/367] Prebid core: enrich FPD by default (#9205) * Move rootDomain * Move FPD enrichments to core * Remove fpdEnrichments module * Cleanup * Add `site`, `device`, and coppa enrichments * FPD enrichments: GDPR * FPD enrichments: USP * Enrich FPD from requestBids * Fix typo in package.json --- libraries/ortbConverter/processors/default.js | 38 +-- modules/.submodules.json | 1 - modules/consentManagement.js | 22 +- modules/consentManagementUsp.js | 16 +- modules/enrichmentFpdModule.js | 192 +----------- modules/userId/index.js | 56 +--- src/fpd/enrichment.js | 94 ++++++ src/fpd/rootDomain.js | 57 ++++ src/prebid.js | 8 +- test/helpers/fpd.js | 71 +++++ test/spec/fpd/enrichment_spec.js | 213 +++++++++++++ test/spec/fpd/gdpr_spec.js | 47 +++ test/spec/fpd/rootDomain_spec.js | 61 ++++ test/spec/fpd/usp_spec.js | 36 +++ test/spec/modules/enrichmentFpdModule_spec.js | 159 ---------- test/spec/modules/fpdModule_spec.js | 288 +----------------- .../modules/improvedigitalBidAdapter_spec.js | 28 +- test/spec/modules/openxOrtbBidAdapter_spec.js | 35 ++- .../modules/prebidServerBidAdapter_spec.js | 76 +++-- test/spec/modules/userId_spec.js | 41 --- .../ortbConverter/default_processors_spec.js | 61 ---- test/spec/ortbConverter/gdpr_spec.js | 31 +- test/spec/ortbConverter/usp_spec.js | 15 - test/spec/unit/pbjs_api_spec.js | 70 +++-- 24 files changed, 751 insertions(+), 965 deletions(-) create mode 100644 src/fpd/enrichment.js create mode 100644 src/fpd/rootDomain.js create mode 100644 test/helpers/fpd.js create mode 100644 test/spec/fpd/enrichment_spec.js create mode 100644 test/spec/fpd/gdpr_spec.js create mode 100644 test/spec/fpd/rootDomain_spec.js create mode 100644 test/spec/fpd/usp_spec.js delete mode 100644 test/spec/ortbConverter/default_processors_spec.js delete mode 100644 test/spec/ortbConverter/usp_spec.js diff --git a/libraries/ortbConverter/processors/default.js b/libraries/ortbConverter/processors/default.js index 70acb7c9953..8d44de00fa2 100644 --- a/libraries/ortbConverter/processors/default.js +++ b/libraries/ortbConverter/processors/default.js @@ -1,4 +1,4 @@ -import {deepSetValue, getDefinedParams, getDNT, mergeDeep} from '../../../src/utils.js'; +import {deepSetValue, mergeDeep} from '../../../src/utils.js'; import {bannerResponseProcessor, fillBannerImp} from './banner.js'; import {fillVideoImp, fillVideoResponse} from './video.js'; import {setResponseMediaType} from './mediaType.js'; @@ -20,14 +20,6 @@ export const DEFAULT_PROCESSORS = { appFpd: fpdFromTopLevelConfig('app'), siteFpd: fpdFromTopLevelConfig('site'), deviceFpd: fpdFromTopLevelConfig('device'), - device: { - // sets device w / h / ua / language - fn: setDevice - }, - site: { - // sets site.domain, page, and ref from refererInfo - fn: setSite - }, props: { // sets request properties id, tmax, test, source.tid fn(ortbRequest, bidderRequest) { @@ -41,15 +33,7 @@ export const DEFAULT_PROCESSORS = { } deepSetValue(ortbRequest, 'source.tid', ortbRequest.source?.tid || bidderRequest.auctionId); } - }, - coppa: { - fn(ortbRequest) { - const coppa = config.getConfig('coppa'); - if (typeof coppa === 'boolean') { - deepSetValue(ortbRequest, 'regs.coppa', coppa ? 1 : 0); - } - } - }, + } }, [IMP]: { fpd: { @@ -144,24 +128,8 @@ function fpdFromTopLevelConfig(prop) { fn(ortbRequest) { const data = config.getConfig(prop); if (typeof data === 'object') { - ortbRequest[prop] = data; + ortbRequest[prop] = mergeDeep({}, ortbRequest[prop], data); } } } } - -export function setDevice(ortbRequest) { - ortbRequest.device = Object.assign({ - w: window.innerWidth, - h: window.innerHeight, - dnt: getDNT() ? 1 : 0, - ua: window.navigator.userAgent, - language: window.navigator.language.split('-').shift() - }, ortbRequest.device); -} - -export function setSite(ortbRequest, bidderRequest) { - if (bidderRequest.refererInfo) { - ortbRequest.site = Object.assign(getDefinedParams(bidderRequest.refererInfo, ['page', 'domain', 'ref']), ortbRequest.site); - } -} diff --git a/modules/.submodules.json b/modules/.submodules.json index f8c30459e1e..c3016914f1b 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -76,7 +76,6 @@ "zeusPrimeRtdProvider" ], "fpdModule": [ - "enrichmentFpdModule", "validationFpdModule", "topicsFpdModule" ], diff --git a/modules/consentManagement.js b/modules/consentManagement.js index 95d622e55e4..6ca12010c74 100644 --- a/modules/consentManagement.js +++ b/modules/consentManagement.js @@ -10,6 +10,7 @@ import {gdprDataHandler} from '../src/adapterManager.js'; import {includes} from '../src/polyfill.js'; import {timedAuctionHook} from '../src/utils/perfMetrics.js'; import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; +import {enrichFPD} from '../src/fpd/enrichment.js'; const DEFAULT_CMP = 'iab'; const DEFAULT_CONSENT_TIMEOUT = 10000; @@ -356,22 +357,27 @@ export function setConsentConfig(config) { } config.getConfig('consentManagement', config => setConsentConfig(config.consentManagement)); -export function setOrtbGdpr(ortbRequest, bidderRequest) { - const consent = bidderRequest.gdprConsent; - if (consent) { - if (typeof consent.gdprApplies === 'boolean') { - deepSetValue(ortbRequest, 'regs.ext.gdpr', consent.gdprApplies ? 1 : 0); +export function enrichFPDHook(next, fpd) { + return next(fpd.then(ortb2 => { + const consent = gdprDataHandler.getConsentData(); + if (consent) { + if (typeof consent.gdprApplies === 'boolean') { + deepSetValue(ortb2, 'regs.ext.gdpr', consent.gdprApplies ? 1 : 0); + } + deepSetValue(ortb2, 'user.ext.consent', consent.consentString); } - deepSetValue(ortbRequest, 'user.ext.consent', consent.consentString); - } + return ortb2; + })); } +enrichFPD.before(enrichFPDHook); + export function setOrtbAdditionalConsent(ortbRequest, bidderRequest) { + // this is not a standardized name for addtlConsent, so keep this as an ORTB library processor rather than an FPD enrichment const addtl = bidderRequest.gdprConsent?.addtlConsent; if (addtl && typeof addtl === 'string') { deepSetValue(ortbRequest, 'user.ext.ConsentedProvidersSettings.consented_providers', addtl); } } -registerOrtbProcessor({type: REQUEST, name: 'gdpr', fn: setOrtbGdpr}); registerOrtbProcessor({type: REQUEST, name: 'gdprAddtlConsent', fn: setOrtbAdditionalConsent}) diff --git a/modules/consentManagementUsp.js b/modules/consentManagementUsp.js index 805c796312c..0a99ec4a913 100644 --- a/modules/consentManagementUsp.js +++ b/modules/consentManagementUsp.js @@ -7,9 +7,9 @@ import {deepSetValue, isFn, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js'; import {config} from '../src/config.js'; import adapterManager, {uspDataHandler} from '../src/adapterManager.js'; -import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; import {timedAuctionHook} from '../src/utils/perfMetrics.js'; import {getHook} from '../src/hook.js'; +import {enrichFPD} from '../src/fpd/enrichment.js'; const DEFAULT_CONSENT_API = 'iab'; const DEFAULT_CONSENT_TIMEOUT = 50; @@ -323,10 +323,14 @@ config.getConfig('consentManagement', config => setConsentConfig(config.consentM getHook('requestBids').before(requestBidsHook, 50); -export function setOrtbUsp(ortbRequest, bidderRequest) { - if (bidderRequest.uspConsent) { - deepSetValue(ortbRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent); - } +export function enrichFPDHook(next, fpd) { + return next(fpd.then(ortb2 => { + const consent = uspDataHandler.getConsentData(); + if (consent) { + deepSetValue(ortb2, 'regs.ext.us_privacy', consent) + } + return ortb2; + })) } -registerOrtbProcessor({type: REQUEST, name: 'usp', fn: setOrtbUsp}); +enrichFPD.before(enrichFPDHook); diff --git a/modules/enrichmentFpdModule.js b/modules/enrichmentFpdModule.js index a4d7c06d0fb..59d5d326109 100644 --- a/modules/enrichmentFpdModule.js +++ b/modules/enrichmentFpdModule.js @@ -1,190 +1,2 @@ - -/** - * This module sets default values and validates ortb2 first part data - * @module modules/firstPartyData - */ -import { timestamp, mergeDeep } from '../src/utils.js'; -import { submodule } from '../src/hook.js'; -import {getRefererInfo, parseDomain} from '../src/refererDetection.js'; -import { getCoreStorageManager } from '../src/storageManager.js'; -import {GreedyPromise} from '../src/utils/promise.js'; -import {getHighEntropySUA, getLowEntropySUA} from '../libraries/fpd/sua.js'; - -let ortb2; -let win = (window === window.top) ? window : window.top; -export const coreStorage = getCoreStorageManager('enrichmentFpd'); - -export const sua = {he: getHighEntropySUA, le: getLowEntropySUA}; - -/** - * Find the root domain - * @param {string|undefined} fullDomain - * @return {string} -*/ -export function findRootDomain(fullDomain = window.location.hostname) { - if (!coreStorage.cookiesAreEnabled()) { - return fullDomain; - } - - const domainParts = fullDomain.split('.'); - if (domainParts.length == 2) { - return fullDomain; - } - let rootDomain; - let continueSearching; - let startIndex = -2; - const TEST_COOKIE_NAME = `_rdc${Date.now()}`; - const TEST_COOKIE_VALUE = 'writeable'; - do { - rootDomain = domainParts.slice(startIndex).join('.'); - let expirationDate = new Date(timestamp() + 10 * 1000).toUTCString(); - - // Write a test cookie - coreStorage.setCookie( - TEST_COOKIE_NAME, - TEST_COOKIE_VALUE, - expirationDate, - 'Lax', - rootDomain, - undefined - ); - - // See if the write was successful - const value = coreStorage.getCookie(TEST_COOKIE_NAME, undefined); - if (value === TEST_COOKIE_VALUE) { - continueSearching = false; - // Delete our test cookie - coreStorage.setCookie( - TEST_COOKIE_NAME, - '', - 'Thu, 01 Jan 1970 00:00:01 GMT', - undefined, - rootDomain, - undefined - ); - } else { - startIndex += -1; - continueSearching = Math.abs(startIndex) <= domainParts.length; - } - } while (continueSearching); - return rootDomain; -} - -/** - * Checks for referer and if exists merges into ortb2 global data - */ -function setReferer() { - if (getRefererInfo().ref) mergeDeep(ortb2, { site: { ref: getRefererInfo().ref } }); -} - -/** - * Checks for canonical url and if exists merges into ortb2 global data - */ -function setPage() { - if (getRefererInfo().page) mergeDeep(ortb2, { site: { page: getRefererInfo().page } }); -} - -/** - * Checks for canonical url and if exists retrieves domain and merges into ortb2 global data - */ -function setDomain() { - const domain = parseDomain(getRefererInfo().page, {noLeadingWww: true}); - if (domain) { - mergeDeep(ortb2, { site: { domain: domain } }); - mergeDeep(ortb2, { site: { publisher: { domain: findRootDomain(domain) } } }); - }; -} - -/** - * Checks for screen/device width and height and sets dimensions - */ -function setDimensions() { - let width; - let height; - - try { - width = win.innerWidth || win.document.documentElement.clientWidth || win.document.body.clientWidth; - height = win.innerHeight || win.document.documentElement.clientHeight || win.document.body.clientHeight; - } catch (e) { - width = window.innerWidth || window.document.documentElement.clientWidth || window.document.body.clientWidth; - height = window.innerHeight || window.document.documentElement.clientHeight || window.document.body.clientHeight; - } - - mergeDeep(ortb2, { device: { w: width, h: height } }); -} - -/** - * Scans page for meta keywords, and if exists, merges into site.keywords - */ -function setKeywords() { - let keywords; - - try { - keywords = win.document.querySelector("meta[name='keywords']"); - } catch (e) { - keywords = window.document.querySelector("meta[name='keywords']"); - } - - if (keywords && keywords.content) mergeDeep(ortb2, { site: { keywords: keywords.content.replace(/\s/g, '') } }); -} - -function setDeviceSua(hints) { - let data = Array.isArray(hints) && hints.length === 0 - ? GreedyPromise.resolve(sua.le()) - : sua.he(hints); - return data.then((sua) => { - if (sua != null) { - mergeDeep(ortb2, {device: {sua}}); - } - }) -} - -/** - * Checks the Global Privacy Control status, and if exists and is true, merges into regs.ext.gpc - */ -function setGpc() { - const gpcValue = navigator.globalPrivacyControl; - if (gpcValue) { - mergeDeep(ortb2, { regs: { ext: { gpc: 1 } } }) - } -} - -/** - * Resets modules global ortb2 data - */ -export const resetEnrichments = () => { ortb2 = null }; - -function runEnrichments(fpdConf) { - setReferer(); - setPage(); - setDomain(); - setDimensions(); - setKeywords(); - setGpc(); - return setDeviceSua(fpdConf.uaHints).then(() => ortb2); -} - -export function processFpd(fpdConf, {global}) { - if (fpdConf.skipEnrichments) { - return {global}; - } else { - let ready; - if (ortb2 == null) { - ortb2 = {}; - ready = runEnrichments(fpdConf); - } else { - ready = GreedyPromise.resolve(); - } - return ready.then(() => ({ - global: mergeDeep({}, ortb2, global) - })) - } -} -/** @type {firstPartyDataSubmodule} */ -export const enrichmentsSubmodule = { - name: 'enrichments', - queue: 2, - processFpd -} - -submodule('firstPartyData', enrichmentsSubmodule) +// Logic from this module was moved into core since approx. 7.27 +// TODO: remove this in v8 diff --git a/modules/userId/index.js b/modules/userId/index.js index fe47ac5c16d..82ebaf2b14e 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -148,7 +148,6 @@ import { logError, logInfo, logWarn, - timestamp, isEmpty, deepSetValue } from '../../src/utils.js'; import {getPPID as coreGetPPID} from '../../src/adserver.js'; @@ -156,6 +155,7 @@ import {defer, GreedyPromise} from '../../src/utils/promise.js'; import {hasPurpose1Consent} from '../../src/utils/gpdr.js'; import {registerOrtbProcessor, REQUEST} from '../../src/pbjsORTB.js'; import {newMetrics, timedAuctionHook, useMetrics} from '../../src/utils/perfMetrics.js'; +import {findRootDomain} from '../../src/fpd/rootDomain.js'; const MODULE_NAME = 'User ID'; const COOKIE = 'cookie'; @@ -385,60 +385,6 @@ function storedConsentDataMatchesConsentData(storedConsentData, consentData) { ); } -/** - * Find the root domain - * @param {string|undefined} fullDomain - * @return {string} - */ -export function findRootDomain(fullDomain = window.location.hostname) { - if (!coreStorage.cookiesAreEnabled()) { - return fullDomain; - } - - const domainParts = fullDomain.split('.'); - if (domainParts.length == 2) { - return fullDomain; - } - let rootDomain; - let continueSearching; - let startIndex = -2; - const TEST_COOKIE_NAME = `_rdc${Date.now()}`; - const TEST_COOKIE_VALUE = 'writeable'; - do { - rootDomain = domainParts.slice(startIndex).join('.'); - let expirationDate = new Date(timestamp() + 10 * 1000).toUTCString(); - - // Write a test cookie - coreStorage.setCookie( - TEST_COOKIE_NAME, - TEST_COOKIE_VALUE, - expirationDate, - 'Lax', - rootDomain, - undefined - ); - - // See if the write was successful - const value = coreStorage.getCookie(TEST_COOKIE_NAME, undefined); - if (value === TEST_COOKIE_VALUE) { - continueSearching = false; - // Delete our test cookie - coreStorage.setCookie( - TEST_COOKIE_NAME, - '', - 'Thu, 01 Jan 1970 00:00:01 GMT', - undefined, - rootDomain, - undefined - ); - } else { - startIndex += -1; - continueSearching = Math.abs(startIndex) <= domainParts.length; - } - } while (continueSearching); - return rootDomain; -} - /** * @param {SubmoduleContainer[]} submodules * @param {function} cb - callback for after processing is done. diff --git a/src/fpd/enrichment.js b/src/fpd/enrichment.js new file mode 100644 index 00000000000..fc50a057378 --- /dev/null +++ b/src/fpd/enrichment.js @@ -0,0 +1,94 @@ +import {hook} from '../hook.js'; +import {getRefererInfo, parseDomain} from '../refererDetection.js'; +import {findRootDomain} from './rootDomain.js'; +import {deepSetValue, getDefinedParams, getDNT, getWindowSelf, getWindowTop, mergeDeep} from '../utils.js'; +import {config} from '../config.js'; +import {getHighEntropySUA, getLowEntropySUA} from '../../libraries/fpd/sua.js'; +import {GreedyPromise} from '../utils/promise.js'; + +export const dep = { + getRefererInfo, + findRootDomain, + getWindowTop, + getWindowSelf, + getHighEntropySUA, + getLowEntropySUA, +}; + +/** + * Enrich an ortb2 object with first party data. + * @param {Promise[{}]} fpd: a promise to an ortb2 object. + * @returns: {Promise[{}]}: a promise to an enriched ortb2 object. + */ +export const enrichFPD = hook('sync', (fpd) => { + return GreedyPromise.all([fpd, getSUA().catch(() => null)]) + .then(([ortb2, sua]) => { + Object.entries(ENRICHMENTS).forEach(([section, getEnrichments]) => { + const data = getEnrichments(); + if (data && Object.keys(data).length > 0) { + ortb2[section] = mergeDeep({}, data, ortb2[section]); + } + }); + if (sua) { + deepSetValue(ortb2, 'device.sua', Object.assign({}, sua, ortb2.device.sua)); + } + return ortb2; + }); +}); + +function winFallback(fn) { + try { + return fn(dep.getWindowTop()); + } catch (e) { + return fn(dep.getWindowSelf()); + } +} + +function getSUA() { + const hints = config.getConfig('firstPartyData.uaHints'); + return Array.isArray(hints) && hints.length === 0 + ? GreedyPromise.resolve(dep.getLowEntropySUA()) + : dep.getHighEntropySUA(hints); +} + +const ENRICHMENTS = { + site() { + const ri = dep.getRefererInfo(); + const domain = parseDomain(ri.page, {noLeadingWww: true}); + const keywords = winFallback((win) => win.document.querySelector('meta[name=\'keywords\']')) + ?.content?.replace?.(/\s/g, ''); + return (site => getDefinedParams(site, Object.keys(site)))({ + page: ri.page, + ref: ri.ref, + domain, + keywords, + publisher: { + domain: dep.findRootDomain(domain) + } + }); + }, + device() { + return winFallback((win) => { + const w = win.innerWidth || win.document.documentElement.clientWidth || win.document.body.clientWidth; + const h = win.innerHeight || win.document.documentElement.clientHeight || win.document.body.clientHeight; + return { + w, + h, + dnt: getDNT() ? 1 : 0, + ua: win.navigator.userAgent, + language: win.navigator.language.split('-').shift(), + }; + }) + }, + regs() { + const regs = {}; + if (winFallback((win) => win.navigator.globalPrivacyControl)) { + deepSetValue(regs, 'ext.gpc', 1); + } + const coppa = config.getConfig('coppa'); + if (typeof coppa === 'boolean') { + regs.coppa = coppa ? 1 : 0; + } + return regs; + } +}; diff --git a/src/fpd/rootDomain.js b/src/fpd/rootDomain.js new file mode 100644 index 00000000000..4095613672f --- /dev/null +++ b/src/fpd/rootDomain.js @@ -0,0 +1,57 @@ +import {memoize, timestamp} from '../utils.js'; +import {getCoreStorageManager} from '../storageManager.js'; + +export const coreStorage = getCoreStorageManager(); + +/** + * Find the root domain by testing for the topmost domain that will allow setting cookies. + */ + +export const findRootDomain = memoize(function findRootDomain(fullDomain = window.location.host) { + if (!coreStorage.cookiesAreEnabled()) { + return fullDomain; + } + + const domainParts = fullDomain.split('.'); + if (domainParts.length === 2) { + return fullDomain; + } + let rootDomain; + let continueSearching; + let startIndex = -2; + const TEST_COOKIE_NAME = `_rdc${Date.now()}`; + const TEST_COOKIE_VALUE = 'writeable'; + do { + rootDomain = domainParts.slice(startIndex).join('.'); + let expirationDate = new Date(timestamp() + 10 * 1000).toUTCString(); + + // Write a test cookie + coreStorage.setCookie( + TEST_COOKIE_NAME, + TEST_COOKIE_VALUE, + expirationDate, + 'Lax', + rootDomain, + undefined + ); + + // See if the write was successful + const value = coreStorage.getCookie(TEST_COOKIE_NAME, undefined); + if (value === TEST_COOKIE_VALUE) { + continueSearching = false; + // Delete our test cookie + coreStorage.setCookie( + TEST_COOKIE_NAME, + '', + 'Thu, 01 Jan 1970 00:00:01 GMT', + undefined, + rootDomain, + undefined + ); + } else { + startIndex += -1; + continueSearching = Math.abs(startIndex) <= domainParts.length; + } + } while (continueSearching); + return rootDomain; +}); diff --git a/src/prebid.js b/src/prebid.js index 06429b13a72..f30b4ea9bbe 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -49,7 +49,8 @@ import {default as adapterManager, gdprDataHandler, getS2SBidderSet, uspDataHand import CONSTANTS from './constants.json'; import * as events from './events.js'; import {newMetrics, useMetrics} from './utils/perfMetrics.js'; -import {defer} from './utils/promise.js'; +import {defer, GreedyPromise} from './utils/promise.js'; +import {enrichFPD} from './fpd/enrichment.js'; const $$PREBID_GLOBAL$$ = getGlobal(); const { triggerUserSyncs } = userSync; @@ -631,7 +632,10 @@ $$PREBID_GLOBAL$$.requestBids = (function() { global: mergeDeep({}, config.getAnyConfig('ortb2') || {}, ortb2 || {}), bidder: Object.fromEntries(Object.entries(config.getBidderConfig()).map(([bidder, cfg]) => [bidder, cfg.ortb2]).filter(([_, ortb2]) => ortb2 != null)) } - return startAuction({bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2Fragments, metrics, defer}); + return enrichFPD(GreedyPromise.resolve(ortb2Fragments.global)).then(global => { + ortb2Fragments.global = global; + return startAuction({bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2Fragments, metrics, defer}); + }) }, 'requestBids'); return wrapHook(delegate, function requestBids(req = {}) { diff --git a/test/helpers/fpd.js b/test/helpers/fpd.js new file mode 100644 index 00000000000..89755f26541 --- /dev/null +++ b/test/helpers/fpd.js @@ -0,0 +1,71 @@ +import {dep, enrichFPD} from 'src/fpd/enrichment.js'; +import {GreedyPromise} from '../../src/utils/promise.js'; +import {deepClone} from '../../src/utils.js'; +import {gdprDataHandler, uspDataHandler} from '../../src/adapterManager.js'; + +export function mockFpdEnrichments(sandbox, overrides = {}) { + overrides = Object.assign({}, { + // override window getters, required for ChromeHeadless, apparently it sees window.self !== window + getWindowTop() { + return window + }, + getWindowSelf() { + return window + }, + getHighEntropySUA() { + return GreedyPromise.resolve() + } + }, overrides) + Object.entries(overrides) + .filter(([k]) => dep[k]) + .forEach(([k, v]) => { + sandbox.stub(dep, k).callsFake(v); + }); + Object.entries({ + gdprConsent: gdprDataHandler, + uspConsent: uspDataHandler, + }).forEach(([ovKey, handler]) => { + const v = overrides[ovKey]; + if (v) { + sandbox.stub(handler, 'getConsentData').callsFake(v); + } + }) +} + +export function addFPDEnrichments(ortb2 = {}, overrides) { + const sandbox = sinon.sandbox.create(); + mockFpdEnrichments(sandbox, overrides) + return enrichFPD(GreedyPromise.resolve(deepClone(ortb2))).finally(() => sandbox.restore()); +} + +export const syncAddFPDEnrichments = synchronize(addFPDEnrichments); + +export function addFPDToBidderRequest(bidderRequest, overrides) { + overrides = Object.assign({}, { + getRefererInfo() { + return bidderRequest.refererInfo || {}; + }, + gdprConsent() { + return bidderRequest.gdprConsent; + }, + uspConsent() { + return bidderRequest.uspConsent; + } + }, overrides); + return addFPDEnrichments(bidderRequest.ortb2 || {}, overrides).then(ortb2 => { + return { + ...bidderRequest, + ortb2 + } + }); +} + +export const syncAddFPDToBidderRequest = synchronize(addFPDToBidderRequest); + +function synchronize(fn) { + return function () { + let result; + fn.apply(this, arguments).then(res => { result = res }); + return result; + } +} diff --git a/test/spec/fpd/enrichment_spec.js b/test/spec/fpd/enrichment_spec.js new file mode 100644 index 00000000000..3363e1867d3 --- /dev/null +++ b/test/spec/fpd/enrichment_spec.js @@ -0,0 +1,213 @@ +import {dep, enrichFPD} from '../../../src/fpd/enrichment.js'; +import {hook} from '../../../src/hook.js'; +import {expect} from 'chai/index.mjs'; +import {config} from 'src/config.js'; + +describe('FPD enrichment', () => { + let sandbox; + before(() => { + hook.ready(); + }); + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + afterEach(() => { + sandbox.restore(); + config.resetConfig(); + }); + + function fpd(ortb2 = {}) { + return enrichFPD(Promise.resolve(ortb2)); + } + + function mockWindow() { + return { + innerHeight: 1, + innerWidth: 1, + navigator: { + language: '' + }, + document: { + querySelector: sinon.stub() + } + }; + } + + function testWindows(getWindow, fn) { + Object.entries({ + 'top': ['getWindowTop', 'getWindowSelf'], + 'self': ['getWindowSelf', 'getWindowTop'] + }).forEach(([t, [winWorks, winThrows]]) => { + describe(`using window.${t}`, () => { + beforeEach(() => { + sandbox.stub(dep, winWorks).callsFake(getWindow); + sandbox.stub(dep, winThrows).throws(new Error()); + }); + fn(); + }); + }); + } + + describe('site', () => { + it('sets page, ref, domain, and publisher.domain', () => { + const refererInfo = { + page: 'www.example.com', + ref: 'referrer.com' + }; + sandbox.stub(dep, 'getRefererInfo').callsFake(() => refererInfo); + sandbox.stub(dep, 'findRootDomain').callsFake((dom) => `publisher.${dom}`); + return fpd().then(ortb2 => { + sinon.assert.match(ortb2.site, { + page: 'www.example.com', + domain: 'example.com', + ref: 'referrer.com', + publisher: { + domain: 'publisher.example.com' + } + }); + }); + }); + + describe('keywords', () => { + let metaTag; + beforeEach(() => { + metaTag = document.createElement('meta'); + metaTag.name = 'keywords'; + metaTag.content = 'kw1, kw2'; + document.head.appendChild(metaTag); + }); + afterEach(() => { + document.head.removeChild(metaTag); + }); + + testWindows(() => window, () => { + it(`sets kewwords from meta tag`, () => { + return fpd().then(ortb2 => { + expect(ortb2.site.keywords).to.eql('kw1,kw2'); + }); + }); + }); + }); + + it('should not set keywords if meta tag is not present', () => { + return fpd().then(ortb2 => { + expect(ortb2.site.hasOwnProperty('keywords')).to.be.false; + }); + }); + + it('respects pub-provided fpd', () => { + return fpd({ + site: { + publisher: { + domain: 'pub.com' + } + } + }).then(ortb2 => { + expect(ortb2.site.publisher.domain).to.eql('pub.com'); + }); + }); + }); + + describe('device', () => { + let win; + beforeEach(() => { + win = mockWindow(); + }); + testWindows(() => win, () => { + it('sets w/h', () => { + win.innerHeight = 123; + win.innerWidth = 321; + return fpd().then(ortb2 => { + sinon.assert.match(ortb2.device, { + w: 321, + h: 123, + }); + }); + }); + + it('sets ua', () => { + win.navigator.userAgent = 'mock-ua'; + return fpd().then(ortb2 => { + expect(ortb2.device.ua).to.eql('mock-ua'); + }) + }); + + it('sets language', () => { + win.navigator.language = 'lang-ignored'; + return fpd().then(ortb2 => { + expect(ortb2.device.language).to.eql('lang'); + }) + }); + }); + }); + + describe('regs', () => { + describe('gpc', () => { + let win; + beforeEach(() => { + win = mockWindow(); + }); + testWindows(() => win, () => { + it('is set if globalPrivacyControl is set', () => { + win.navigator.globalPrivacyControl = true; + return fpd().then(ortb2 => { + expect(ortb2.regs.ext.gpc).to.eql(1); + }); + }); + + it('is not set otherwise', () => { + return fpd().then(ortb2 => { + expect(ortb2.regs?.ext?.gpc).to.not.exist; + }) + }) + }); + }) + describe('coppa', () => { + [[true, 1], [false, 0]].forEach(([cfgVal, regVal]) => { + it(`is set to ${regVal} if config = ${cfgVal}`, () => { + config.setConfig({coppa: cfgVal}); + return fpd().then(ortb2 => { + expect(ortb2.regs.coppa).to.eql(regVal); + }) + }); + }) + + it('is not set if not configured', () => { + return fpd().then(ortb2 => { + expect(ortb2.regs?.coppa).to.not.exist; + }) + }) + }); + }); + + describe('sua', () => { + it('does not set device.sua if resolved sua is null', () => { + sandbox.stub(dep, 'getHighEntropySUA').returns(Promise.resolve()) + return fpd().then(ortb2 => { + expect(ortb2.device.sua).to.not.exist; + }) + }); + it('uses low entropy values if uaHints is []', () => { + sandbox.stub(dep, 'getLowEntropySUA').callsFake(() => ({mock: 'sua'})); + config.setConfig({ + firstPartyData: { + uaHints: [], + } + }) + return fpd().then(ortb2 => { + expect(ortb2.device.sua).to.eql({mock: 'sua'}); + }) + }); + it('uses high entropy values otherwise', () => { + sandbox.stub(dep, 'getHighEntropySUA').callsFake((hints) => Promise.resolve({hints})); + config.setConfig({ + firstPartyData: { + uaHints: ['h1', 'h2'] + } + }); + return fpd().then(ortb2 => { + expect(ortb2.device.sua).to.eql({hints: ['h1', 'h2']}) + }) + }); + }); +}); diff --git a/test/spec/fpd/gdpr_spec.js b/test/spec/fpd/gdpr_spec.js new file mode 100644 index 00000000000..8fc04815112 --- /dev/null +++ b/test/spec/fpd/gdpr_spec.js @@ -0,0 +1,47 @@ +import {gdprDataHandler} from '../../../src/adapterManager.js'; +import {enrichFPDHook} from '../../../modules/consentManagement.js'; + +describe('GDPR FPD enrichment', () => { + let sandbox, consent; + beforeEach(() => { + consent = null; + sandbox = sinon.sandbox.create(); + sandbox.stub(gdprDataHandler, 'getConsentData').callsFake(() => consent); + }); + afterEach(() => { + sandbox.restore(); + }) + + function callHook() { + let result; + enrichFPDHook((res) => { result = res }, Promise.resolve({})); + return result; + } + + it('sets gdpr properties from gdprDataHandler', () => { + consent = {gdprApplies: true, consentString: 'consent'}; + return callHook().then(ortb2 => { + expect(ortb2.regs.ext.gdpr).to.eql(1); + expect(ortb2.user.ext.consent).to.eql('consent'); + }) + }); + + it('does not set it if missing', () => { + return callHook().then((ortb2) => { + expect(ortb2).to.eql({}); + }) + }); + + it('sets user.ext.consent, but not regs.ext.gdpr, if gpdrApplies is not a boolean', () => { + consent = {consentString: 'mock-consent'}; + return callHook().then(ortb2 => { + expect(ortb2).to.eql({ + user: { + ext: { + consent: 'mock-consent' + } + } + }) + }) + }); +}); diff --git a/test/spec/fpd/rootDomain_spec.js b/test/spec/fpd/rootDomain_spec.js new file mode 100644 index 00000000000..008ef749edc --- /dev/null +++ b/test/spec/fpd/rootDomain_spec.js @@ -0,0 +1,61 @@ +import {expect} from 'chai/index.js'; +import {findRootDomain, coreStorage} from 'src/fpd/rootDomain.js'; + +describe('findRootDomain', function () { + let sandbox, cookies, rejectDomain; + + beforeEach(function () { + findRootDomain.clear(); + cookies = {}; + rejectDomain = ''; + sandbox = sinon.createSandbox(); + sandbox.stub(coreStorage, 'cookiesAreEnabled').returns(true); + sandbox.stub(coreStorage, 'setCookie').callsFake((cookie, value, expiration, sameSite, domain) => { + if (rejectDomain !== domain) { + if (new Date(expiration) <= Date.now()) { + delete cookies[cookie]; + } else { + cookies[cookie] = value; + } + } + }) + sandbox.stub(coreStorage, 'getCookie').callsFake((cookie) => { + return cookies[cookie] + }); + }); + + afterEach(function () { + sandbox.restore(); + }); + + after(() => { + findRootDomain.clear(); + }) + + it('should just find the root domain', function () { + rejectDomain = 'co.uk'; + var domain = findRootDomain('sub.realdomain.co.uk'); + expect(domain).to.be.eq('realdomain.co.uk'); + expect(cookies).to.eql({}); + }); + + it('should find the full domain when no subdomain is present', function () { + rejectDomain = 'co.uk'; + var domain = findRootDomain('realdomain.co.uk'); + expect(domain).to.be.eq('realdomain.co.uk'); + expect(cookies).to.eql({}); + }); + + it('should return domain as-is if cookies are disabled', () => { + coreStorage.cookiesAreEnabled.returns(false); + expect(findRootDomain('sub.example.com')).to.eql('sub.example.com'); + sinon.assert.notCalled(coreStorage.setCookie); + }); + + it('should memoize default value', () => { + const domain = findRootDomain(); + expect(domain.length > 0).to.be.true; + expect(findRootDomain()).to.eql(domain); + sinon.assert.calledOnce(coreStorage.getCookie); + }); +}); diff --git a/test/spec/fpd/usp_spec.js b/test/spec/fpd/usp_spec.js new file mode 100644 index 00000000000..f616b086ffa --- /dev/null +++ b/test/spec/fpd/usp_spec.js @@ -0,0 +1,36 @@ +import {enrichFPDHook} from '../../../modules/consentManagementUsp.js'; +import {uspDataHandler} from '../../../src/adapterManager.js'; + +describe('FPD enrichment USP', () => { + let sandbox, consent; + beforeEach(() => { + consent = null; + sandbox = sinon.sandbox.create(); + sandbox.stub(uspDataHandler, 'getConsentData').callsFake(() => consent); + }); + + afterEach(() => { + sandbox.restore(); + }); + + function callHook() { + let result; + enrichFPDHook((res) => { + result = res; + }, Promise.resolve({})); + return result; + } + + it('sets regs.ext.us_privacy from uspDataHandler', () => { + consent = '1NN'; + return callHook().then(ortb2 => { + expect(ortb2.regs.ext.us_privacy).to.eql('1NN'); + }) + }); + + it('does not set if missing', () => { + return callHook().then(ortb2 => { + expect(ortb2).to.eql({}); + }) + }); +}); diff --git a/test/spec/modules/enrichmentFpdModule_spec.js b/test/spec/modules/enrichmentFpdModule_spec.js index 38853f1528c..e69de29bb2d 100644 --- a/test/spec/modules/enrichmentFpdModule_spec.js +++ b/test/spec/modules/enrichmentFpdModule_spec.js @@ -1,159 +0,0 @@ -import { expect } from 'chai'; -import {config} from 'src/config.js'; -import { getRefererInfo } from 'src/refererDetection.js'; -import {processFpd, coreStorage, resetEnrichments} from 'modules/enrichmentFpdModule.js'; -import * as enrichmentModule from 'modules/enrichmentFpdModule.js'; -import {GreedyPromise} from '../../../src/utils/promise.js'; - -describe('the first party data enrichment module', function() { - let width; - let widthStub; - let height; - let heightStub; - let querySelectorStub; - let coreStorageStub; - let canonical; - let keywords; - let lowEntropySuaStub; - let highEntropySuaStub; - - before(function() { - canonical = document.createElement('link'); - canonical.rel = 'canonical'; - keywords = document.createElement('meta'); - keywords.name = 'keywords'; - }); - - beforeEach(function() { - resetEnrichments(); - querySelectorStub = sinon.stub(window.top.document, 'querySelector'); - querySelectorStub.withArgs("link[rel='canonical']").returns(canonical); - querySelectorStub.withArgs("meta[name='keywords']").returns(keywords); - widthStub = sinon.stub(window.top, 'innerWidth').get(function() { - return width; - }); - heightStub = sinon.stub(window.top, 'innerHeight').get(function() { - return height; - }); - coreStorageStub = sinon.stub(coreStorage, 'getCookie'); - coreStorageStub - .onFirstCall() - .returns(null) // co.uk - .onSecondCall() - .returns('writeable'); // domain.co.uk - lowEntropySuaStub = sinon.stub(enrichmentModule.sua, 'le').callsFake(() => null); - highEntropySuaStub = sinon.stub(enrichmentModule.sua, 'he').callsFake(() => GreedyPromise.resolve()); - }); - - afterEach(function() { - widthStub.restore(); - heightStub.restore(); - querySelectorStub.restore(); - coreStorageStub.restore(); - canonical = document.createElement('link'); - canonical.rel = 'canonical'; - keywords = document.createElement('meta'); - keywords.name = 'keywords'; - lowEntropySuaStub.restore(); - highEntropySuaStub.restore(); - }); - - function syncProcessFpd(fpdConf, ortb2Fragments) { - let result; - processFpd(fpdConf, ortb2Fragments).then((res) => { result = res; }); - return result; - }; - - it('adds ref and device values', function() { - width = 800; - height = 500; - - let validated = syncProcessFpd({}, {}).global; - - const {ref, page, domain} = getRefererInfo(); - expect(validated.site.ref).to.equal(ref || undefined); - expect(validated.site.page).to.equal(page || undefined) - expect(validated.site.domain).to.equal(domain || undefined) - expect(validated.device).to.deep.equal({ w: 800, h: 500 }); - expect(validated.site.keywords).to.be.undefined; - }); - - it('adds page domain values if pageUrl url exists', function() { - config.setConfig({'pageUrl': 'https://www.subdomain.domain.co.uk/path?query=12345'}); - width = 800; - height = 500; - - let validated = syncProcessFpd({}, {}).global; - - expect(validated.site.ref).to.equal(getRefererInfo().ref || undefined); - expect(validated.site.page).to.equal('https://www.subdomain.domain.co.uk/path?query=12345'); - expect(validated.site.domain).to.equal('subdomain.domain.co.uk'); - expect(validated.site.publisher.domain).to.equal('domain.co.uk'); - expect(validated.device).to.deep.equal({ w: 800, h: 500 }); - expect(validated.site.keywords).to.be.undefined; - }); - - it('adds keyword value if keyword meta content exists', function() { - width = 800; - height = 500; - keywords.content = 'value1,value2,value3'; - - let validated = syncProcessFpd({}, {}).global; - - expect(validated.site.keywords).to.equal('value1,value2,value3'); - }); - - it('does not overwrite existing data from getConfig ortb2', function() { - width = 800; - height = 500; - - let validated = syncProcessFpd({}, {global: {device: {w: 1200, h: 700}, site: {ref: 'https://someUrl.com', page: 'test.com'}}}).global; - - expect(validated.site.ref).to.equal('https://someUrl.com'); - expect(validated.site.page).to.equal('test.com'); - expect(validated.device).to.deep.equal({ w: 1200, h: 700 }); - expect(validated.site.keywords).to.be.undefined; - }); - - it('does not run enrichments again on the second call', () => { - width = 1; - height = 2; - const first = syncProcessFpd({}, {}).global; - width = 3; - const second = syncProcessFpd({}, {}).global; - expect(first).to.eql(second); - }); - - describe('device.sua', () => { - it('does not set device.sua if resolved sua is null', () => { - const sua = syncProcessFpd({}, {}).global.device?.sua; - expect(sua).to.not.exist; - }); - it('uses low entropy values if uaHints is []', () => { - lowEntropySuaStub.callsFake(() => ({mock: 'sua'})); - const sua = syncProcessFpd({uaHints: []}, {}).global.device.sua; - expect(sua).to.eql({mock: 'sua'}); - }); - it('uses high entropy values otherwise', () => { - highEntropySuaStub.callsFake((hints) => GreedyPromise.resolve({hints})); - const sua = syncProcessFpd({uaHints: ['h1', 'h2']}, {}).global.device.sua; - expect(sua).to.eql({hints: ['h1', 'h2']}); - }) - }) - - it('should store a reference to gpc witin ortb2.regs.ext if it has been enabled', function() { - let validated; - width = 800; - height = 500; - - validated = syncProcessFpd({}, {}).global; - expect(validated.regs).to.equal(undefined); - - resetEnrichments(); - - const globalPrivacyControlStub = sinon.stub(window, 'navigator').value({globalPrivacyControl: true}); - validated = syncProcessFpd({}, {}).global; - expect(validated.regs.ext.gpc).to.equal(1); - globalPrivacyControlStub.restore(); - }); -}); diff --git a/test/spec/modules/fpdModule_spec.js b/test/spec/modules/fpdModule_spec.js index 7d41fbb55e1..4536b304f9d 100644 --- a/test/spec/modules/fpdModule_spec.js +++ b/test/spec/modules/fpdModule_spec.js @@ -1,16 +1,14 @@ import {expect} from 'chai'; import {config} from 'src/config.js'; -import {getRefererInfo} from 'src/refererDetection.js'; -import {processFpd, registerSubmodules, startAuctionHook, reset} from 'modules/fpdModule/index.js'; -import * as enrichmentModule from 'modules/enrichmentFpdModule.js'; -import * as validationModule from 'modules/validationFpdModule/index.js'; -import {resetEnrichments} from 'modules/enrichmentFpdModule.js'; -import {GreedyPromise} from '../../../src/utils/promise.js'; +import {registerSubmodules, reset, startAuctionHook} from 'modules/fpdModule/index.js'; describe('the first party data module', function () { afterEach(function () { config.resetConfig(); }); + after(() => { + reset(); + }) describe('startAuctionHook', () => { const mockFpd = { @@ -50,282 +48,4 @@ describe('the first party data module', function () { }); }); }); - - describe('first party data intitializing', function () { - let width; - let widthStub; - let height; - let heightStub; - let querySelectorStub; - let canonical; - let keywords; - let lowEntropySuaStub; - let highEntropySuaStub; - - before(function() { - reset(); - registerSubmodules(enrichmentModule); - registerSubmodules(validationModule); - - canonical = document.createElement('link'); - canonical.rel = 'canonical'; - keywords = document.createElement('meta'); - keywords.name = 'keywords'; - }); - - beforeEach(function() { - resetEnrichments(); - querySelectorStub = sinon.stub(window.top.document, 'querySelector'); - querySelectorStub.withArgs("link[rel='canonical']").returns(canonical); - querySelectorStub.withArgs("meta[name='keywords']").returns(keywords); - widthStub = sinon.stub(window.top, 'innerWidth').get(function () { - return width; - }); - heightStub = sinon.stub(window.top, 'innerHeight').get(function () { - return height; - }); - lowEntropySuaStub = sinon.stub(enrichmentModule.sua, 'le').callsFake(() => null); - highEntropySuaStub = sinon.stub(enrichmentModule.sua, 'he').callsFake(() => GreedyPromise.resolve()); - }); - - afterEach(function() { - widthStub.restore(); - heightStub.restore(); - querySelectorStub.restore(); - canonical = document.createElement('link'); - canonical.rel = 'canonical'; - keywords = document.createElement('meta'); - keywords.name = 'keywords'; - lowEntropySuaStub.restore(); - highEntropySuaStub.restore(); - }); - - it('filters ortb2 data that is set', function () { - const global = { - user: { - data: {}, - gender: 'f', - age: 45 - }, - site: { - content: { - data: [{ - segment: { - test: 1 - }, - name: 'foo' - }, { - segment: [{ - id: 'test' - }, { - id: 3 - }], - name: 'bar' - }] - } - }, - device: { - w: 1, - h: 1 - } - }; - - config.setConfig({'pageUrl': 'https://www.domain.com/path?query=12345'}); - width = 1120; - height = 750; - - return processFpd({global}).then(({global: validated}) => { - expect(validated.site.ref).to.equal(getRefererInfo().ref || undefined); - expect(validated.site.page).to.equal('https://www.domain.com/path?query=12345'); - expect(validated.site.domain).to.equal('domain.com'); - expect(validated.site.content.data).to.deep.equal([{segment: [{id: 'test'}], name: 'bar'}]); - expect(validated.user.data).to.be.undefined; - expect(validated.device).to.deep.to.equal({w: 1, h: 1}); - expect(validated.site.keywords).to.be.undefined; - }); - }); - - it('should not overwrite existing data with default settings', function () { - const global = { - site: { - ref: 'https://referer.com' - } - }; - - return processFpd({global}).then(({global: validated}) => { - expect(validated.site.ref).to.equal('https://referer.com'); - }); - }); - - it('should allow overwrite default data with setConfig', function () { - const global = { - site: { - ref: 'https://referer.com' - } - }; - - return processFpd({global}).then(({global: validated}) => { - expect(validated.site.ref).to.equal('https://referer.com'); - }); - }); - - it('should filter all data', function () { - let global = { - imp: [], - site: { - name: 123, - domain: 456, - page: 789, - ref: 987, - keywords: ['keywords'], - search: 654, - cat: 'cat', - sectioncat: 'sectioncat', - pagecat: 'pagecat', - content: { - data: [{ - name: 1, - segment: [] - }] - } - }, - user: { - yob: 'twenty', - gender: 0, - keywords: ['foobar'], - data: ['test'] - }, - device: [800, 450], - cur: { - adServerCurrency: 'USD' - } - }; - config.setConfig({'firstPartyData': {skipEnrichments: true}}); - return processFpd({global}).then(({global: validated}) => { - expect(validated).to.deep.equal({}); - }); - }); - - it('should add enrichments but not alter any arbitrary ortb2 data', function () { - let global = { - site: { - ext: { - data: { - inventory: ['value1'] - } - } - }, - user: { - ext: { - data: { - visitor: ['value2'] - } - } - }, - cur: ['USD'] - }; - return processFpd({global}).then(({global: validated}) => { - expect(validated.site.ref).to.equal(getRefererInfo().referer); - expect(validated.site.ext.data).to.deep.equal({inventory: ['value1']}); - expect(validated.user.ext.data).to.deep.equal({visitor: ['value2']}); - expect(validated.cur).to.deep.equal(['USD']); - }) - }); - - it('should filter bidderConfig data', function () { - let bidder = { - bidderA: { - site: { - keywords: 'other', - ref: 'https://domain.com' - }, - user: { - keywords: 'test', - data: [{ - segment: [{id: 4}], - name: 't' - }] - } - } - }; - - return processFpd({bidder}).then(({bidder: validated}) => { - expect(validated.bidderA).to.not.be.undefined; - expect(validated.bidderA.user.data).to.be.undefined; - expect(validated.bidderA.user.keywords).to.equal('test'); - expect(validated.bidderA.site.keywords).to.equal('other'); - expect(validated.bidderA.site.ref).to.equal('https://domain.com'); - }) - }); - - it('should not filter bidderConfig data as it is valid', function () { - let bidder = { - bidderA: { - site: { - keywords: 'other', - ref: 'https://domain.com' - }, - user: { - keywords: 'test', - data: [{ - segment: [{id: 'data1_id'}], - name: 'data1' - }] - } - } - }; - - return processFpd({bidder}).then(({bidder: validated}) => { - expect(validated.bidderA).to.not.be.undefined; - expect(validated.bidderA.user.data).to.deep.equal([{segment: [{id: 'data1_id'}], name: 'data1'}]); - expect(validated.bidderA.user.keywords).to.equal('test'); - expect(validated.bidderA.site.keywords).to.equal('other'); - expect(validated.bidderA.site.ref).to.equal('https://domain.com'); - }); - }); - - it('should not set default values if skipEnrichments is turned on', function () { - config.setConfig({'firstPartyData': {skipEnrichments: true}}); - - let global = { - site: { - keywords: 'other' - }, - user: { - keywords: 'test', - data: [{ - segment: [{id: 'data1_id'}], - name: 'data1' - }] - } - }; - - return processFpd({global}).then(({global: validated}) => { - expect(validated.device).to.be.undefined; - expect(validated.site.ref).to.be.undefined; - expect(validated.site.page).to.be.undefined; - expect(validated.site.domain).to.be.undefined; - }); - }); - - it('should not validate ortb2 data if skipValidations is turned on', function () { - config.setConfig({'firstPartyData': {skipValidations: true}}); - - let global = { - site: { - keywords: 'other' - }, - user: { - keywords: 'test', - data: [{ - segment: [{id: 'nonfiltered'}] - }] - } - }; - - return processFpd({global}).then(({global: validated}) => { - expect(validated.user.data).to.deep.equal([{segment: [{id: 'nonfiltered'}]}]); - }); - }); - }); }); diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js index b3b01dc93b5..400b9145e0b 100644 --- a/test/spec/modules/improvedigitalBidAdapter_spec.js +++ b/test/spec/modules/improvedigitalBidAdapter_spec.js @@ -15,6 +15,8 @@ import 'modules/consentManagementUsp.js'; import 'modules/schain.js'; import {decorateAdUnitsWithNativeParams, toLegacyResponse} from '../../../src/native.js'; import {createEidsArray} from '../../../modules/userId/eids.js'; +import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js'; +import {hook} from '../../../src/hook.js'; describe('Improve Digital Adapter Tests', function () { const METHOD = 'POST'; @@ -168,6 +170,10 @@ describe('Improve Digital Adapter Tests', function () { return bidRequests; } + before(() => { + hook.ready(); + }); + describe('isBidRequestValid', function () { it('should return false when no bid', function () { expect(spec.isBidRequestValid()).to.equal(false); @@ -220,7 +226,7 @@ describe('Improve Digital Adapter Tests', function () { it('should make a well-formed request objects', function () { getConfigStub = sinon.stub(config, 'getConfig'); getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true); - const request = spec.buildRequests([simpleBidRequest], bidderRequest)[0]; + const request = spec.buildRequests([simpleBidRequest], syncAddFPDToBidderRequest(bidderRequest))[0]; expect(request).to.be.an('object'); expect(request.method).to.equal(METHOD); expect(request.url).to.equal(AD_SERVER_URL); @@ -390,7 +396,7 @@ describe('Improve Digital Adapter Tests', function () { it('should add GDPR consent string', function () { const bidRequest = Object.assign({}, simpleBidRequest); - const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdpr)[0].data); + const payload = JSON.parse(spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestGdpr))[0].data); expect(payload.regs.ext.gdpr).to.exist.and.to.equal(1); expect(payload.user.ext.consent).to.equal('CONSENT'); expect(payload.user.ext.ConsentedProvidersSettings).to.not.exist; @@ -401,13 +407,13 @@ describe('Improve Digital Adapter Tests', function () { const bidderRequestGdprEmptyAddtl = deepClone(bidderRequestGdpr); bidderRequestGdprEmptyAddtl.gdprConsent.addtlConsent = '1~'; const bidRequest = Object.assign({}, simpleBidRequest); - const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdprEmptyAddtl)[0].data); + const payload = JSON.parse(spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestGdprEmptyAddtl))[0].data); expect(payload.user.ext.consented_providers_settings).to.not.exist; }); it('should add ConsentedProvidersSettings when extend mode enabled', function () { const bidRequest = deepClone(extendBidRequest); - const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdpr)[0].data); + const payload = JSON.parse(spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestGdpr))[0].data); expect(payload.regs.ext.gdpr).to.exist.and.to.equal(1); expect(payload.user.ext.consent).to.equal('CONSENT'); expect(payload.user.ext.ConsentedProvidersSettings.consented_providers).to.exist.and.to.equal('1~1.35.41.101'); @@ -416,7 +422,7 @@ describe('Improve Digital Adapter Tests', function () { it('should add CCPA consent string', function () { const bidRequest = Object.assign({}, simpleBidRequest); - const request = spec.buildRequests([bidRequest], {...bidderRequest, ...{ uspConsent: '1YYY' }}); + const request = spec.buildRequests([bidRequest], syncAddFPDToBidderRequest({...bidderRequest, ...{ uspConsent: '1YYY' }})); const payload = JSON.parse(request[0].data); expect(payload.regs.ext.us_privacy).to.equal('1YYY'); }); @@ -425,17 +431,17 @@ describe('Improve Digital Adapter Tests', function () { getConfigStub = sinon.stub(config, 'getConfig'); getConfigStub.withArgs('coppa').returns(true); let bidRequest = Object.assign({}, simpleBidRequest); - let payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdpr)[0].data); + let payload = JSON.parse(spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestGdpr))[0].data); expect(payload.regs.coppa).to.equal(1); getConfigStub.withArgs('coppa').returns(false); bidRequest = Object.assign({}, simpleBidRequest); - payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequestGdpr)[0].data); + payload = JSON.parse(spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestGdpr))[0].data); expect(payload.regs.coppa).to.equal(0); }); it('should add referrer', function () { const bidRequest = Object.assign({}, simpleBidRequest); - const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0]; + const request = spec.buildRequests([bidRequest], syncAddFPDToBidderRequest(bidderRequestReferrer))[0]; const payload = JSON.parse(request.data); expect(payload.site.page).to.equal('https://blah.com/test.html'); }); @@ -678,21 +684,21 @@ describe('Improve Digital Adapter Tests', function () { page: 'https://improveditigal.com/', domain: 'improveditigal.com' }); - let request = spec.buildRequests([simpleBidRequest], bidderRequestReferrer)[0]; + let request = spec.buildRequests([simpleBidRequest], syncAddFPDToBidderRequest(bidderRequestReferrer))[0]; let payload = JSON.parse(request.data); expect(payload.site.content).does.exist.and.equal('XYZ'); expect(payload.site.page).does.exist.and.equal('https://improveditigal.com/'); expect(payload.site.domain).does.exist.and.equal('improveditigal.com'); getConfigStub.reset(); - request = spec.buildRequests([simpleBidRequest], bidderRequestReferrer)[0]; + request = spec.buildRequests([simpleBidRequest], syncAddFPDToBidderRequest(bidderRequestReferrer))[0]; payload = JSON.parse(request.data); expect(payload.site.content).does.not.exist; expect(payload.site.page).does.exist.and.equal('https://blah.com/test.html'); expect(payload.site.domain).does.exist.and.equal('blah.com'); const ortb2 = {site: {content: 'ZZZ'}}; - request = spec.buildRequests([simpleBidRequest], {...bidderRequestReferrer, ortb2})[0]; + request = spec.buildRequests([simpleBidRequest], syncAddFPDToBidderRequest({...bidderRequestReferrer, ortb2}))[0]; payload = JSON.parse(request.data); expect(payload.site.content).does.exist.and.equal('ZZZ'); expect(payload.site.page).does.exist.and.equal('https://blah.com/test.html'); diff --git a/test/spec/modules/openxOrtbBidAdapter_spec.js b/test/spec/modules/openxOrtbBidAdapter_spec.js index 09e76d6ca7a..be6427f607b 100644 --- a/test/spec/modules/openxOrtbBidAdapter_spec.js +++ b/test/spec/modules/openxOrtbBidAdapter_spec.js @@ -14,10 +14,16 @@ import 'modules/consentManagement.js'; import 'modules/consentManagementUsp.js'; import 'modules/schain.js'; import {deepClone} from 'src/utils.js'; +import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js'; +import {hook} from '../../../src/hook.js'; const DEFAULT_SYNC = SYNC_URL + '?ph=' + DEFAULT_PH; describe('OpenxRtbAdapter', function () { + before(() => { + hook.ready(); + }); + const adapter = newBidder(spec); describe('inherited functions', function () { @@ -634,14 +640,14 @@ describe('OpenxRtbAdapter', function () { }); it('should send a signal to specify that US Privacy applies to this request', function () { - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.regs.ext.us_privacy).to.equal('1YYN'); expect(request[1].data.regs.ext.us_privacy).to.equal('1YYN'); }); it('should not send the regs object, when consent string is undefined', function () { delete bidderRequest.uspConsent; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.regs?.us_privacy).to.not.exist; }); }); @@ -676,21 +682,21 @@ describe('OpenxRtbAdapter', function () { it('should send a signal to specify that GDPR applies to this request', function () { bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.regs.ext.gdpr).to.equal(1); expect(request[1].data.regs.ext.gdpr).to.equal(1); }); it('should send the consent string', function () { bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); }); it('should send the addtlConsent string', function () { bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent); expect(request[1].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent); }); @@ -698,7 +704,7 @@ describe('OpenxRtbAdapter', function () { it('should send a signal to specify that GDPR does not apply to this request', function () { bidderRequest.gdprConsent.gdprApplies = false; bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.regs.ext.gdpr).to.equal(0); expect(request[1].data.regs.ext.gdpr).to.equal(0); }); @@ -707,7 +713,7 @@ describe('OpenxRtbAdapter', function () { 'but can send consent data, ', function () { delete bidderRequest.gdprConsent.gdprApplies; bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.regs?.ext?.gdpr).to.not.be.ok; expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); @@ -716,7 +722,7 @@ describe('OpenxRtbAdapter', function () { it('when consent string is undefined, should not send the consent string, ', function () { delete bidderRequest.gdprConsent.consentString; bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); expect(request[0].data.imp[0].ext.consent).to.equal(undefined); expect(request[1].data.imp[0].ext.consent).to.equal(undefined); }); @@ -725,7 +731,7 @@ describe('OpenxRtbAdapter', function () { context('coppa', function() { it('when there are no coppa param settings, should not send a coppa flag', function () { - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.regs?.coppa).to.be.not.ok; }); @@ -738,7 +744,7 @@ describe('OpenxRtbAdapter', function () { return utils.deepAccess(mockConfig, key); }); - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.regs.coppa).to.equal(1); }); @@ -760,21 +766,21 @@ describe('OpenxRtbAdapter', function () { it('when there is a do not track, should send a dnt', function () { doNotTrackStub.returns(1); - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.device.dnt).to.equal(1); }); it('when there is not do not track, don\'t send dnt', function () { doNotTrackStub.returns(0); - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.device.dnt).to.equal(0); }); it('when there is no defined do not track, don\'t send dnt', function () { doNotTrackStub.returns(null); - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest)); expect(request[0].data.device.dnt).to.equal(0); }); }); @@ -1503,5 +1509,4 @@ describe('OpenxRtbAdapter', function () { }); }); }); -}) -; +}); diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index f5f77e61056..9da242381be 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1,4 +1,4 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import { PrebidServer as Adapter, resetSyncedStatus, @@ -7,31 +7,30 @@ import { } 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 {deepAccess, deepClone} from 'src/utils.js'; +import {ajax} from 'src/ajax.js'; +import {config} from 'src/config.js'; import * as 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'; -import { deepAccess, deepClone } from 'src/utils.js'; -import 'modules/appnexusBidAdapter.js' // appnexus alias test -import 'modules/rubiconBidAdapter.js' // rubicon alias test -import 'src/prebid.js' // $$PREBID_GLOBAL$$.aliasBidder test -import 'modules/currency.js' // adServerCurrency test -// also load modules that register ORTB processors -import 'modules/currency.js'; +import {server} from 'test/mocks/xhr.js'; +import {createEidsArray} from 'modules/userId/eids.js'; +import 'modules/appnexusBidAdapter.js'; // appnexus alias test +import 'modules/rubiconBidAdapter.js'; // rubicon alias test +import 'src/prebid.js'; // $$PREBID_GLOBAL$$.aliasBidder test +import 'modules/currency.js'; // adServerCurrency test import 'modules/userId/index.js'; import 'modules/multibid/index.js'; import 'modules/priceFloors.js'; import 'modules/consentManagement.js'; import 'modules/consentManagementUsp.js'; import 'modules/schain.js'; -import { hook } from '../../../src/hook.js'; -import { decorateAdUnitsWithNativeParams } from '../../../src/native.js'; -import { auctionManager } from '../../../src/auctionManager.js'; -import { stubAuctionIndex } from '../../helpers/indexStub.js'; -import { registerBidder } from 'src/adapters/bidderFactory.js'; +import {hook} from '../../../src/hook.js'; +import {decorateAdUnitsWithNativeParams} from '../../../src/native.js'; +import {auctionManager} from '../../../src/auctionManager.js'; +import {stubAuctionIndex} from '../../helpers/indexStub.js'; +import {registerBidder} from 'src/adapters/bidderFactory.js'; import {getGlobal} from '../../../src/prebidGlobal.js'; +import {syncAddFPDEnrichments, syncAddFPDToBidderRequest} from '../../helpers/fpd.js'; let CONFIG = { accountId: '1', @@ -544,6 +543,16 @@ const RESPONSE_OPENRTB_NATIVE = { ] }; +function addFpdEnrichmentsToS2SRequest(s2sReq, bidderRequests) { + return { + ...s2sReq, + ortb2Fragments: { + ...(s2sReq.ortb2Fragments || {}), + global: syncAddFPDToBidderRequest({...(bidderRequests?.[0] || {}), ortb2: s2sReq.ortb2Fragments?.global || {}}).ortb2 + } + } +} + describe('S2S Adapter', function () { let adapter, addBidResponse = sinon.spy(), @@ -766,7 +775,7 @@ describe('S2S Adapter', function () { let gdprBidRequest = utils.deepClone(BID_REQUESTS); gdprBidRequest[0].gdprConsent = mockConsent(); - adapter.callBids(REQUEST, gdprBidRequest, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, gdprBidRequest), gdprBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.gdpr).is.equal(1); @@ -775,7 +784,7 @@ describe('S2S Adapter', function () { config.resetConfig(); config.setConfig({ s2sConfig: CONFIG }); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); requestBid = JSON.parse(server.requests[1].requestBody); expect(requestBid.regs).to.not.exist; @@ -791,7 +800,7 @@ describe('S2S Adapter', function () { addtlConsent: 'superduperconsent', }); - adapter.callBids(REQUEST, gdprBidRequest, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, gdprBidRequest), gdprBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.gdpr).is.equal(1); @@ -877,13 +886,13 @@ describe('S2S Adapter', function () { $$PREBID_GLOBAL$$.requestBids.removeAll(); }); - it('is added to ortb2 request when in bidRequest', function () { + it('is added to ortb2 request when in FPD', function () { config.setConfig({ s2sConfig: CONFIG }); let uspBidRequest = utils.deepClone(BID_REQUESTS); uspBidRequest[0].uspConsent = '1NYN'; - adapter.callBids(REQUEST, uspBidRequest, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, uspBidRequest), uspBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.us_privacy).is.equal('1NYN'); @@ -891,7 +900,7 @@ describe('S2S Adapter', function () { config.resetConfig(); config.setConfig({ s2sConfig: CONFIG }); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); requestBid = JSON.parse(server.requests[1].requestBody); expect(requestBid.regs).to.not.exist; @@ -929,7 +938,7 @@ describe('S2S Adapter', function () { consentBidRequest[0].uspConsent = '1NYN'; consentBidRequest[0].gdprConsent = mockConsent(); - adapter.callBids(REQUEST, consentBidRequest, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, consentBidRequest), consentBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.us_privacy).is.equal('1NYN'); @@ -977,7 +986,7 @@ describe('S2S Adapter', function () { }; config.setConfig(_config); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); sinon.assert.match(requestBid.device, { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC', @@ -1004,7 +1013,7 @@ describe('S2S Adapter', function () { }; config.setConfig(_config); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); sinon.assert.match(requestBid.device, { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC', @@ -1367,7 +1376,7 @@ describe('S2S Adapter', function () { }; config.setConfig(_config); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); sinon.assert.match(requestBid.device, { w: window.innerWidth, @@ -1474,7 +1483,7 @@ describe('S2S Adapter', function () { }; config.setConfig(_config); - adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(REQUEST, BID_REQUESTS), 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.publisher).to.exist.and.to.be.a('object'); @@ -1491,6 +1500,7 @@ describe('S2S Adapter', function () { content: { language: 'en' }, + domain: 'mytestpage.com', page: 'http://mytestpage.com' }); }); @@ -1815,7 +1825,7 @@ describe('S2S Adapter', function () { device: device }); - adapter.callBids(s2sBidRequest, BID_REQUESTS, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest(s2sBidRequest, BID_REQUESTS), BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.site).to.exist.and.to.be.a('object'); @@ -2343,7 +2353,11 @@ describe('S2S Adapter', function () { })); const commonContextExpected = utils.mergeDeep({ 'page': 'http://mytestpage.com', - 'publisher': { 'id': '1' } + 'domain': 'mytestpage.com', + 'publisher': { + 'id': '1', + 'domain': 'mytestpage.com' + } }, commonSite); const ortb2Fragments = { @@ -2351,7 +2365,7 @@ describe('S2S Adapter', function () { bidder: Object.fromEntries(allowedBidders.map(bidder => [bidder, {site, user, bcat, badv}])) }; - adapter.callBids({...s2sBidRequest, ortb2Fragments}, bidRequests, addBidResponse, done, ajax); + adapter.callBids(addFpdEnrichmentsToS2SRequest({...s2sBidRequest, ortb2Fragments}, bidRequests), bidRequests, addBidResponse, done, ajax); const parsedRequestBody = JSON.parse(server.requests[0].requestBody); expect(parsedRequestBody.ext.prebid.bidderconfig).to.deep.equal(expected); expect(parsedRequestBody.site).to.deep.equal(commonContextExpected); diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index f4abcc4b9f6..99e0681e547 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -2768,47 +2768,6 @@ describe('User ID', function () { }) }) }); - - describe('findRootDomain', function () { - let sandbox; - - beforeEach(function () { - init(config); - setSubmoduleRegistry([sharedIdSystemSubmodule]); - config.setConfig({ - userSync: { - syncDelay: 0, - userIds: [ - { - name: 'pubCommonId', - value: { pubcid: '11111' }, - }, - ], - }, - }); - sandbox = sinon.createSandbox(); - sandbox - .stub(coreStorage, 'getCookie') - .onFirstCall() - .returns(null) // .co.uk - .onSecondCall() - .returns('writeable'); // realdomain.co.uk; - }); - - afterEach(function () { - sandbox.restore(); - }); - - it('should just find the root domain', function () { - var domain = findRootDomain('sub.realdomain.co.uk'); - expect(domain).to.be.eq('realdomain.co.uk'); - }); - - it('should find the full domain when no subdomain is present', function () { - var domain = findRootDomain('realdomain.co.uk'); - expect(domain).to.be.eq('realdomain.co.uk'); - }); - }); }); describe('handles config with ESP configuration in user sync object', function() { diff --git a/test/spec/ortbConverter/default_processors_spec.js b/test/spec/ortbConverter/default_processors_spec.js deleted file mode 100644 index 28a35390b86..00000000000 --- a/test/spec/ortbConverter/default_processors_spec.js +++ /dev/null @@ -1,61 +0,0 @@ -import {setDevice, setSite} from '../../../libraries/ortbConverter/processors/default.js'; - -describe('setDevice', () => { - it('sets device.w, h, dnt, language, ua', () => { - const req = {}; - setDevice(req); - ['h', 'w', 'dnt', 'language', 'ua'].forEach(prop => expect(req.device[prop]).to.exist) - }); - - it('does not override FPD', () => { - const req = { - device: { - w: 'w', - h: 'h', - ext: {} - } - }; - setDevice(req); - sinon.assert.match(req.device, { - w: 'w', - h: 'h', - ext: {} - }) - }); -}); - -describe('setSite', () => { - const refererInfo = { - page: 'page.com', - ref: 'ref.com', - domain: 'domain.com' - }; - - it('sets site, domain, ref from refererInfo', () => { - const req = { - site: { - ext: {} - } - }; - setSite(req, {refererInfo}); - sinon.assert.match(req.site, refererInfo); - expect(req.site.ext).to.eql({}); - }); - - it('does not override FPD', () => { - const req = { - site: { - ref: 'other ref' - } - } - setSite(req, {refererInfo}); - expect(req.site.ref).to.eql('other ref'); - ['domain', 'page'].forEach(prop => expect(req.site[prop]).to.eql(refererInfo[prop])); - }); - - it('does not set null properties from refererInfo', () => { - const req = {}; - setSite(req, {refererInfo: {...refererInfo, ref: null}}); - expect(req.site.ref).to.not.exist; - }); -}); diff --git a/test/spec/ortbConverter/gdpr_spec.js b/test/spec/ortbConverter/gdpr_spec.js index 9851d7603b4..78fd1830438 100644 --- a/test/spec/ortbConverter/gdpr_spec.js +++ b/test/spec/ortbConverter/gdpr_spec.js @@ -1,33 +1,4 @@ -import {setOrtbAdditionalConsent, setOrtbGdpr} from '../../../modules/consentManagement.js'; - -describe('pbjs - ortb gpdr', () => { - it('sets gdpr properties from bidderRequest', () => { - const req = {}; - setOrtbGdpr(req, {gdprConsent: {gdprApplies: true, consentString: 'consent'}}); - expect(req.regs.ext.gdpr).to.eql(1); - expect(req.user.ext.consent).to.eql('consent'); - }); - - it('does not set it if missing', () => { - const req = {}; - setOrtbGdpr(req, {}); - expect(req).to.eql({}); - }); - - it('sets user.ext.consent, but not regs.ext.gdpr, if gpdrApplies is not a boolean', () => { - const req = {}; - setOrtbGdpr(req, { - gdprConsent: {consentString: 'mock-consent'} - }); - expect(req).to.eql({ - user: { - ext: { - consent: 'mock-consent' - } - } - }) - }); -}); +import {setOrtbAdditionalConsent} from '../../../modules/consentManagement.js'; describe('pbjs -> ortb addtlConsent', () => { it('sets ConsentedProvidersSettings', () => { diff --git a/test/spec/ortbConverter/usp_spec.js b/test/spec/ortbConverter/usp_spec.js deleted file mode 100644 index 01ff689cd97..00000000000 --- a/test/spec/ortbConverter/usp_spec.js +++ /dev/null @@ -1,15 +0,0 @@ -import {setOrtbUsp} from '../../../modules/consentManagementUsp.js'; - -describe('pbjs - ortb usp', () => { - it('sets regs.ext.us_privacy from bidderRequest', () => { - const req = {}; - setOrtbUsp(req, {uspConsent: '1NN'}); - expect(req.regs.ext.us_privacy).to.eql('1NN'); - }); - - it('does not set if missing', () => { - const req = {}; - setOrtbUsp(req, {}); - expect(req).to.eql({}); - }); -}) diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 8e3314bd954..9d8ea70e200 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -23,6 +23,8 @@ import $$PREBID_GLOBAL$$ from 'src/prebid.js'; import {resetAuctionState} from 'src/auction.js'; import {stubAuctionIndex} from '../../helpers/indexStub.js'; import {createBid} from '../../../src/bidfactory.js'; +import {enrichFPD} from '../../../src/fpd/enrichment.js'; +import {mockFpdEnrichments} from '../../helpers/fpd.js'; var assert = require('chai').assert; var expect = require('chai').expect; @@ -195,7 +197,7 @@ window.apntag = { } describe('Unit: Prebid Module', function () { - let bidExpiryStub + let bidExpiryStub, sandbox; before(() => { hook.ready(); @@ -205,12 +207,15 @@ describe('Unit: Prebid Module', function () { }); beforeEach(function () { + sandbox = sinon.sandbox.create(); + mockFpdEnrichments(sandbox); bidExpiryStub = sinon.stub(filters, 'isBidNotExpired').callsFake(() => true); configObj.setConfig({ useBidCache: true }); resetAuctionState(); }); afterEach(function() { + sandbox.restore(); $$PREBID_GLOBAL$$.adUnits = []; bidExpiryStub.restore(); configObj.setConfig({ useBidCache: false }); @@ -1749,39 +1754,62 @@ describe('Unit: Prebid Module', function () { configObj.resetConfig(); }); - it('passing global and auction-level FPD as ortb2Fragments.global', () => { - configObj.setConfig({ - ortb2: { + describe('with FPD', () => { + let globalFPD, auctionFPD, mergedFPD; + beforeEach(() => { + globalFPD = { 'k1': 'v1', 'k2': { 'k3': 'v3', 'k4': 'v4' } - } - }); - $$PREBID_GLOBAL$$.requestBids({ - ortb2: { + }; + auctionFPD = { 'k5': 'v5', 'k2': { 'k3': 'override', 'k7': 'v7' } - } - }); - sinon.assert.calledWith(startAuctionStub, sinon.match({ - ortb2Fragments: { - global: { - 'k1': 'v1', - 'k5': 'v5', - 'k2': { - 'k3': 'override', - 'k4': 'v4', - 'k7': 'v7' - } + }; + mergedFPD = { + 'k1': 'v1', + 'k5': 'v5', + 'k2': { + 'k3': 'override', + 'k4': 'v4', + 'k7': 'v7' } + }; + }); + + it('merged from setConfig and requestBids', () => { + configObj.setConfig({ortb2: globalFPD}); + $$PREBID_GLOBAL$$.requestBids({ortb2: auctionFPD}); + sinon.assert.calledWith(startAuctionStub, sinon.match({ + ortb2Fragments: {global: mergedFPD} + })); + }); + + it('enriched through enrichFPD', () => { + function enrich(next, fpd) { + next.bail(fpd.then(ortb2 => { + ortb2.enrich = true; + return ortb2; + })) } - })) + enrichFPD.before(enrich); + try { + configObj.setConfig({ortb2: globalFPD}); + $$PREBID_GLOBAL$$.requestBids({ortb2: auctionFPD}); + sinon.assert.calledWith(startAuctionStub, sinon.match({ + ortb2Fragments: {global: {...mergedFPD, enrich: true}} + })); + } finally { + enrichFPD.getHooks({hook: enrich}).remove(); + } + }) }); + it('passing bidder-specific FPD as ortb2Fragments.bidder', () => { configObj.setBidderConfig({ bidders: ['bidderA', 'bidderC'], From 747f1430f33f69ca683198ae7ca8c10473ff7ce9 Mon Sep 17 00:00:00 2001 From: Zeeshan Rasool Date: Tue, 13 Dec 2022 19:59:40 +0000 Subject: [PATCH 199/367] Permutive RTD Module: add support for new ssp standard cohorts (#9236) * add logic to parse and pass ssp data to appnexus * simplify shouldSetConfig condition * Write SSP cohorts into p_standard targeting (+ bug fixes) * fix tests * Simplify * add logic to parse and pass ssp data to appnexus * simplify shouldSetConfig condition * Write SSP cohorts into p_standard targeting (+ bug fixes) * fix tests * Simplify * use new key for auction kw cohorts * Push SSP cohorts to SSPs via ORTB2 * Add tests and fix bugs * Update tests * update example with _pssps * Remove custom `appnexusAuctionKeywords` and use user.keywords in ortb2 config * Fix linting issues Co-authored-by: Paulius Imbrasas --- .../gpt/permutiveRtdProvider_example.html | 3 +- modules/permutiveRtdProvider.js | 61 ++++++++-- .../spec/modules/permutiveRtdProvider_spec.js | 113 ++++++++++++++++-- 3 files changed, 156 insertions(+), 21 deletions(-) diff --git a/integrationExamples/gpt/permutiveRtdProvider_example.html b/integrationExamples/gpt/permutiveRtdProvider_example.html index 118cc678726..554f2081c6d 100644 --- a/integrationExamples/gpt/permutiveRtdProvider_example.html +++ b/integrationExamples/gpt/permutiveRtdProvider_example.html @@ -15,7 +15,8 @@ _papns: ['appnexus1', 'appnexus2'], _psegs: ['1234', '1000001', '1000002'], _ppam: ['ppam1', 'ppam2'], - _pcrprs: ['pcrprs1', 'pcrprs2'] + _pcrprs: ['pcrprs1', 'pcrprs2'], + _pssps: { ssps: ['appnexus', 'some other'], cohorts: ['abcd', 'efgh', 'ijkl'] }, } for (let key in data) { diff --git a/modules/permutiveRtdProvider.js b/modules/permutiveRtdProvider.js index c11d1c12436..d62834cfcfc 100644 --- a/modules/permutiveRtdProvider.js +++ b/modules/permutiveRtdProvider.js @@ -14,6 +14,7 @@ import {includes} from '../src/polyfill.js'; const MODULE_NAME = 'permutive' export const PERMUTIVE_SUBMODULE_CONFIG_KEY = 'permutive-prebid-rtd' +export const PERMUTIVE_STANDARD_AUD_KEYWORD = 'p_standard_aud' export const storage = getStorageManager({gvlid: null, moduleName: MODULE_NAME}) @@ -118,9 +119,21 @@ export function setBidderRtb (bidderOrtb2, customModuleConfig) { const transformationConfigs = deepAccess(moduleConfig, 'params.transformations') || [] const segmentData = getSegments(maxSegs) - acBidders.forEach(function (bidder) { + const ssps = segmentData?.ssp?.ssps ?? [] + const sspCohorts = segmentData?.ssp?.cohorts ?? [] + + const bidders = new Set([...acBidders, ...ssps]) + bidders.forEach(function (bidder) { const currConfig = { ortb2: bidderOrtb2[bidder] || {} } - const nextConfig = updateOrtbConfig(currConfig, segmentData.ac, transformationConfigs) // ORTB2 uses the `ac` segment IDs + + const isAcBidder = acBidders.indexOf(bidder) > -1 + const isSspBidder = ssps.indexOf(bidder) > -1 + + let cohorts = [] + if (isAcBidder) cohorts = segmentData.ac + if (isSspBidder) cohorts = [...new Set([...cohorts, ...sspCohorts])].slice(0, maxSegs) + + const nextConfig = updateOrtbConfig(currConfig, cohorts, sspCohorts, transformationConfigs) bidderOrtb2[bidder] = nextConfig.ortb2; }) } @@ -131,9 +144,10 @@ export function setBidderRtb (bidderOrtb2, customModuleConfig) { * @param {Object[]} transformationConfigs - array of objects with `id` and `config` properties, used to determine * the transformations on user data to include the ORTB2 object * @param {string[]} segmentIDs - Permutive segment IDs + * @param {string[]} sspSegmentIDs - Permutive SSP segment IDs * @return {Object} Merged ortb2 object */ -function updateOrtbConfig (currConfig, segmentIDs, transformationConfigs) { +function updateOrtbConfig (currConfig, segmentIDs, sspSegmentIDs, transformationConfigs) { const name = 'permutive.com' const permutiveUserData = { @@ -154,6 +168,12 @@ function updateOrtbConfig (currConfig, segmentIDs, transformationConfigs) { deepSetValue(ortbConfig, 'ortb2.user.data', updatedUserData) + // As of writing this, only used for AppNexus/Xandr in place of appnexusAuctionKeywords in config + const currentUserKeywords = deepAccess(ortbConfig, 'ortb2.user.keywords') || '' + const keywords = sspSegmentIDs.map(segment => `${PERMUTIVE_STANDARD_AUD_KEYWORD}=${segment}`).join(',') + const updatedUserKeywords = (currentUserKeywords === '') ? keywords : `${currentUserKeywords},${keywords}` + deepSetValue(ortbConfig, 'ortb2.user.keywords', updatedUserKeywords) + return ortbConfig } @@ -222,10 +242,19 @@ function getCustomBidderFn (moduleConfig, bidder) { * @return {Object} Bidder function */ function getDefaultBidderFn (bidder) { + const isPStandardTargetingEnabled = (data, acEnabled) => { + return (acEnabled && data.ac && data.ac.length) || (data.ssp && data.ssp.cohorts.length) + } + const pStandardTargeting = (data, acEnabled) => { + const ac = (acEnabled) ? (data.ac ?? []) : [] + const ssp = data?.ssp?.cohorts ?? [] + return [...new Set([...ac, ...ssp])] + } const bidderMap = { appnexus: function (bid, data, acEnabled) { - if (acEnabled && data.ac && data.ac.length) { - deepSetValue(bid, 'params.keywords.p_standard', data.ac) + if (isPStandardTargetingEnabled(data, acEnabled)) { + const segments = pStandardTargeting(data, acEnabled) + deepSetValue(bid, 'params.keywords.p_standard', segments) } if (data.appnexus && data.appnexus.length) { deepSetValue(bid, 'params.keywords.permutive', data.appnexus) @@ -234,19 +263,20 @@ function getDefaultBidderFn (bidder) { return bid }, rubicon: function (bid, data, acEnabled) { - if (acEnabled && data.ac && data.ac.length) { - deepSetValue(bid, 'params.visitor.p_standard', data.ac) + if (isPStandardTargetingEnabled(data, acEnabled)) { + const segments = pStandardTargeting(data, acEnabled) + deepSetValue(bid, 'params.visitor.p_standard', segments) } if (data.rubicon && data.rubicon.length) { - const rubiconCohorts = deepAccess(bid, 'params.video') ? data.rubicon.map(String) : data.rubicon - deepSetValue(bid, 'params.visitor.permutive', rubiconCohorts) + deepSetValue(bid, 'params.visitor.permutive', data.rubicon.map(String)) } return bid }, ozone: function (bid, data, acEnabled) { - if (acEnabled && data.ac && data.ac.length) { - deepSetValue(bid, 'params.customData.0.targeting.p_standard', data.ac) + if (isPStandardTargetingEnabled(data, acEnabled)) { + const segments = pStandardTargeting(data, acEnabled) + deepSetValue(bid, 'params.customData.0.targeting.p_standard', segments) } return bid @@ -290,10 +320,17 @@ export function getSegments (maxSegs) { rubicon: readSegments('_prubicons'), appnexus: readSegments('_papns'), gam: readSegments('_pdfps'), + ssp: readSegments('_pssps'), } for (const bidder in segments) { - segments[bidder] = segments[bidder].slice(0, maxSegs) + if (bidder === 'ssp') { + if (segments[bidder].cohorts && Array.isArray(segments[bidder].cohorts)) { + segments[bidder].cohorts = segments[bidder].cohorts.slice(0, maxSegs) + } + } else { + segments[bidder] = segments[bidder].slice(0, maxSegs) + } } return segments diff --git a/test/spec/modules/permutiveRtdProvider_spec.js b/test/spec/modules/permutiveRtdProvider_spec.js index 3f104ee1e2e..5030e662ea9 100644 --- a/test/spec/modules/permutiveRtdProvider_spec.js +++ b/test/spec/modules/permutiveRtdProvider_spec.js @@ -242,6 +242,42 @@ describe('permutiveRtdProvider', function () { }) }) it('should not overwrite ortb2 config', function () { + const moduleConfig = getConfig() + const acBidders = moduleConfig.params.acBidders + const sampleOrtbConfig = { + site: { + name: 'example' + }, + user: { + data: [ + { + name: 'www.dataprovider1.com', + ext: { taxonomyname: 'iab_audience_taxonomy' }, + segment: [{ id: '687' }, { id: '123' }] + } + ] + } + } + + const bidderConfig = Object.fromEntries(acBidders.map(bidder => [bidder, sampleOrtbConfig])) + + const transformedUserData = { + name: 'transformation', + ext: { test: true }, + segment: [1, 2, 3] + } + + setBidderRtb(bidderConfig, moduleConfig, { + // TODO: this argument is unused, is the test still valid / needed? + testTransformation: userData => transformedUserData + }) + + acBidders.forEach(bidder => { + expect(bidderConfig[bidder].site.name).to.equal(sampleOrtbConfig.site.name) + expect(bidderConfig[bidder].user.data).to.deep.include.members([sampleOrtbConfig.user.data[0]]) + }) + }) + it('should update user.keywords and not override existing values', function () { const moduleConfig = getConfig() const acBidders = moduleConfig.params.acBidders const sampleOrtbConfig = { @@ -275,9 +311,64 @@ describe('permutiveRtdProvider', function () { acBidders.forEach(bidder => { expect(bidderConfig[bidder].site.name).to.equal(sampleOrtbConfig.site.name) - expect(bidderConfig[bidder].user.keywords).to.equal(sampleOrtbConfig.user.keywords) expect(bidderConfig[bidder].user.data).to.deep.include.members([sampleOrtbConfig.user.data[0]]) + expect(bidderConfig[bidder].user.keywords).to.deep.equal('a,b,p_standard_aud=123,p_standard_aud=abc') + }) + }) + it('should merge ortb2 correctly for ac and ssps', function () { + setLocalStorage({ + '_ppam': [], + '_psegs': [], + '_pcrprs': ['abc', 'def', 'xyz'], + '_pssps': { + ssps: ['foo', 'bar'], + cohorts: ['xyz', 'uvw'], + } }) + const moduleConfig = { + name: 'permutive', + waitForIt: true, + params: { + acBidders: ['foo', 'other'], + maxSegs: 30 + } + } + const bidderConfig = {}; + + setBidderRtb(bidderConfig, moduleConfig) + + // include both ac and ssp cohorts, as foo is both in ac bidders and ssps + const expectedFooTargetingData = [ + { id: 'abc' }, + { id: 'def' }, + { id: 'xyz' }, + { id: 'uvw' }, + ] + expect(bidderConfig['foo'].user.data).to.deep.include.members([{ + name: 'permutive.com', + segment: expectedFooTargetingData + }]) + + // don't include ac targeting as it's not in ac bidders + const expectedBarTargetingData = [ + { id: 'xyz' }, + { id: 'uvw' }, + ] + expect(bidderConfig['bar'].user.data).to.deep.include.members([{ + name: 'permutive.com', + segment: expectedBarTargetingData + }]) + + // only include ac targeting as this ssp is not in ssps list + const expectedOtherTargetingData = [ + { id: 'abc' }, + { id: 'def' }, + { id: 'xyz' }, + ] + expect(bidderConfig['other'].user.data).to.deep.include.members([{ + name: 'permutive.com', + segment: expectedOtherTargetingData + }]) }) }) @@ -291,7 +382,11 @@ describe('permutiveRtdProvider', function () { const segments = getSegments(max) for (const key in segments) { - expect(segments[key]).to.have.length(max) + if (key === 'ssp') { + expect(segments[key].cohorts).to.have.length(max) + } else { + expect(segments[key]).to.have.length(max) + } } }) }) @@ -311,7 +406,7 @@ describe('permutiveRtdProvider', function () { if (bidder === 'appnexus') { expect(deepAccess(params, 'keywords.permutive')).to.eql(data.appnexus) - expect(deepAccess(params, 'keywords.p_standard')).to.eql(data.ac) + expect(deepAccess(params, 'keywords.p_standard')).to.eql(data.ac.concat(data.ssp.cohorts)) } }) }) @@ -332,7 +427,7 @@ describe('permutiveRtdProvider', function () { if (bidder === 'rubicon') { expect(deepAccess(params, 'visitor.permutive')).to.eql(data.rubicon) - expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac) + expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac.concat(data.ssp.cohorts)) } }) }) @@ -363,7 +458,7 @@ describe('permutiveRtdProvider', function () { deepAccess(params, 'visitor.permutive'), 'Should map all targeting values to a string', ).to.eql(data.rubicon.map(String)) - expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac) + expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac.concat(data.ssp.cohorts)) } }) }) @@ -383,7 +478,7 @@ describe('permutiveRtdProvider', function () { const { bidder, params } = bid if (bidder === 'ozone') { - expect(deepAccess(params, 'customData.0.targeting.p_standard')).to.eql(data.ac) + expect(deepAccess(params, 'customData.0.targeting.p_standard')).to.eql(data.ac.concat(data.ssp.cohorts)) } }) }) @@ -417,7 +512,7 @@ describe('permutiveRtdProvider', function () { if (bidder === 'rubicon') { expect(deepAccess(params, 'visitor.permutive')).to.eql(data.gam) - expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac) + expect(deepAccess(params, 'visitor.p_standard')).to.eql(data.ac.concat(data.ssp.cohorts)) } }) }) @@ -555,6 +650,7 @@ function transformedTargeting (data = getTargetingData()) { appnexus: data._papns, rubicon: data._prubicons, gam: data._pdfps, + ssp: data._pssps, } } @@ -565,7 +661,8 @@ function getTargetingData () { _papns: ['appnexus1', 'appnexus2'], _psegs: ['1234', '1000001', '1000002'], _ppam: ['ppam1', 'ppam2'], - _pcrprs: ['pcrprs1', 'pcrprs2'] + _pcrprs: ['pcrprs1', 'pcrprs2', 'dup'], + _pssps: { ssps: ['xyz', 'abc', 'dup'], cohorts: ['123', 'abc'] } } } From dc7e77f7c11928ff0c966badfe2a17b8ea18b880 Mon Sep 17 00:00:00 2001 From: jxdeveloper1 <71084096+jxdeveloper1@users.noreply.github.com> Date: Wed, 14 Dec 2022 05:11:42 +0800 Subject: [PATCH 200/367] Jixie Bid Adapter: Add read jxtoko cookie (#9331) * Adapter does not seem capable of supporting advertiserDomains #6650 added response comment and some trivial code. * removed a blank line at the end of file added a space behind the // in comments * in response to comment from reviewer. add the aspect of advertiserdomain in unit tests * added the code to get the keywords from the meta tags if available. * added some cookie fetching --- modules/jixieBidAdapter.js | 2 ++ test/spec/modules/jixieBidAdapter_spec.js | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/modules/jixieBidAdapter.js b/modules/jixieBidAdapter.js index f6f58883990..5eeab197f3a 100644 --- a/modules/jixieBidAdapter.js +++ b/modules/jixieBidAdapter.js @@ -56,6 +56,8 @@ function fetchIds_() { if (tmp) ret.client_id_ls = tmp; tmp = storage.getDataFromLocalStorage('_jxxs'); if (tmp) ret.session_id_ls = tmp; + tmp = storage.getCookie('_jxtoko'); + if (tmp) ret.jxtoko_id = tmp; } catch (error) {} return ret; } diff --git a/test/spec/modules/jixieBidAdapter_spec.js b/test/spec/modules/jixieBidAdapter_spec.js index 0c999f1cd51..c354de3c3ac 100644 --- a/test/spec/modules/jixieBidAdapter_spec.js +++ b/test/spec/modules/jixieBidAdapter_spec.js @@ -71,6 +71,7 @@ describe('jixie Adapter', function () { const clientIdTest1_ = '1aba6a40-f711-11e9-868c-53a2ae972xxx'; const sessionIdTest1_ = '1594782644-1aba6a40-f711-11e9-868c-53a2ae972xxx'; + const jxtokoTest1_ = 'eyJJRCI6ImFiYyJ9'; // to serve as the object that prebid will call jixie buildRequest with: (param2) const bidderRequest_ = { @@ -198,6 +199,9 @@ describe('jixie Adapter', function () { // get the interceptors ready: let getCookieStub = sinon.stub(storage, 'getCookie'); let getLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); + getCookieStub + .withArgs('_jxtoko') + .returns(jxtokoTest1_); getCookieStub .withArgs('_jxx') .returns(clientIdTest1_); @@ -227,6 +231,7 @@ describe('jixie Adapter', function () { expect(payload).to.have.property('client_id_ls', clientIdTest1_); expect(payload).to.have.property('session_id_c', sessionIdTest1_); expect(payload).to.have.property('session_id_ls', sessionIdTest1_); + expect(payload).to.have.property('jxtoko_id', jxtokoTest1_); expect(payload).to.have.property('device', device_); expect(payload).to.have.property('domain', domain_); expect(payload).to.have.property('pageurl', pageurl_); From 1b1c2a828614a45fab50e1b2c3e3373b269e0ccd Mon Sep 17 00:00:00 2001 From: Olivier Date: Wed, 14 Dec 2022 11:38:15 +0100 Subject: [PATCH 201/367] AdagioBidAdapter: add missing try-catch (#9338) --- modules/adagioBidAdapter.js | 75 ++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js index 8dcd95f933b..4f86a914982 100644 --- a/modules/adagioBidAdapter.js +++ b/modules/adagioBidAdapter.js @@ -761,46 +761,51 @@ function getSlotPosition(adUnitElementId) { position.x = Math.round(sfGeom.t); position.y = Math.round(sfGeom.l); } else if (canAccessTopWindow()) { - // window.top based computing - const wt = getWindowTop(); - const d = wt.document; + try { + // window.top based computing + const wt = getWindowTop(); + const d = wt.document; - let domElement; + let domElement; - if (inIframe() === true) { - const ws = getWindowSelf(); - const currentElement = ws.document.getElementById(adUnitElementId); - domElement = internal.getElementFromTopWindow(currentElement, ws); - } else { - domElement = wt.document.getElementById(adUnitElementId); - } + if (inIframe() === true) { + const ws = getWindowSelf(); + const currentElement = ws.document.getElementById(adUnitElementId); + domElement = internal.getElementFromTopWindow(currentElement, ws); + } else { + domElement = wt.document.getElementById(adUnitElementId); + } - if (!domElement) { - return ''; - } + if (!domElement) { + return ''; + } - let box = domElement.getBoundingClientRect(); - - const docEl = d.documentElement; - const body = d.body; - const clientTop = d.clientTop || body.clientTop || 0; - const clientLeft = d.clientLeft || body.clientLeft || 0; - const scrollTop = wt.pageYOffset || docEl.scrollTop || body.scrollTop; - const scrollLeft = wt.pageXOffset || docEl.scrollLeft || body.scrollLeft; - - const elComputedStyle = wt.getComputedStyle(domElement, null); - const elComputedDisplay = elComputedStyle.display || 'block'; - const mustDisplayElement = elComputedDisplay === 'none'; - - if (mustDisplayElement) { - domElement.style = domElement.style || {}; - const originalDisplay = domElement.style.display; - domElement.style.display = 'block'; - box = domElement.getBoundingClientRect(); - domElement.style.display = originalDisplay || null; + let box = domElement.getBoundingClientRect(); + + const docEl = d.documentElement; + const body = d.body; + const clientTop = d.clientTop || body.clientTop || 0; + const clientLeft = d.clientLeft || body.clientLeft || 0; + const scrollTop = wt.pageYOffset || docEl.scrollTop || body.scrollTop; + const scrollLeft = wt.pageXOffset || docEl.scrollLeft || body.scrollLeft; + + const elComputedStyle = wt.getComputedStyle(domElement, null); + const elComputedDisplay = elComputedStyle.display || 'block'; + const mustDisplayElement = elComputedDisplay === 'none'; + + if (mustDisplayElement) { + domElement.style = domElement.style || {}; + const originalDisplay = domElement.style.display; + domElement.style.display = 'block'; + box = domElement.getBoundingClientRect(); + domElement.style.display = originalDisplay || null; + } + position.x = Math.round(box.left + scrollLeft - clientLeft); + position.y = Math.round(box.top + scrollTop - clientTop); + } catch (err) { + logError(LOG_PREFIX, err); + return ''; } - position.x = Math.round(box.left + scrollLeft - clientLeft); - position.y = Math.round(box.top + scrollTop - clientTop); } else { return ''; } From 9abfb3d2ba3ed0160f3beaea394f438bd2fca99a Mon Sep 17 00:00:00 2001 From: Steffen Anders Date: Wed, 14 Dec 2022 13:24:11 +0100 Subject: [PATCH 202/367] AdUp Technology bid adapter: optimize floor price detection (#9332) --- modules/aduptechBidAdapter.js | 90 ++++++++----- test/spec/modules/aduptechBidAdapter_spec.js | 131 ++++++++++++++----- 2 files changed, 159 insertions(+), 62 deletions(-) diff --git a/modules/aduptechBidAdapter.js b/modules/aduptechBidAdapter.js index 5d8b69af77f..c39d9e14f17 100644 --- a/modules/aduptechBidAdapter.js +++ b/modules/aduptechBidAdapter.js @@ -1,4 +1,4 @@ -import {deepAccess, getAdUnitSizes} from '../src/utils.js'; +import {getAdUnitSizes, isArray, isBoolean, isEmpty, isFn, isPlainObject} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE} from '../src/mediaTypes.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; @@ -23,7 +23,7 @@ export const internal = { if (bidderRequest && bidderRequest.gdprConsent) { return { consentString: bidderRequest.gdprConsent.consentString, - consentRequired: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true + consentRequired: (isBoolean(bidderRequest.gdprConsent.gdprApplies)) ? bidderRequest.gdprConsent.gdprApplies : true }; } @@ -60,8 +60,26 @@ export const internal = { */ extractBannerConfig: (bidRequest) => { const sizes = getAdUnitSizes(bidRequest); - if (Array.isArray(sizes) && sizes.length > 0) { - return { sizes: sizes }; + if (isArray(sizes) && !isEmpty(sizes)) { + const banner = { sizes: sizes }; + + // try to add floor for each banner size + banner.sizes.forEach(size => { + const floor = internal.getFloor(bidRequest, { mediaType: BANNER, size }); + if (floor) { + size.push(floor.floor); + size.push(floor.currency); + } + }); + + // try to add default floor for banner + const floor = internal.getFloor(bidRequest, { mediaType: BANNER, size: '*' }); + if (floor) { + banner.floorPrice = floor.floor; + banner.floorCurrency = floor.currency; + } + + return banner; } return null; @@ -74,8 +92,17 @@ export const internal = { * @returns {null|Object.} */ extractNativeConfig: (bidRequest) => { - if (bidRequest && deepAccess(bidRequest, 'mediaTypes.native')) { - return bidRequest.mediaTypes.native; + if (bidRequest?.mediaTypes?.native) { + const native = bidRequest.mediaTypes.native; + + // try to add default floor for native + const floor = internal.getFloor(bidRequest, { mediaType: NATIVE, size: '*' }); + if (floor) { + native.floorPrice = floor.floor; + native.floorCurrency = floor.currency; + } + + return native; } return null; @@ -96,27 +123,25 @@ export const internal = { }, /** - * Extracts the floor price params from given bidRequest + * Try to get floor information via bidRequest.getFloor() * * @param {BidRequest} bidRequest - * @returns {undefined|float} + * @param {Object} options + * @returns {null|Object.} */ - extractFloorPrice: (bidRequest) => { - let floorPrice; - if (bidRequest && bidRequest.params && bidRequest.params.floor) { - // if there is a manual floorPrice set - floorPrice = !isNaN(parseInt(bidRequest.params.floor)) ? bidRequest.params.floor : undefined; - } - if (typeof bidRequest.getFloor === 'function') { - // use prebid floor module - let floorInfo; - try { - floorInfo = bidRequest.getFloor(); - } catch (e) {} - floorPrice = typeof floorInfo === 'object' && !isNaN(parseInt(floorInfo.floor)) ? floorInfo.floor : floorPrice; + getFloor: (bidRequest, options) => { + if (!isFn(bidRequest?.getFloor)) { + return null; } - return floorPrice; + try { + const floor = bidRequest.getFloor(options); + if (isPlainObject(floor) && !isNaN(floor.floor)) { + return floor; + } + } catch {} + + return null; }, /** @@ -128,11 +153,11 @@ export const internal = { groupBidRequestsByPublisher: (bidRequests) => { const groupedBidRequests = {}; - if (!bidRequests || bidRequests.length === 0) { + if (!bidRequests || isEmpty(bidRequests)) { return groupedBidRequests; } - bidRequests.forEach((bidRequest) => { + bidRequests.forEach(bidRequest => { const publisher = internal.extractParams(bidRequest).publisher; if (!publisher) { return; @@ -205,7 +230,7 @@ export const spec = { const requests = []; // stop here on invalid or empty data - if (!bidderRequest || !validBidRequests || validBidRequests.length === 0) { + if (!bidderRequest || !validBidRequests || isEmpty(validBidRequests)) { return requests; } @@ -237,7 +262,7 @@ export const spec = { } // handle multiple bids per request - groupedBidRequests[publisher].forEach((bidRequest) => { + groupedBidRequests[publisher].forEach(bidRequest => { const bid = { bidId: bidRequest.bidId, transactionId: bidRequest.transactionId, @@ -257,10 +282,11 @@ export const spec = { bid.native = nativeConfig; } - // add floor price - const floorPrice = internal.extractFloorPrice(bidRequest); - if (floorPrice) { - bid.floorPrice = floorPrice; + // try to add default floor + const floor = internal.getFloor(bidRequest, { mediaType: '*', size: '*' }); + if (floor) { + bid.floorPrice = floor.floor; + bid.floorCurrency = floor.currency; } request.data.imp.push(bid); @@ -282,12 +308,12 @@ export const spec = { const bidResponses = []; // stop here on invalid or empty data - if (!response || !deepAccess(response, 'body.bids') || response.body.bids.length === 0) { + if (!response?.body?.bids || isEmpty(response.body.bids)) { return bidResponses; } // parse multiple bids per response - response.body.bids.forEach((bid) => { + response.body.bids.forEach(bid => { if (!bid || !bid.bid || !bid.creative) { return; } diff --git a/test/spec/modules/aduptechBidAdapter_spec.js b/test/spec/modules/aduptechBidAdapter_spec.js index bbc4e554f7e..8dbdbbfeab5 100644 --- a/test/spec/modules/aduptechBidAdapter_spec.js +++ b/test/spec/modules/aduptechBidAdapter_spec.js @@ -182,6 +182,54 @@ describe('AduptechBidAdapter', () => { }); }); + describe('getFloor', () => { + let bidRequest; + + beforeEach(() => { + bidRequest = { + getFloor: sinon.stub() + }; + }); + + it('should handle empty or invalid bidRequest', () => { + expect(internal.getFloor(null)).to.be.null; + expect(internal.getFloor({})).to.be.null; + expect(internal.getFloor({ getFloor: 'foo' })).to.be.null; + }); + + it('should detect floor via getFloor()', () => { + const result = { + floor: 1.11, + currency: 'USD' + }; + + const options = { + mediaType: BANNER, + size: '*' + } + + bidRequest.getFloor.returns(result); + + expect(internal.getFloor(bidRequest, options)).to.deep.equal(result); + expect(bidRequest.getFloor.calledOnceWith(options)).to.be.true; + }); + + it('should handle empty, invalid or faulty getFloor() results', () => { + bidRequest.getFloor + .onCall(0).returns({}) + .onCall(1).returns({ floor: 'foo' }) + .onCall(2).returns('bar') + .onCall(3).throws(new Error('baz')); + + expect(internal.getFloor(bidRequest, {})).to.be.null; + expect(internal.getFloor(bidRequest, {})).to.be.null; + expect(internal.getFloor(bidRequest, {})).to.be.null; + expect(internal.getFloor(bidRequest, {})).to.be.null; + + expect(bidRequest.getFloor.callCount).to.equal(4); + }); + }); + describe('groupBidRequestsByPublisher', () => { it('should handle empty bidRequests', () => { expect(internal.groupBidRequestsByPublisher(null)).to.deep.equal({}); @@ -541,34 +589,35 @@ describe('AduptechBidAdapter', () => { } }; - const getFloorResponse = { - currency: 'USD', - floor: '1.23' - }; - - const validBidRequests = [ - { - bidId: 'bidId1', - adUnitCode: 'adUnitCode1', - transactionId: 'transactionId1', - mediaTypes: { - banner: { - sizes: [[100, 200], [300, 400]] - } - }, - params: { - publisher: 'publisher1', - placement: 'placement1' + const bidRequest = { + bidId: 'bidId1', + adUnitCode: 'adUnitCode1', + transactionId: 'transactionId1', + mediaTypes: { + banner: { + sizes: [[100, 200], [300, 400]] }, - getFloor: () => { - return getFloorResponse + native: { + image: { + required: true + }, } - } - ]; + }, + params: { + publisher: 'publisher1', + placement: 'placement1' + }, + getFloor: sinon.stub() + .onCall(0).returns({ floor: 1.11, currency: 'USD' }) + .onCall(1).returns({ floor: 2.22, currency: 'EUR' }) + .onCall(2).returns({ floor: 3.33, currency: 'USD' }) + .onCall(3).returns({ floor: 4.44, currency: 'GBP' }) + .onCall(4).returns({ floor: 5.55, currency: 'EUR' }) + }; - expect(spec.buildRequests(validBidRequests, bidderRequest)).to.deep.equal([ + expect(spec.buildRequests([bidRequest], bidderRequest)).to.deep.equal([ { - url: internal.buildEndpointUrl(validBidRequests[0].params.publisher), + url: internal.buildEndpointUrl(bidRequest.params.publisher), method: ENDPOINT_METHOD, data: { auctionId: bidderRequest.auctionId, @@ -580,17 +629,39 @@ describe('AduptechBidAdapter', () => { }, imp: [ { - bidId: validBidRequests[0].bidId, - transactionId: validBidRequests[0].transactionId, - adUnitCode: validBidRequests[0].adUnitCode, - params: validBidRequests[0].params, - banner: validBidRequests[0].mediaTypes.banner, - floorPrice: getFloorResponse.floor + bidId: bidRequest.bidId, + transactionId: bidRequest.transactionId, + adUnitCode: bidRequest.adUnitCode, + params: bidRequest.params, + banner: { + sizes: [ + [100, 200, 1.11, 'USD'], + [300, 400, 2.22, 'EUR'], + ], + floorPrice: 3.33, + floorCurrency: 'USD' + }, + native: { + image: { + required: true + }, + floorPrice: 4.44, + floorCurrency: 'GBP' + }, + floorPrice: 5.55, + floorCurrency: 'EUR' } ] } } ]); + + expect(bidRequest.getFloor.callCount).to.equal(5); + expect(bidRequest.getFloor.getCall(0).calledWith({ mediaType: BANNER, size: bidRequest.mediaTypes.banner.sizes[0] })).to.be.true; + expect(bidRequest.getFloor.getCall(1).calledWith({ mediaType: BANNER, size: bidRequest.mediaTypes.banner.sizes[1] })).to.be.true; + expect(bidRequest.getFloor.getCall(2).calledWith({ mediaType: BANNER, size: '*' })).to.be.true; + expect(bidRequest.getFloor.getCall(3).calledWith({ mediaType: NATIVE, size: '*' })).to.be.true; + expect(bidRequest.getFloor.getCall(4).calledWith({ mediaType: '*', size: '*' })).to.be.true; }); }); From 9f11a94397a6b90550dd2dd9456e66a70d773644 Mon Sep 17 00:00:00 2001 From: Mikhail Ivanchenko Date: Wed, 14 Dec 2022 16:13:00 +0300 Subject: [PATCH 203/367] nextMillenniumBidAdapter: improve getUserSyncs function (#9313) * add video support * improve userSync url * improve userSync url * Add tests for a new cases * use deepAccess instead of instanceof --- modules/nextMillenniumBidAdapter.js | 45 +++++++--- .../modules/nextMillenniumBidAdapter_spec.js | 83 +++++++++++-------- 2 files changed, 79 insertions(+), 49 deletions(-) diff --git a/modules/nextMillenniumBidAdapter.js b/modules/nextMillenniumBidAdapter.js index cf732d343e5..b5d0e15d078 100644 --- a/modules/nextMillenniumBidAdapter.js +++ b/modules/nextMillenniumBidAdapter.js @@ -1,4 +1,5 @@ import { + isArray, _each, createTrackPixelHtml, deepAccess, @@ -24,7 +25,6 @@ const BIDDER_CODE = 'nextMillennium'; const ENDPOINT = 'https://pbs.nextmillmedia.com/openrtb2/auction'; const TEST_ENDPOINT = 'https://test.pbs.nextmillmedia.com/openrtb2/auction'; const REPORT_ENDPOINT = 'https://report2.hb.brainlyads.com/statistics/metric'; -const SYNC_ENDPOINT = 'https://cookies.nextmillmedia.com/sync?'; const TIME_TO_LIVE = 360; const VIDEO_PARAMS = [ 'api', 'linearity', 'maxduration', 'mimes', 'minduration', 'placement', @@ -208,20 +208,27 @@ export const spec = { getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { const pixels = []; - let syncUrl = SYNC_ENDPOINT; - if (gdprConsent && gdprConsent.gdprApplies) { - syncUrl += 'gdpr=1&gdpr_consent=' + gdprConsent.consentString; - } - if (uspConsent) { - syncUrl += 'us_privacy=' + uspConsent; - } + if (isArray(responses)) { + responses.forEach(response => { + if (syncOptions.pixelEnabled) { + deepAccess(response, 'body.ext.sync.image', []).forEach(imgUrl => { + pixels.push({ + type: 'image', + url: replaceUsersyncMacros(imgUrl, gdprConsent, uspConsent) + }); + }) + } - if (syncOptions.iframeEnabled) { - pixels.push({type: 'iframe', url: syncUrl + 'type=iframe'}); - } - if (syncOptions.pixelEnabled) { - pixels.push({type: 'image', url: syncUrl + 'type=image'}); + if (syncOptions.iframeEnabled) { + deepAccess(response, 'body.ext.sync.iframe', []).forEach(iframeUrl => { + pixels.push({ + type: 'iframe', + url: replaceUsersyncMacros(iframeUrl, gdprConsent, uspConsent) + }); + }) + } + }) } return pixels; @@ -263,6 +270,18 @@ export const spec = { }, }; +function replaceUsersyncMacros(url, gdprConsent, uspConsent) { + const { consentString, gdprApplies } = gdprConsent; + + return url.replace( + '{{.GDPR}}', Number(gdprApplies) + ).replace( + '{{.GDPRConsent}}', consentString + ).replace( + '{{.USPrivacy}}', uspConsent + ); +}; + function getAdEl(bid) { // best way I could think of to get El, is by matching adUnitCode to google slots... const slot = window.googletag && window.googletag.pubads && window.googletag.pubads().getSlots().find(slot => slot.getAdUnitPath() === bid.adUnitCode); diff --git a/test/spec/modules/nextMillenniumBidAdapter_spec.js b/test/spec/modules/nextMillenniumBidAdapter_spec.js index 3094c1349f7..90f0d8ae15c 100644 --- a/test/spec/modules/nextMillenniumBidAdapter_spec.js +++ b/test/spec/modules/nextMillenniumBidAdapter_spec.js @@ -28,6 +28,34 @@ describe('nextMillenniumBidAdapterTests', function() { } ]; + const serverResponse = { + body: { + id: 'f7b3d2da-e762-410c-b069-424f92c4c4b2', + seatbid: [ + { + bid: [ + { + id: '7457329903666272789', + price: 0.5, + adm: 'Hello! It\'s a test ad!', + adid: '96846035', + adomain: ['test.addomain.com'], + w: 300, + h: 250 + } + ] + } + ], + cur: 'USD', + ext: { + sync: { + image: ['urlA'], + iframe: ['urlB'], + } + } + } + }; + const bidRequestDataGI = [ { adUnitCode: 'test-banner-gi', @@ -96,6 +124,24 @@ describe('nextMillenniumBidAdapterTests', function() { expect(JSON.parse(request[0].data).regs.ext.gdpr).to.equal(1); }); + it('Test getUserSyncs function', function () { + const syncOptions = { + 'iframeEnabled': false, + 'pixelEnabled': true + } + let userSync = spec.getUserSyncs(syncOptions, [serverResponse], bidRequestData[0].gdprConsent, bidRequestData[0].uspConsent); + expect(userSync).to.be.an('array').with.lengthOf(1); + expect(userSync[0].type).to.equal('image'); + expect(userSync[0].url).to.equal('urlA'); + + syncOptions.iframeEnabled = true; + syncOptions.pixelEnabled = false; + userSync = spec.getUserSyncs(syncOptions, [serverResponse], bidRequestData[0].gdprConsent, bidRequestData[0].uspConsent); + expect(userSync).to.be.an('array').with.lengthOf(1); + expect(userSync[0].type).to.equal('iframe'); + expect(userSync[0].url).to.equal('urlB'); + }); + it('Request params check without GDPR Consent', function () { delete bidRequestData[0].gdprConsent const request = spec.buildRequests(bidRequestData, bidRequestData[0]); @@ -137,51 +183,16 @@ describe('nextMillenniumBidAdapterTests', function() { it('Check if imp object was added', function() { const request = spec.buildRequests(bidRequestData) expect(JSON.parse(request[0].data).imp).to.be.an('array') - }) + }); it('Check if imp prebid stored id is correct', function() { const request = spec.buildRequests(bidRequestData) const requestData = JSON.parse(request[0].data); const storedReqId = requestData.ext.prebid.storedrequest.id; expect(requestData.imp[0].ext.prebid.storedrequest.id).to.equal(storedReqId) - }) - - it('Test getUserSyncs function', function () { - const syncOptions = { - 'iframeEnabled': false, - 'pixelEnabled': true - } - const userSync = spec.getUserSyncs(syncOptions); - 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://cookies.nextmillmedia.com/sync?type=image'); }); it('validate_response_params', function() { - const serverResponse = { - body: { - id: 'f7b3d2da-e762-410c-b069-424f92c4c4b2', - seatbid: [ - { - bid: [ - { - id: '7457329903666272789', - price: 0.5, - adm: 'Hello! It\'s a test ad!', - adid: '96846035', - adomain: ['test.addomain.com'], - w: 300, - h: 250 - } - ] - } - ], - cur: 'USD' - } - }; - let bids = spec.interpretResponse(serverResponse, bidRequestData[0]); expect(bids).to.have.lengthOf(1); From 14bdd9d36957bf59e87b965cc871deae2ac24929 Mon Sep 17 00:00:00 2001 From: Lionell Pack Date: Thu, 15 Dec 2022 08:58:31 +1100 Subject: [PATCH 204/367] Uid2 module: major implementation change (#9264) * Complete the UID2 integration. Update docs. Add tests. * Removed some unnecessary code in uid2IdSystem.uid2IdSystem. Improved log messages. Pass through configured baseUrl. Tidied up some in-progress code problems. Added a timer mock to track and clear timers at the end of each test, to prevent interference. Improved testing code and fixed some bugs. * Move cookie cleanup into the after so it doesn't leave a mess behind for subsequent tests. Allow specifying multiple --file options when running/watching tests. * Provide an additional mock object for some test environments which don't provide crypto.subtle. * Improve some documentation for the UID2 module. * Improved UID2 module logging when debug flag is enabled. * Added tests around the api base url config for UID2. Added the new UID2 config to the example. * Update integration example to attempt a token refresh (it will fail due to not being a valid token). * Refactor to avoid duplicating cookie read code. Add a test for the case when the id value is provided directly in config without making use of the new token refresh system. * Fix an incorrect log call. Co-authored-by: Lionell Pack --- integrationExamples/gpt/userId_example.html | 12 +- karma.conf.maker.js | 2 +- modules/uid2IdSystem.js | 248 ++++++++++++++-- modules/uid2IdSystem.md | 34 ++- test/mocks/timers.js | 84 ++++++ test/spec/modules/uid2IdSystem_spec.js | 310 ++++++++++++++++++++ 6 files changed, 655 insertions(+), 35 deletions(-) create mode 100644 test/mocks/timers.js create mode 100644 test/spec/modules/uid2IdSystem_spec.js diff --git a/integrationExamples/gpt/userId_example.html b/integrationExamples/gpt/userId_example.html index 5a6c80c4adf..4f94c73c281 100644 --- a/integrationExamples/gpt/userId_example.html +++ b/integrationExamples/gpt/userId_example.html @@ -249,7 +249,17 @@ } }, { - "name": "uid2" + "name": "uid2", + "params": { + "uid2Token": { + "advertising_token": "example token", + "refresh_token": "aslkdjaslkjdaslkhj", + "identity_expires": Date.now() + 60*1000, + "refresh_from": Date.now() - 10*1000, + "refresh_expires": Date.now() + 12*60*60*1000, + "refresh_response_key": null + } + } } , { diff --git a/karma.conf.maker.js b/karma.conf.maker.js index b20f73d74bc..692db7755e8 100644 --- a/karma.conf.maker.js +++ b/karma.conf.maker.js @@ -110,7 +110,7 @@ module.exports = function(codeCoverage, browserstack, watchMode, file, disableFe var webpackConfig = newWebpackConfig(codeCoverage, disableFeatures); var plugins = newPluginsArray(browserstack); - var files = file ? ['test/test_deps.js', file] : ['test/test_index.js']; + var files = file ? ['test/test_deps.js', file].flatMap(f => f) : ['test/test_index.js']; // This file opens the /debug.html tab automatically. // It has no real value unless you're running --watch, and intend to do some debugging in the browser. if (watchMode) { diff --git a/modules/uid2IdSystem.js b/modules/uid2IdSystem.js index 23656639532..9fd75f12591 100644 --- a/modules/uid2IdSystem.js +++ b/modules/uid2IdSystem.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ /** * This module adds uid2 ID support to the User ID module * The {@link module:modules/userId} module is required. @@ -10,48 +11,142 @@ import {submodule} from '../src/hook.js'; import { getStorageManager } from '../src/storageManager.js'; const MODULE_NAME = 'uid2'; +const MODULE_REVISION = `1.0`; +const PREBID_VERSION = '$prebid.version$'; +const UID2_CLIENT_ID = `PrebidJS-${PREBID_VERSION}-UID2Module-${MODULE_REVISION}`; const GVLID = 887; const LOG_PRE_FIX = 'UID2: '; const ADVERTISING_COOKIE = '__uid2_advertising_token'; -function readCookie() { - return storage.cookiesAreEnabled() ? storage.getCookie(ADVERTISING_COOKIE) : null; +// eslint-disable-next-line no-unused-vars +const UID2_TEST_URL = 'https://operator-integ.uidapi.com'; +const UID2_PROD_URL = 'https://prod.uidapi.com'; +const UID2_BASE_URL = UID2_PROD_URL; + +function getStorage() { + return getStorageManager({gvlid: GVLID, moduleName: MODULE_NAME}); +} + +function createLogInfo(prefix) { + return function (...strings) { + logInfo(prefix + ' ', ...strings); + } } +export const storage = getStorage(); +const _logInfo = createLogInfo(LOG_PRE_FIX); function readFromLocalStorage() { return storage.localStorageIsEnabled() ? storage.getDataFromLocalStorage(ADVERTISING_COOKIE) : null; } -function getStorage() { - return getStorageManager({gvlid: GVLID, moduleName: MODULE_NAME}); +function readModuleCookie() { + const cookie = readCookie(ADVERTISING_COOKIE); + if (cookie && cookie.includes('{')) { + return JSON.parse(cookie); + } + return cookie; } -const storage = getStorage(); +function readJsonCookie(cookieName) { + return JSON.parse(readCookie(cookieName)); +} -const _logInfo = createLogInfo(LOG_PRE_FIX); +function readCookie(cookieName) { + const cookie = storage.cookiesAreEnabled() ? storage.getCookie(cookieName) : null; + if (!cookie) { + _logInfo(`Attempted to read UID2 from cookie '${cookieName}' but it was empty`); + return null; + }; + _logInfo(`Read UID2 from cookie '${cookieName}'`); + return cookie; +} -function createLogInfo(prefix) { - return function (...strings) { - logInfo(prefix + ' ', ...strings); +function storeValue(value) { + if (storage.cookiesAreEnabled()) { + storage.setCookie(ADVERTISING_COOKIE, JSON.stringify(value), Date.now() + 60 * 60 * 24 * 1000); + } else if (storage.localStorageIsEnabled()) { + storage.setLocalStorage(ADVERTISING_COOKIE, value); } } -/** - * Encode the id - * @param value - * @returns {string|*} - */ -function encodeId(value) { - const result = {}; - if (value) { - const bidIds = { - id: value +function isValidIdentity(identity) { + return !!(typeof identity === 'object' && identity !== null && identity.advertising_token && identity.identity_expires && identity.refresh_from && identity.refresh_token && identity.refresh_expires); +} + +// This is extracted from an in-progress API client. Once it's available via NPM, this class should be replaced with the NPM package. +class Uid2ApiClient { + constructor(opts) { + this._baseUrl = opts.baseUrl ? opts.baseUrl : UID2_BASE_URL; + this._clientVersion = UID2_CLIENT_ID; + } + createArrayBuffer(text) { + const arrayBuffer = new Uint8Array(text.length); + for (let i = 0; i < text.length; i++) { + arrayBuffer[i] = text.charCodeAt(i); } - result.uid2 = bidIds; - _logInfo('Decoded value ' + JSON.stringify(result)); - return result; + return arrayBuffer; + } + hasStatusResponse(response) { + return typeof (response) === 'object' && response && response.status; + } + isValidRefreshResponse(response) { + return this.hasStatusResponse(response) && ( + response.status === 'optout' || response.status === 'expired_token' || (response.status === 'success' && response.body && isValidIdentity(response.body)) + ); + } + ResponseToRefreshResult(response) { + if (this.isValidRefreshResponse(response)) { + if (response.status === 'success') { return { status: response.status, identity: response.body }; } + return response; + } else { return "Response didn't contain a valid status"; } + } + callRefreshApi(refreshDetails) { + const url = this._baseUrl + '/v2/token/refresh'; + const req = new XMLHttpRequest(); + req.overrideMimeType('text/plain'); + req.open('POST', url, true); + req.setRequestHeader('X-UID2-Client-Version', this._clientVersion); + let resolvePromise; + let rejectPromise; + const promise = new Promise((resolve, reject) => { + resolvePromise = resolve; + rejectPromise = reject; + }); + req.onreadystatechange = () => { + if (req.readyState !== req.DONE) { return; } + try { + if (!refreshDetails.refresh_response_key || req.status !== 200) { + _logInfo('Error status OR no response decryption key available, assuming unencrypted JSON'); + const response = JSON.parse(req.responseText); + const result = this.ResponseToRefreshResult(response); + if (typeof result === 'string') { rejectPromise(result); } else { resolvePromise(result); } + } else { + _logInfo('Decrypting refresh API response'); + const encodeResp = this.createArrayBuffer(atob(req.responseText)); + window.crypto.subtle.importKey('raw', this.createArrayBuffer(atob(refreshDetails.refresh_response_key)), { name: 'AES-GCM' }, false, ['decrypt']).then((key) => { + _logInfo('Imported decryption key') + // returns the symmetric key + window.crypto.subtle.decrypt({ + name: 'AES-GCM', + iv: encodeResp.slice(0, 12), + tagLength: 128, // The tagLength you used to encrypt (if any) + }, key, encodeResp.slice(12)).then((decrypted) => { + const decryptedResponse = String.fromCharCode(...new Uint8Array(decrypted)); + _logInfo('Decrypted to:', decryptedResponse); + const response = JSON.parse(decryptedResponse); + const result = this.ResponseToRefreshResult(response); + if (typeof result === 'string') { rejectPromise(result); } else { resolvePromise(result); } + }, (reason) => console.warn(`Call to UID2 API failed`, reason)); + }, (reason) => console.warn(`Call to UID2 API failed`, reason)); + } + } catch (err) { + rejectPromise(err); + } + }; + _logInfo('Sending refresh request', req); + req.send(refreshDetails.refresh_token); + return promise; } - return undefined; } /** @type {Submodule} */ @@ -71,27 +166,118 @@ export const uid2IdSubmodule = { * decode the stored id value for passing to bid requests * @function * @param {string} value - * @returns {{uid2:{ id: string }} or undefined if value doesn't exists + * @returns {{uid2:{ id: string } }} or undefined if value doesn't exists */ decode(value) { - return (value) ? encodeId(value) : undefined; + const result = decodeImpl(value); + _logInfo('UID2 decode returned', result); + return result; }, /** * performs action to obtain id and return a value. * @function - * @param {SubmoduleConfig} [config] + * @param {SubmoduleConfig} [configparams] * @param {ConsentData|undefined} consentData * @returns {uid2Id} */ getId(config, consentData) { - _logInfo('Creating UID 2.0'); - let value = readCookie() || readFromLocalStorage(); - _logInfo('The advertising token: ' + value); - return {id: value} + const result = getIdImpl(config, consentData); + _logInfo(`UID2 getId returned`, result); + return result; }, - }; +function refreshTokenAndStore(baseUrl, token) { + _logInfo('UID2 base url provided: ', baseUrl); + const client = new Uid2ApiClient({baseUrl}); + return client.callRefreshApi(token).then((response) => { + _logInfo('Refresh endpoint responded with:', response); + const tokens = { + originalToken: token, + latestToken: response.identity, + }; + storeValue(tokens); + return tokens; + }); +} + +function decodeImpl(value) { + if (typeof value === 'string') { + _logInfo('Found an old-style ID from an earlier version of the module. Refresh is unavailable for this token.'); + const result = { uid2: { id: value } }; + return result; + } + if (Date.now() < value.latestToken.identity_expires) { + return { uid2: { id: value.latestToken.advertising_token } }; + } + return null; +} + +function getIdImpl(config, consentData) { + let suppliedToken = null; + const uid2BaseUrl = config?.params?.uid2ApiBase ?? UID2_BASE_URL; + if (config && config.params) { + if (config.params.uid2Token) { + suppliedToken = config.params.uid2Token; + _logInfo('Read token from params', suppliedToken); + } else if (config.params.uid2ServerCookie) { + suppliedToken = readJsonCookie(config.params.uid2ServerCookie); + _logInfo('Read token from server-supplied cookie', suppliedToken); + } + } + let storedTokens = readModuleCookie() || readFromLocalStorage(); + _logInfo('Loaded module-stored tokens:', storedTokens); + + if (storedTokens && typeof storedTokens === 'string') { + // Legacy value stored, this must be from an old integration. If no token supplied, just use the legacy value. + + if (!suppliedToken) { + _logInfo('Returning legacy cookie value.'); + return { id: storedTokens }; + } + // Otherwise, ignore the legacy value - it should get over-written later anyway. + _logInfo('Discarding superseded legacy cookie.'); + storedTokens = null; + } + + if (suppliedToken && storedTokens) { + if (storedTokens.originalToken?.advertising_token !== suppliedToken.advertising_token) { + _logInfo('Server supplied new token - ignoring stored value.', storedTokens.originalToken?.advertising_token, suppliedToken.advertising_token); + // Stored token wasn't originally sourced from the provided token - ignore the stored value. A new user has logged in? + storedTokens = null; + } + } + // At this point, any legacy values or superseded stored tokens have been nulled out. + const useSuppliedToken = !(storedTokens?.latestToken) || (suppliedToken && suppliedToken.identity_expires > storedTokens.latestToken.identity_expires); + const newestAvailableToken = useSuppliedToken ? suppliedToken : storedTokens.latestToken; + _logInfo('UID2 module selected latest token', useSuppliedToken, newestAvailableToken); + if (!newestAvailableToken || Date.now() > newestAvailableToken.refresh_expires) { + _logInfo('Newest available token is expired and not refreshable.'); + return { id: null }; + } + if (Date.now() > newestAvailableToken.identity_expires) { + const promise = refreshTokenAndStore(uid2BaseUrl, newestAvailableToken); + _logInfo('Token is expired but can be refreshed, attempting refresh.'); + return { callback: (cb) => { + promise.then((result) => { + _logInfo('Refresh reponded, passing the updated token on.', result); + cb(result); + }); + } }; + } + // If should refresh (but don't need to), refresh in the background. + if (Date.now() > newestAvailableToken.refresh_from) { + _logInfo(`Refreshing token in background with low priority.`); + refreshTokenAndStore(uid2BaseUrl, newestAvailableToken); + } + const tokens = { + originalToken: suppliedToken ?? storedTokens?.originalToken, + latestToken: newestAvailableToken, + }; + storeValue(tokens); + return { id: tokens }; +} + // Register submodule for userId submodule('userId', uid2IdSubmodule); diff --git a/modules/uid2IdSystem.md b/modules/uid2IdSystem.md index fa596b17584..82ff1b3cb68 100644 --- a/modules/uid2IdSystem.md +++ b/modules/uid2IdSystem.md @@ -6,11 +6,23 @@ UID 2.0 ID Module. Individual params may be set for the UID 2.0 Submodule. At least one identifier must be set in the params. +The module will handle refreshing the token periodically and storing the updated token using the Prebid.js storage manager. If you provide an expired identity and the module has a valid identity which was refreshed from the identity you provide, it will use the refreshed identity. The module stores the original token used for refreshing the token, and it will use the refreshed tokens as long as the original token matches the one supplied. + ``` pbjs.setConfig({ userSync: { userIds: [{ - name: 'uid2' + name: 'uid2', + params: { + // Either: + uid2ServerCookie: 'your_UID2_server_set_cookie_name' + // Or: + uid2Token: { + 'advertising_token': '...', + 'refresh_token': '...', + // etc. - see the Sample Token below for contents of this object + } + } }] } }); @@ -18,7 +30,25 @@ pbjs.setConfig({ ## Parameter Descriptions for the `usersync` Configuration Section The below parameters apply only to the UID 2.0 User ID Module integration. +You should supply either `uid2Token` or `uid2ServerCookie`. + +If you provide `uid2Token`, the value should be a JavaScript/JSON object with the decrypted `body` payload response from a call to either `/token/generate` or `/token/refresh`. + +If you provide `uid2ServerCookie`, the module will expect that same JSON object to be stored in the cookie - i.e. it will pass the cookie value to `JSON.parse` and expect to receive an object containing similar to what you see in the `Sample token` section below. + +The module will make calls to the `/token/refresh` endpoint to update the token it stores internally, so bids may contain an updated token. + +If neither of `uid2Token` or `uid2ServerCookie` are supplied, and the module has stored a token using the Prebid.js storage system (typically in a cookie named `__uid2_advertising_token`), it will use that token. This cookie is internal to the module and should not be set directly. + +If a new token is supplied which does not match the original token used to generate any refreshed tokens, all stored tokens will be discarded and the new token used instead (refreshed if necessary). + +### Sample token + +`{`
  `"advertising_token": "...",`
  `"refresh_token": "...",`
  `"identity_expires": 1633643601000,`
  `"refresh_from": 1633643001000,`
  `"refresh_expires": 1636322000000,`
  `"refresh_response_key": "wR5t6HKMfJ2r4J7fEGX9Gw=="`
`}` + | Param under userSync.userIds[] | Scope | Type | Description | Example | | --- | --- | --- | --- | --- | | name | Required | String | ID value for the UID20 module - `"uid2"` | `"uid2"` | -| value | Optional | Object | Used only if the page has a separate mechanism for storing the UID 2.0 ID. The value is an object containing the values to be sent to the adapters. In this scenario, no URL is called and nothing is added to local storage | `{"uid2": { "id": "eb33b0cb-8d35-4722-b9c0-1a31d4064888"}}` | +| params.uid2Token | Optional | Object | The initial UID2 token. This should be `body` element of the decrypted response from a call to the `/token/generate` or `/token/refresh` endpoint. | See the sample token above. | +| params.uid2ServerCookie | Optional | String | The name of a cookie which holds the initial UID2 token, set by the server. The cookie should contain JSON in the same format as the alternative uid2Token param. **If uid2Token is supplied, this param is ignored.** | See the sample token above. | +| params.uid2ApiBase | Optional | String | Overrides the default UID2 API endpoint. | `https://prod.uidapi.com` _(default)_ | diff --git a/test/mocks/timers.js b/test/mocks/timers.js new file mode 100644 index 00000000000..6efd798c881 --- /dev/null +++ b/test/mocks/timers.js @@ -0,0 +1,84 @@ +/* + * Provides wrappers for timers to allow easy cancelling and/or awaiting of outstanding timers. + * This helps avoid functionality leaking from one test to the next. + */ + +let wrappersActive = false; + +export function configureTimerInterceptors(debugLog = function() {}, generateStackTraces = false) { + if (wrappersActive) throw new Error(`Timer wrappers are already in place.`); + wrappersActive = true; + let theseWrappersActive = true; + + let originalSetTimeout = setTimeout, originalSetInterval = setInterval, originalClearTimeout = clearTimeout, originalClearInterval = clearInterval; + + let timerId = -1; + let timers = []; + + const waitOnTimersResolves = []; + function checkWaits() { + if (timers.length === 0) waitOnTimersResolves.forEach((r) => r()); + } + const waitAllActiveTimers = () => timers.length === 0 ? Promise.resolve() : new Promise((resolve) => waitOnTimersResolves.push(resolve)); + const clearAllActiveTimers = () => timers.forEach((timer) => timer.type === 'timeout' ? clearTimeout(timer.handle) : clearInterval(timer.handle)); + + const generateInterceptor = (type, originalFunctionWrapper) => (fn, delay, ...args) => { + timerId++; + debugLog(`Setting wrapped timeout ${timerId} for ${delay ?? 0}`); + const info = { timerId, type }; + if (generateStackTraces) { + try { + throw new Error(); + } catch (ex) { + info.stack = ex.stack; + } + } + info.handle = originalFunctionWrapper(info, fn, delay, ...args); + timers.push(info); + return info.handle; + }; + const setTimeoutInterceptor = generateInterceptor('timeout', (info, fn, delay, ...args) => originalSetTimeout(() => { + try { + debugLog(`Running timeout ${info.timerId}`); + fn(...args); + } finally { + const infoIndex = timers.indexOf(info); + if (infoIndex > -1) timers.splice(infoIndex, 1); + checkWaits(); + } + }, delay)); + + const setIntervalInterceptor = generateInterceptor('interval', (info, fn, interval, ...args) => originalSetInterval(() => { + debugLog(`Running interval ${info.timerId}`); + fn(...args); + }, interval)); + + const generateClearInterceptor = (type, originalClearFunction) => (handle) => { + originalClearFunction(handle); + const infoIndex = timers.findIndex((i) => i.handle === handle && i.type === type); + if (infoIndex > -1) timers.splice(infoIndex, 1); + checkWaits(); + } + const clearTimeoutInterceptor = generateClearInterceptor('timeout', originalClearTimeout); + const clearIntervalInterceptor = generateClearInterceptor('interval', originalClearInterval); + + setTimeout = setTimeoutInterceptor; + setInterval = setIntervalInterceptor; + clearTimeout = clearTimeoutInterceptor; + clearInterval = clearIntervalInterceptor; + + return { + waitAllActiveTimers, + clearAllActiveTimers, + timers, + restore: () => { + if (theseWrappersActive) { + theseWrappersActive = false; + setTimeout = originalSetTimeout; + setInterval = originalSetInterval; + clearTimeout = originalClearTimeout; + clearInterval = originalClearInterval; + } + } + } +} diff --git a/test/spec/modules/uid2IdSystem_spec.js b/test/spec/modules/uid2IdSystem_spec.js new file mode 100644 index 00000000000..b33e8cda501 --- /dev/null +++ b/test/spec/modules/uid2IdSystem_spec.js @@ -0,0 +1,310 @@ +import {coreStorage, init, setSubmoduleRegistry, requestBidsHook} from 'modules/userId/index.js'; +import {config} from 'src/config.js'; +import * as utils from 'src/utils.js'; +import { uid2IdSubmodule } from 'modules/uid2IdSystem.js'; +import 'src/prebid.js'; +import { getGlobal } from 'src/prebidGlobal.js'; +import { server } from 'test/mocks/xhr.js'; +import { configureTimerInterceptors } from 'test/mocks/timers.js'; +import {hook} from 'src/hook.js'; +import {uninstall as uninstallGdprEnforcement} from 'modules/gdprEnforcement.js'; + +let expect = require('chai').expect; + +const clearTimersAfterEachTest = true; +const debugOutput = () => {}; + +const expireCookieDate = 'Thu, 01 Jan 1970 00:00:01 GMT'; +const msIn12Hours = 60 * 60 * 12 * 1000; +const moduleCookieName = '__uid2_advertising_token'; +const publisherCookieName = '__UID2_SERVER_COOKIE'; +const auctionDelayMs = 10; +const legacyConfigParams = null; +const serverCookieConfigParams = { uid2ServerCookie: publisherCookieName } +const getFutureCookieExpiry = () => new Date(Date.now() + msIn12Hours).toUTCString(); +const setPublisherCookie = (token) => coreStorage.setCookie(publisherCookieName, JSON.stringify(token), getFutureCookieExpiry()); + +const makePrebidIdentityContainer = (token) => ({uid2: {id: token}}); +const makePrebidConfig = (params = null, extraSettings = {}, debug = false) => ({ + userSync: { auctionDelay: auctionDelayMs, userIds: [{name: 'uid2', params}] }, debug, ...extraSettings +}); + +const initialToken = `initial-advertising-token`; +const legacyToken = 'legacy-advertising-token'; +const refreshedToken = 'refreshed-advertising-token'; +const makeUid2Token = (token = initialToken, shouldRefresh = false, expired = false) => ({ + advertising_token: token, + refresh_token: 'fake-refresh-token', + identity_expires: expired ? Date.now() - 1000 : Date.now() + 60 * 60 * 1000, + refresh_from: shouldRefresh ? Date.now() - 1000 : Date.now() + 60 * 1000, + refresh_expires: Date.now() + 24 * 60 * 60 * 1000, // 24 hours + refresh_response_key: 'wR5t6HKMfJ2r4J7fEGX9Gw==', +}); +const expectInitialToken = (bid) => expect(bid?.userId ?? {}).to.deep.include(makePrebidIdentityContainer(initialToken)); +const expectRefreshedToken = (bid) => expect(bid?.userId ?? {}).to.deep.include(makePrebidIdentityContainer(refreshedToken)); +const expectNoIdentity = (bid) => expect(bid).to.not.haveOwnProperty('userId'); +const expectGlobalToHaveRefreshedIdentity = () => expect(getGlobal().getUserIds()).to.deep.include(makePrebidIdentityContainer(refreshedToken)); +const expectGlobalToHaveNoUid2 = () => expect(getGlobal().getUserIds()).to.not.haveOwnProperty('uid2'); +const expectLegacyToken = (bid) => expect(bid.userId).to.deep.include(makePrebidIdentityContainer(legacyToken)); +const expectNoLegacyToken = (bid) => expect(bid.userId).to.not.deep.include(makePrebidIdentityContainer(legacyToken)); +const expectModuleCookieEmptyOrMissing = () => expect(coreStorage.getCookie(moduleCookieName)).to.be.null; +const expectModuleCookieToContain = (initialIdentity, latestIdentity) => { + const cookie = JSON.parse(coreStorage.getCookie(moduleCookieName)); + if (initialIdentity) expect(cookie.originalToken.advertising_token).to.equal(initialIdentity); + if (latestIdentity) expect(cookie.latestToken.advertising_token).to.equal(latestIdentity); +} + +const apiUrl = 'https://prod.uidapi.com/v2/token/refresh'; +const headers = { 'Content-Type': 'application/json' }; +const makeSuccessResponseBody = () => btoa(JSON.stringify({ status: 'success', body: { ...makeUid2Token(), advertising_token: refreshedToken } })); +const configureUid2Response = (httpStatus, response) => server.respondWith('POST', apiUrl, (xhr) => xhr.respond(httpStatus, headers, response)); +const configureUid2ApiSuccessResponse = () => configureUid2Response(200, makeSuccessResponseBody()); +const configureUid2ApiFailResponse = () => configureUid2Response(500, 'Error'); + +const respondAfterDelay = (delay) => new Promise((resolve) => setTimeout(() => { + server.respond(); + setTimeout(() => resolve()); +}, delay)); + +const runAuction = async () => { + const adUnits = [{ + code: 'adUnit-code', + mediaTypes: {banner: {}, native: {}}, + sizes: [[300, 200], [300, 600]], + bids: [{bidder: 'sampleBidder', params: {placementId: 'banner-only-bidder'}}] + }]; + return new Promise(function(resolve) { + requestBidsHook(function() { + resolve(adUnits[0].bids[0]); + }, {adUnits}); + }); +} + +// Runs the provided test twice - once with a successful API mock, once with one which returns a server error +const testApiSuccessAndFailure = (act, testDescription, failTestDescription, only = false) => { + const testFn = only ? it.only : it; + testFn(`API responds successfully: ${testDescription}`, async function() { + configureUid2ApiSuccessResponse(); + await act(true); + }); + testFn(`API responds with an error: ${failTestDescription ?? testDescription}`, async function() { + configureUid2ApiFailResponse(); + await act(false); + }); +} +describe(`UID2 module`, function () { + let suiteSandbox, testSandbox, timerSpy, fullTestTitle, restoreSubtleToUndefined = false; + before(function () { + timerSpy = configureTimerInterceptors(debugOutput); + hook.ready(); + uninstallGdprEnforcement(); + + suiteSandbox = sinon.sandbox.create(); + // I'm unable to find an authoritative source, but apparently subtle isn't available in some test stacks for security reasons. + // I've confirmed it's available in Firefox since v34 (it seems to be unavailable on BrowserStack in Firefox v106). + if (typeof window.crypto.subtle === 'undefined') { + restoreSubtleToUndefined = true; + window.crypto.subtle = { importKey: () => {}, decrypt: () => {} }; + } + suiteSandbox.stub(window.crypto.subtle, 'importKey').callsFake(() => Promise.resolve()); + suiteSandbox.stub(window.crypto.subtle, 'decrypt').callsFake((settings, key, data) => Promise.resolve(new Uint8Array([...settings.iv, ...data]))); + }); + + after(function () { + suiteSandbox.restore(); + timerSpy.restore(); + if (restoreSubtleToUndefined) window.crypto.subtle = undefined; + }); + + const getFullTestTitle = (test) => `${test.parent.title ? getFullTestTitle(test.parent) + ' | ' : ''}${test.title}`; + beforeEach(function () { + debugOutput(`----------------- START TEST ------------------`); + fullTestTitle = getFullTestTitle(this.test.ctx.currentTest); + debugOutput(fullTestTitle); + testSandbox = sinon.sandbox.create(); + testSandbox.stub(utils, 'logWarn'); + + init(config); + setSubmoduleRegistry([uid2IdSubmodule]); + }); + + afterEach(async function() { + $$PREBID_GLOBAL$$.requestBids.removeAll(); + config.resetConfig(); + testSandbox.restore(); + if (timerSpy.timers.length > 0) { + if (clearTimersAfterEachTest) { + debugOutput(`Cancelling ${timerSpy.timers.length} still-active timers.`); + timerSpy.clearAllActiveTimers(); + } else { + debugOutput(`Waiting on ${timerSpy.timers.length} still-active timers...`, timerSpy.timers); + await timerSpy.waitAllActiveTimers(); + } + } + coreStorage.setCookie(moduleCookieName, '', expireCookieDate); + coreStorage.setCookie(publisherCookieName, '', expireCookieDate); + + debugOutput('----------------- END TEST ------------------'); + }); + + describe('Configuration', function() { + it('When no baseUrl is provided in config, the module calls the production endpoint', function() { + const uid2Token = makeUid2Token(initialToken, true, true); + config.setConfig(makePrebidConfig({uid2Token})); + expect(server.requests[0]?.url).to.have.string('https://prod.uidapi.com/'); + }); + + it('When a baseUrl is provided in config, the module calls the provided endpoint', function() { + const uid2Token = makeUid2Token(initialToken, true, true); + config.setConfig(makePrebidConfig({uid2Token, uid2ApiBase: 'https://operator-integ.uidapi.com'})); + expect(server.requests[0]?.url).to.have.string('https://operator-integ.uidapi.com/'); + }); + }); + + it('When a legacy value is provided directly in configuration, it is passed on', async function() { + const valueConfig = makePrebidConfig(); + valueConfig.userSync.userIds[0].value = {uid2: {id: legacyToken}} + config.setConfig(valueConfig); + const bid = await runAuction(); + + expectLegacyToken(bid); + }); + + // These tests cover 'legacy' cookies - i.e. cookies set with just the uid2 advertising token, which was how some previous integrations worked. + // Some users might still have this cookie, and the module should use that token if a newer one isn't provided. + // This should cover older integrations where the server is setting this legacy cookie and expecting the module to pass it on. + describe('When a legacy cookie exists', function () { + // Creates a test which sets the legacy cookie, configures the UID2 module with provided params, runs an + const createLegacyTest = function(params, bidAssertions) { + return async function() { + coreStorage.setCookie(moduleCookieName, legacyToken, getFutureCookieExpiry()); + config.setConfig(makePrebidConfig(params)); + + const bid = await runAuction(); + bidAssertions.forEach(function(assertion) { assertion(bid); }); + } + }; + + it('and a legacy config is used, it should provide the legacy cookie', + createLegacyTest(legacyConfigParams, [expectLegacyToken])); + it('and a server cookie config is used without a valid server cookie, it should provide the legacy cookie', + createLegacyTest(serverCookieConfigParams, [expectLegacyToken])); + it('and a server cookie is used with a valid server cookie, it should provide the server cookie', + async function() { setPublisherCookie(makeUid2Token()); await createLegacyTest(serverCookieConfigParams, [expectInitialToken, expectNoLegacyToken])(); }); + it('and a token is provided in config, it should provide the config token', + createLegacyTest({uid2Token: makeUid2Token()}, [expectInitialToken, expectNoLegacyToken])); + }); + + // This setup runs all of the functional tests with both types of config - the full token response in params, or a server cookie with the cookie name provided + let scenarios = [ + { + name: 'Token provided in config call', + setConfig: (token, extraConfig = {}) => config.setConfig(makePrebidConfig({uid2Token: token}, extraConfig)), + }, + { + name: 'Token provided in server-set cookie', + setConfig: (token, extraConfig) => { + setPublisherCookie(token); + config.setConfig(makePrebidConfig(serverCookieConfigParams, extraConfig)); + }, + } + ] + + scenarios.forEach(function(scenario) { + describe(scenario.name, function() { + describe(`When an expired token which can be refreshed is provided`, function() { + describe('When the refresh is available in time', function() { + testApiSuccessAndFailure(async function(apiSucceeds) { + scenario.setConfig(makeUid2Token(initialToken, true, true)); + respondAfterDelay(auctionDelayMs / 10); + const bid = await runAuction(); + + if (apiSucceeds) expectRefreshedToken(bid); + else expectNoIdentity(bid); + }, 'it should be used in the auction', 'the auction should have no uid2'); + + testApiSuccessAndFailure(async function(apiSucceeds) { + scenario.setConfig(makeUid2Token(initialToken, true, true)); + respondAfterDelay(auctionDelayMs / 10); + + await runAuction(); + if (apiSucceeds) { + expectModuleCookieToContain(initialToken, refreshedToken); + } else { + expectModuleCookieEmptyOrMissing(); + } + }, 'the refreshed token should be stored in the module cookie', 'the module cookie should not be set'); + }); + describe(`when the response doesn't arrive before the auction timer`, function() { + testApiSuccessAndFailure(async function() { + scenario.setConfig(makeUid2Token(initialToken, true, true)); + const bid = await runAuction(); + expectNoIdentity(bid); + }, 'it should run the auction'); + + testApiSuccessAndFailure(async function(apiSucceeds) { + scenario.setConfig(makeUid2Token(initialToken, true, true)); + const promise = respondAfterDelay(auctionDelayMs * 2); + + const bid = await runAuction(); + expectNoIdentity(bid); + expectGlobalToHaveNoUid2(); + await promise; + if (apiSucceeds) expectGlobalToHaveRefreshedIdentity(); + else expectGlobalToHaveNoUid2(); + }, 'it should update the userId after the auction', 'there should be no global identity'); + }) + describe('and there is a refreshed token in the module cookie', function() { + it('the refreshed value from the cookie is used', async function() { + const initialIdentity = makeUid2Token(initialToken, true, true); + const refreshedIdentity = makeUid2Token(refreshedToken); + const moduleCookie = {originalToken: initialIdentity, latestToken: refreshedIdentity}; + coreStorage.setCookie(moduleCookieName, JSON.stringify(moduleCookie), getFutureCookieExpiry()); + scenario.setConfig(initialIdentity); + + const bid = await runAuction(); + expectRefreshedToken(bid); + }); + }) + }); + + describe(`When a current token is provided`, function() { + beforeEach(function() { + scenario.setConfig(makeUid2Token()); + }); + + it('it should use the token in the auction', async function() { + const bid = await runAuction(); + expectInitialToken(bid); + }); + }); + + describe(`When a current token which should be refreshed is provided, and the auction is set to run immediately`, function() { + beforeEach(function() { + scenario.setConfig(makeUid2Token(initialToken, true), {auctionDelay: 0, syncDelay: 1}); + }); + testApiSuccessAndFailure(async function() { + respondAfterDelay(10); + const bid = await runAuction(); + expectInitialToken(bid); + }, 'it should not be refreshed before the auction runs'); + + testApiSuccessAndFailure(async function(success) { + const promise = respondAfterDelay(1); + await runAuction(); + await promise; + if (success) { + expectModuleCookieToContain(initialToken, refreshedToken); + } else { + expectModuleCookieToContain(initialToken, initialToken); + } + }, 'the refreshed token should be stored in the module cookie after the auction runs', 'the module cookie should only have the original token'); + + it('it should use the current token in the auction', async function() { + const bid = await runAuction(); + expectInitialToken(bid); + }); + }); + }); + }); +}); From bc68d77cf85409c5f9f2c184a7e10bef2169d348 Mon Sep 17 00:00:00 2001 From: GlobalsunHB <119595168+GlobalsunHB@users.noreply.github.com> Date: Thu, 15 Dec 2022 15:22:55 +0200 Subject: [PATCH 205/367] Globalsun Bid Adapter: Initial Release (#9307) * init new adapter Globalsun * kick off integration tests Co-authored-by: Chris Huie --- modules/globalsunBidAdapter.js | 212 ++++++++++ modules/globalsunBidAdapter.md | 79 ++++ test/spec/modules/globalsunBidAdapter_spec.js | 398 ++++++++++++++++++ 3 files changed, 689 insertions(+) create mode 100644 modules/globalsunBidAdapter.js create mode 100644 modules/globalsunBidAdapter.md create mode 100644 test/spec/modules/globalsunBidAdapter_spec.js diff --git a/modules/globalsunBidAdapter.js b/modules/globalsunBidAdapter.js new file mode 100644 index 00000000000..ae3407bbbdd --- /dev/null +++ b/modules/globalsunBidAdapter.js @@ -0,0 +1,212 @@ +import { isFn, deepAccess, logMessage, logError } from '../src/utils.js'; +import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; + +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; + +const BIDDER_CODE = 'globalsun'; +const AD_URL = 'https://endpoint.globalsun.io/pbjs'; +const SYNC_URL = 'https://cs.globalsun.io'; + +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 || bid.vastXml); + case NATIVE: + return Boolean(bid.native && bid.native.impressionTrackers && bid.native.impressionTrackers.length); + default: + return false; + } +} + +function getPlacementReqData(bid) { + const { params, bidId, mediaTypes } = bid; + const schain = bid.schain || {}; + const { placementId, endpointId } = params; + const bidfloor = getBidFloor(bid); + + const placement = { + bidId, + schain, + bidfloor + }; + + if (placementId) { + placement.placementId = placementId; + placement.type = 'publisher'; + } else if (endpointId) { + placement.endpointId = endpointId; + placement.type = 'network'; + } + + if (mediaTypes && mediaTypes[BANNER]) { + placement.adFormat = BANNER; + placement.sizes = mediaTypes[BANNER].sizes; + } else if (mediaTypes && mediaTypes[VIDEO]) { + placement.adFormat = VIDEO; + placement.playerSize = mediaTypes[VIDEO].playerSize; + placement.minduration = mediaTypes[VIDEO].minduration; + placement.maxduration = mediaTypes[VIDEO].maxduration; + placement.mimes = mediaTypes[VIDEO].mimes; + placement.protocols = mediaTypes[VIDEO].protocols; + placement.startdelay = mediaTypes[VIDEO].startdelay; + placement.placement = mediaTypes[VIDEO].placement; + placement.skip = mediaTypes[VIDEO].skip; + placement.skipafter = mediaTypes[VIDEO].skipafter; + placement.minbitrate = mediaTypes[VIDEO].minbitrate; + placement.maxbitrate = mediaTypes[VIDEO].maxbitrate; + placement.delivery = mediaTypes[VIDEO].delivery; + placement.playbackmethod = mediaTypes[VIDEO].playbackmethod; + placement.api = mediaTypes[VIDEO].api; + placement.linearity = mediaTypes[VIDEO].linearity; + } else if (mediaTypes && mediaTypes[NATIVE]) { + placement.native = mediaTypes[NATIVE]; + placement.adFormat = NATIVE; + } + + return placement; +} + +function getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return deepAccess(bid, 'params.bidfloor', 0); + } + + try { + const bidFloor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (err) { + logError(err); + return 0; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + + isBidRequestValid: (bid = {}) => { + const { params, bidId, mediaTypes } = bid; + let valid = Boolean(bidId && params && (params.placementId || params.endpointId)); + + if (mediaTypes && mediaTypes[BANNER]) { + valid = valid && Boolean(mediaTypes[BANNER] && mediaTypes[BANNER].sizes); + } else if (mediaTypes && mediaTypes[VIDEO]) { + valid = valid && Boolean(mediaTypes[VIDEO] && mediaTypes[VIDEO].playerSize); + } else if (mediaTypes && mediaTypes[NATIVE]) { + valid = valid && Boolean(mediaTypes[NATIVE]); + } else { + valid = false; + } + return valid; + }, + + buildRequests: (validBidRequests = [], bidderRequest = {}) => { + // convert Native ORTB definition to old-style prebid native definition + validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); + + let deviceWidth = 0; + let deviceHeight = 0; + + let winLocation; + try { + const winTop = window.top; + deviceWidth = winTop.screen.width; + deviceHeight = winTop.screen.height; + winLocation = winTop.location; + } catch (e) { + logMessage(e); + winLocation = window.location; + } + + const refferUrl = bidderRequest.refererInfo && bidderRequest.refererInfo.page; + let refferLocation; + try { + refferLocation = refferUrl && new URL(refferUrl); + } catch (e) { + logMessage(e); + } + // TODO: does the fallback make sense here? + let location = refferLocation || winLocation; + const language = (navigator && navigator.language) ? navigator.language.split('-')[0] : ''; + const host = location.host; + const page = location.pathname; + const secure = location.protocol === 'https:' ? 1 : 0; + const placements = []; + const request = { + deviceWidth, + deviceHeight, + language, + secure, + host, + page, + placements, + coppa: config.getConfig('coppa') === true ? 1 : 0, + ccpa: bidderRequest.uspConsent || undefined, + gdpr: bidderRequest.gdprConsent || undefined, + tmax: config.getConfig('bidderTimeout') + }; + + const len = validBidRequests.length; + for (let i = 0; i < len; i++) { + const bid = validBidRequests[i]; + placements.push(getPlacementReqData(bid)); + } + + 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)) { + const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : []; + resItem.meta = { ...resItem.meta, advertiserDomains }; + + response.push(resItem); + } + } + return response; + }, + + getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { + let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image'; + let syncUrl = SYNC_URL + `/${syncType}?pbjs=1`; + if (gdprConsent && gdprConsent.consentString) { + if (typeof gdprConsent.gdprApplies === 'boolean') { + syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + syncUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`; + } + } + if (uspConsent && uspConsent.consentString) { + syncUrl += `&ccpa_consent=${uspConsent.consentString}`; + } + + const coppa = config.getConfig('coppa') ? 1 : 0; + syncUrl += `&coppa=${coppa}`; + + return [{ + type: syncType, + url: syncUrl + }]; + } +}; + +registerBidder(spec); diff --git a/modules/globalsunBidAdapter.md b/modules/globalsunBidAdapter.md new file mode 100644 index 00000000000..07c3ce32155 --- /dev/null +++ b/modules/globalsunBidAdapter.md @@ -0,0 +1,79 @@ +# Overview + +``` +Module Name: Globalsun Bidder Adapter +Module Type: Globalsun Bidder Adapter +Maintainer: prebid@globalsun.io +``` + +# Description + +Connects to Globalsun exchange for bids. +Globalsun bid adapter supports Banner, Video (instream and outstream) and Native. + +# Test Parameters +``` + var adUnits = [ + // Will return static test banner + { + code: 'adunit1', + mediaTypes: { + banner: { + sizes: [ [300, 250], [320, 50] ], + } + }, + bids: [ + { + bidder: 'globalsun', + params: { + placementId: 'testBanner', + } + } + ] + }, + { + code: 'addunit2', + mediaTypes: { + video: { + playerSize: [ [640, 480] ], + context: 'instream', + minduration: 5, + maxduration: 60, + } + }, + bids: [ + { + bidder: 'globalsun', + params: { + placementId: 'testVideo', + } + } + ] + }, + { + code: 'addunit3', + mediaTypes: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + }, + bids: [ + { + bidder: 'globalsun', + params: { + placementId: 'testNative', + } + } + ] + } + ]; +``` diff --git a/test/spec/modules/globalsunBidAdapter_spec.js b/test/spec/modules/globalsunBidAdapter_spec.js new file mode 100644 index 00000000000..3795f3038a7 --- /dev/null +++ b/test/spec/modules/globalsunBidAdapter_spec.js @@ -0,0 +1,398 @@ +import { expect } from 'chai'; +import { spec } from '../../../modules/globalsunBidAdapter.js'; +import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js'; +import { getUniqueIdentifierStr } from '../../../src/utils.js'; + +const bidder = 'globalsun' + +describe('GlobalsunBidAdapter', function () { + const bids = [ + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + placementId: 'testBanner', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [VIDEO]: { + playerSize: [[300, 300]], + minduration: 5, + maxduration: 60 + } + }, + params: { + placementId: 'testVideo', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [NATIVE]: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + } + }, + params: { + placementId: 'testNative', + } + } + ]; + + const invalidBid = { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + + } + } + + const bidderRequest = { + uspConsent: '1---', + gdprConsent: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw', + refererInfo: { + referer: 'https://test.com' + } + }; + + describe('isBidRequestValid', function () { + it('Should return true if there are bidId, params and key parameters present', function () { + expect(spec.isBidRequestValid(bids[0])).to.be.true; + }); + it('Should return false if at least one of parameters is not present', function () { + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + }); + + describe('buildRequests', function () { + let serverRequest = spec.buildRequests(bids, 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://endpoint.globalsun.io/pbjs'); + }); + + it('Returns general data 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', + 'coppa', + 'ccpa', + 'gdpr', + 'tmax' + ); + 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.coppa).to.be.a('number'); + expect(data.gdpr).to.be.a('string'); + expect(data.ccpa).to.be.a('string'); + expect(data.tmax).to.be.a('number'); + expect(data.placements).to.have.lengthOf(3); + }); + + it('Returns valid placements', function () { + const { placements } = serverRequest.data; + for (let i = 0, len = placements.length; i < len; i++) { + const placement = placements[i]; + expect(placement.placementId).to.be.oneOf(['testBanner', 'testVideo', 'testNative']); + expect(placement.adFormat).to.be.oneOf([BANNER, VIDEO, NATIVE]); + expect(placement.bidId).to.be.a('string'); + expect(placement.schain).to.be.an('object'); + expect(placement.bidfloor).to.exist.and.to.equal(0); + expect(placement.type).to.exist.and.to.equal('publisher'); + + if (placement.adFormat === BANNER) { + expect(placement.sizes).to.be.an('array'); + } + switch (placement.adFormat) { + case BANNER: + expect(placement.sizes).to.be.an('array'); + break; + case VIDEO: + expect(placement.playerSize).to.be.an('array'); + expect(placement.minduration).to.be.an('number'); + expect(placement.maxduration).to.be.an('number'); + break; + case NATIVE: + expect(placement.native).to.be.an('object'); + break; + } + } + }); + + it('Returns data with gdprConsent and without uspConsent', function () { + delete bidderRequest.uspConsent; + serverRequest = spec.buildRequests(bids, 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 = '1---'; + delete bidderRequest.gdprConsent; + serverRequest = spec.buildRequests(bids, 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([], bidderRequest); + 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', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + 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', 'meta'); + expect(dataItem.requestId).to.equal(banner.body[0].requestId); + expect(dataItem.cpm).to.equal(banner.body[0].cpm); + expect(dataItem.width).to.equal(banner.body[0].width); + expect(dataItem.height).to.equal(banner.body[0].height); + expect(dataItem.ad).to.equal(banner.body[0].ad); + expect(dataItem.ttl).to.equal(banner.body[0].ttl); + expect(dataItem.creativeId).to.equal(banner.body[0].creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(banner.body[0].currency); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + 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', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + 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', 'meta'); + 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'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + 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', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + 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', 'meta'); + 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'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + 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() { + it('Should return array of objects with proper sync config , include GDPR', function() { + const syncData = spec.getUserSyncs({}, {}, { + consentString: 'ALL', + gdprApplies: true, + }, {}); + expect(syncData).to.be.an('array').which.is.not.empty; + expect(syncData[0]).to.be.an('object') + expect(syncData[0].type).to.be.a('string') + expect(syncData[0].type).to.equal('image') + expect(syncData[0].url).to.be.a('string') + expect(syncData[0].url).to.equal('https://cs.globalsun.io/image?pbjs=1&gdpr=1&gdpr_consent=ALL&coppa=0') + }); + it('Should return array of objects with proper sync config , include CCPA', function() { + const syncData = spec.getUserSyncs({}, {}, {}, { + consentString: '1---' + }); + expect(syncData).to.be.an('array').which.is.not.empty; + expect(syncData[0]).to.be.an('object') + expect(syncData[0].type).to.be.a('string') + expect(syncData[0].type).to.equal('image') + expect(syncData[0].url).to.be.a('string') + expect(syncData[0].url).to.equal('https://cs.globalsun.io/image?pbjs=1&ccpa_consent=1---&coppa=0') + }); + }); +}); From 77ba4ece1dce547c3ca824d43b79e6529c843aa6 Mon Sep 17 00:00:00 2001 From: Nitin Nimbalkar <96475150+nitin0610@users.noreply.github.com> Date: Fri, 16 Dec 2022 02:50:27 +0530 Subject: [PATCH 206/367] Topics module: Initial Topics iframe implementation (#8947) * Topics: Initial Topics iframe implementation * Topics API: LINT errors solved * Added Empty Topics Check * Topics: Storage Map logic and added message listener secure check * Topics: Iframe implementation for bidders * Added topics_iframe html in example for reference * Added Pubmatic Topic iframe URL * Added Pubmatic Topic iframe URL- Removed comment * Topics Module: Consent management logic added * Topics Module: Added Device Access check * Topics Module: Unit test cases added and minor changes * Topics Module: Array.find used instead of array.some and variable name changed * Topics IFrame Implementation: Purpose present check is handled --- integrationExamples/gpt/topics_frame.html | 43 +++++ modules/topicsFpdModule.js | 183 +++++++++++++++++++++- test/spec/modules/topicsFpdModule_spec.js | 178 ++++++++++++++++++++- 3 files changed, 401 insertions(+), 3 deletions(-) create mode 100644 integrationExamples/gpt/topics_frame.html diff --git a/integrationExamples/gpt/topics_frame.html b/integrationExamples/gpt/topics_frame.html new file mode 100644 index 00000000000..7a12b030a6a --- /dev/null +++ b/integrationExamples/gpt/topics_frame.html @@ -0,0 +1,43 @@ + + + + Topics demo + + + + + + + + + \ No newline at end of file diff --git a/modules/topicsFpdModule.js b/modules/topicsFpdModule.js index dbd1d3e90e9..f5a3c0a2c70 100644 --- a/modules/topicsFpdModule.js +++ b/modules/topicsFpdModule.js @@ -1,8 +1,31 @@ -import {logError, logWarn, mergeDeep} from '../src/utils.js'; +import {logError, logWarn, mergeDeep, isEmpty, safeJSONParse, logInfo, hasDeviceAccess} from '../src/utils.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {submodule} from '../src/hook.js'; import {GreedyPromise} from '../src/utils/promise.js'; +import {config} from '../src/config.js'; +import {getCoreStorageManager} from '../src/storageManager.js'; +import {includes} from '../src/polyfill.js'; +import {gdprDataHandler} from '../src/adapterManager.js'; +const MODULE_NAME = 'topicsFpd'; +const DEFAULT_EXPIRATION_DAYS = 21; +const TCF_REQUIRED_PURPOSES = ['1', '2', '3', '4']; +let HAS_GDPR_CONSENT = true; +let LOAD_TOPICS_INITIALISE = false; +const HAS_DEVICE_ACCESS = hasDeviceAccess(); + +const bidderIframeList = { + maxTopicCaller: 1, + bidders: [{ + bidder: 'pubmatic', + iframeURL: 'https://ads.pubmatic.com/AdServer/js/topics/topics_frame.html' + }] +} +export const coreStorage = getCoreStorageManager(MODULE_NAME); +export const topicStorageName = 'prebid:topics'; +export const lastUpdated = 'lastUpdated'; + +const iframeLoadedURL = []; const TAXONOMIES = { // map from topic taxonomyVersion to IAB segment taxonomy '1': 600 @@ -17,6 +40,20 @@ function partitionBy(field, items) { }, {}); } +/** + * function to get list of loaded Iframes calling Topics API + */ +function getLoadedIframeURL() { + return iframeLoadedURL; +} + +/** + * function to set/push iframe in the list which is loaded to called topics API. + */ +function setLoadedIframeURL(url) { + return iframeLoadedURL.push(url); +} + export function getTopicsData(name, topics, taxonomies = TAXONOMIES) { return Object.entries(partitionBy('taxonomyVersion', topics)) .filter(([taxonomyVersion]) => { @@ -61,7 +98,12 @@ export function getTopics(doc = document) { const topicsData = getTopics().then((topics) => getTopicsData(getRefererInfo().domain, topics)); export function processFpd(config, {global}, {data = topicsData} = {}) { + if (!LOAD_TOPICS_INITIALISE) { + loadTopicsForBidders(); + LOAD_TOPICS_INITIALISE = true; + } return data.then((data) => { + data = [].concat(data, getCachedTopics()); // Add cached data in FPD data. if (data.length) { mergeDeep(global, { user: { @@ -73,6 +115,145 @@ export function processFpd(config, {global}, {data = topicsData} = {}) { }); } +/** + * function to fetch the cached topic data from storage for bidders and return it + */ +export function getCachedTopics() { + let cachedTopicData = []; + if (!HAS_GDPR_CONSENT || !HAS_DEVICE_ACCESS) { + return cachedTopicData; + } + const topics = config.getConfig('userSync.topics') || bidderIframeList; + const bidderList = topics.bidders || []; + let storedSegments = new Map(safeJSONParse(coreStorage.getDataFromLocalStorage(topicStorageName))); + storedSegments && storedSegments.forEach((value, cachedBidder) => { + // Check bidder exist in config for cached bidder data and then only retrieve the cached data + let bidderConfigObj = bidderList.find(({bidder}) => cachedBidder == bidder) + if (bidderConfigObj) { + if (!isCachedDataExpired(value[lastUpdated], bidderConfigObj?.expiry || DEFAULT_EXPIRATION_DAYS)) { + Object.keys(value).forEach((segData) => { + segData != lastUpdated && cachedTopicData.push(value[segData]); + }) + } else { + // delete the specific bidder map from the store and store the updated maps + storedSegments.delete(cachedBidder); + coreStorage.setDataInLocalStorage(topicStorageName, JSON.stringify([...storedSegments])); + } + } + }); + return cachedTopicData; +} + +/** + * Recieve messages from iframe loaded for bidders to fetch topic + * @param {MessageEvent} evt + */ +export function receiveMessage(evt) { + if (evt && evt.data) { + try { + let data = safeJSONParse(evt.data); + if (includes(getLoadedIframeURL(), evt.origin) && data && data.segment && !isEmpty(data.segment.topics)) { + const {domain, topics, bidder} = data.segment; + const iframeTopicsData = getTopicsData(domain, topics)[0]; + iframeTopicsData && storeInLocalStorage(bidder, iframeTopicsData); + } + } catch (err) { } + } +} + +/** +Function to store Topics data recieved from iframe in storage(name: "prebid:topics") +* @param {Topics} topics +*/ +export function storeInLocalStorage(bidder, topics) { + const storedSegments = new Map(safeJSONParse(coreStorage.getDataFromLocalStorage(topicStorageName))); + if (storedSegments.has(bidder)) { + storedSegments.get(bidder)[topics['ext']['segclass']] = topics; + storedSegments.get(bidder)[lastUpdated] = new Date().getTime(); + storedSegments.set(bidder, storedSegments.get(bidder)); + } else { + storedSegments.set(bidder, {[topics.ext.segclass]: topics, [lastUpdated]: new Date().getTime()}) + } + coreStorage.setDataInLocalStorage(topicStorageName, JSON.stringify([...storedSegments])); +} + +function isCachedDataExpired(storedTime, cacheTime) { + const _MS_PER_DAY = 1000 * 60 * 60 * 24; + const currentTime = new Date().getTime(); + const daysDifference = Math.ceil((currentTime - storedTime) / _MS_PER_DAY); + return daysDifference > cacheTime; +} + +/** +* Function to get random bidders based on count passed with array of bidders +**/ +function getRandomBidders(arr, count) { + return ([...arr].sort(() => 0.5 - Math.random())).slice(0, count) +} + +/** + * function to add listener for message receiving from IFRAME + */ +function listenMessagesFromTopicIframe() { + window.addEventListener('message', receiveMessage, false); +} + +function checkTCFv2(vendorData, requiredPurposes = TCF_REQUIRED_PURPOSES) { + const {gdprApplies, purpose} = vendorData; + if (!gdprApplies || !purpose) { + return true; + } + return requiredPurposes.map((purposeNo) => { + const purposeConsent = purpose.consents ? purpose.consents[purposeNo] : false; + if (purposeConsent) { + return true; + } + return false; + }).reduce((a, b) => a && b, true); +} + +export function hasGDPRConsent() { + // Check for GDPR consent for purpose 1,2,3,4 and return false if consent has not been given + const gdprConsent = gdprDataHandler.getConsentData(); + const hasGdpr = (gdprConsent && typeof gdprConsent.gdprApplies === 'boolean' && gdprConsent.gdprApplies) ? 1 : 0; + const gdprConsentString = hasGdpr ? gdprConsent.consentString : ''; + if (hasGdpr) { + if ((!gdprConsentString || gdprConsentString === '') || !gdprConsent.vendorData) { + return false; + } + return checkTCFv2(gdprConsent.vendorData); + } + return true; +} + +/** + * function to load the iframes of the bidder to load the topics data + */ +function loadTopicsForBidders() { + HAS_GDPR_CONSENT = hasGDPRConsent(); + if (!HAS_GDPR_CONSENT || !HAS_DEVICE_ACCESS) { + logInfo('Topics Module : Consent string is required to fetch the topics from third party domains.'); + return; + } + const topics = config.getConfig('userSync.topics') || bidderIframeList; + if (topics) { + listenMessagesFromTopicIframe(); + const randomBidders = getRandomBidders(topics.bidders || [], topics.maxTopicCaller || 1) + randomBidders && randomBidders.forEach(({ bidder, iframeURL }) => { + if (bidder && iframeURL) { + let ifrm = document.createElement('iframe'); + ifrm.name = 'ifrm_'.concat(bidder); + ifrm.src = ''.concat(iframeURL, '?bidder=').concat(bidder); + ifrm.style.display = 'none'; + setLoadedIframeURL(new URL(iframeURL).origin); + iframeURL && window.document.documentElement.appendChild(ifrm); + } + }) + } else { + logWarn(`Topics config not defined under userSync Object`); + } +} + submodule('firstPartyData', { name: 'topics', queue: 1, diff --git a/test/spec/modules/topicsFpdModule_spec.js b/test/spec/modules/topicsFpdModule_spec.js index 3781768497b..69e7cc16ca8 100644 --- a/test/spec/modules/topicsFpdModule_spec.js +++ b/test/spec/modules/topicsFpdModule_spec.js @@ -1,5 +1,7 @@ -import {getTopics, getTopicsData, processFpd} from '../../../modules/topicsFpdModule.js'; -import {deepClone} from '../../../src/utils.js'; +import {getTopics, getTopicsData, processFpd, hasGDPRConsent, getCachedTopics, receiveMessage, topicStorageName} from '../../../modules/topicsFpdModule.js'; +import {deepClone, safeJSONParse} from '../../../src/utils.js'; +import {gdprDataHandler} from 'src/adapterManager.js'; +import {getCoreStorageManager} from 'src/storageManager.js'; describe('getTopicsData', () => { function makeTopic(topic, modelv, taxv = '1') { @@ -237,3 +239,175 @@ describe('processFpd', () => { }); }); }); + +describe('Topics Module GDPR consent check', () => { + let gdprDataHdlrStub; + beforeEach(() => { + gdprDataHdlrStub = sinon.stub(gdprDataHandler, 'getConsentData'); + }) + + afterEach(() => { + gdprDataHdlrStub.restore(); + }); + + it('should return false when GDPR is applied but consent string is not present', () => { + const consentString = ''; + const consentConfig = { + consentString: consentString, + gdprApplies: true, + vendorData: {} + }; + gdprDataHdlrStub.returns(consentConfig); + expect(hasGDPRConsent()).to.equal(false); + }); + + it("should return true when GDPR doesn't apply", () => { + const consentString = 'CPi8wgAPi8wgAADABBENCrCsAP_AAH_AAAAAISNB7D=='; + const consentConfig = { + consentString: consentString, + gdprApplies: false, + vendorData: {} + }; + + gdprDataHdlrStub.returns(consentConfig); + expect(hasGDPRConsent()).to.equal(true); + }); + + it('should return true when GDPR is applied and purpose consent is true for all purpose[1,2,3,4]', () => { + const consentString = 'CPi8wgAPi8wgAADABBENCrCsAP_AAH_AAAAAISNB7D=='; + const consentConfig = { + consentString: consentString, + gdprApplies: true, + vendorData: { + metadata: consentString, + gdprApplies: true, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true + } + } + } + }; + + gdprDataHdlrStub.returns(consentConfig); + expect(hasGDPRConsent()).to.equal(true); + }); + + it('should return false when GDPR is applied and purpose consent is false for one of the purpose[1,2,3,4]', () => { + const consentString = 'CPi8wgAPi8wgAADABBENCrCsAP_AAH_AAAAAISNB7D=='; + const consentConfig = { + consentString: consentString, + gdprApplies: true, + vendorData: { + metadata: consentString, + gdprApplies: true, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: false + } + } + } + }; + + gdprDataHdlrStub.returns(consentConfig); + expect(hasGDPRConsent()).to.equal(false); + }); +}); + +describe('getCachedTopics()', () => { + const storage = getCoreStorageManager('topicsFpd'); + const expected = [{ + ext: { + segtax: 600, + segclass: '2206021246' + }, + segment: [{ + 'id': '243' + }, { + 'id': '265' + }], + name: 'ads.pubmatic.com' + }]; + const consentString = 'CPi8wgAPi8wgAADABBENCrCsAP_AAH_AAAAAISNB7D=='; + const consentConfig = { + consentString: consentString, + gdprApplies: true, + vendorData: { + metadata: consentString, + gdprApplies: true, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true + } + } + } + }; + const mockData = [ + { + name: 'domain', + segment: [{id: 123}] + }, + { + name: 'domain', + segment: [{id: 321}], + } + ]; + + const evt = { + data: '{"segment":{"domain":"ads.pubmatic.com","topics":[{"configVersion":"chrome.1","modelVersion":"2206021246","taxonomyVersion":"1","topic":165,"version":"chrome.1:1:2206021246"}],"bidder":"pubmatic"},"date":1669743901858}', + origin: 'https://ads.pubmatic.com' + } + + let gdprDataHdlrStub; + beforeEach(() => { + gdprDataHdlrStub = sinon.stub(gdprDataHandler, 'getConsentData'); + }); + + afterEach(() => { + storage.removeDataFromLocalStorage(topicStorageName); + gdprDataHdlrStub.restore(); + }); + + it('should return segments for bidder if GDPR consent is true and there is cached segments stored which is not expired', () => { + let storedSegments = '[["pubmatic",{"2206021246":{"ext":{"segtax":600,"segclass":"2206021246"},"segment":[{"id":"243"},{"id":"265"}],"name":"ads.pubmatic.com"},"lastUpdated":1669719242027}]]'; + storage.setDataInLocalStorage(topicStorageName, storedSegments); + gdprDataHdlrStub.returns(consentConfig); + assert.deepEqual(getCachedTopics(), expected); + }); + + it('should return empty segments for bidder if GDPR consent is true and there is cached segments stored which is expired', () => { + let storedSegments = '[["pubmatic",{"2206021246":{"ext":{"segtax":600,"segclass":"2206021246"},"segment":[{"id":"243"},{"id":"265"}],"name":"ads.pubmatic.com"},"lastUpdated":1659719242027}]]'; + storage.setDataInLocalStorage(topicStorageName, storedSegments); + gdprDataHdlrStub.returns(consentConfig); + assert.deepEqual(getCachedTopics(), []); + }); + + it('should stored segments if receiveMessage event is triggerred with segment data', () => { + return processFpd({}, {global: {}}, {data: Promise.resolve(mockData)}) + .then(({global}) => { + receiveMessage(evt) + let segments = new Map(safeJSONParse(storage.getDataFromLocalStorage(topicStorageName))); + expect(segments.has('pubmatic')).to.equal(true); + }); + }); + + it('should update stored segments if receiveMessage event is triggerred with segment data', () => { + let storedSegments = '[["pubmatic",{"2206021246":{"ext":{"segtax":600,"segclass":"2206021246"},"segment":[{"id":"243"},{"id":"265"}],"name":"ads.pubmatic.com"},"lastUpdated":1669719242027}]]'; + storage.setDataInLocalStorage(topicStorageName, storedSegments); + return processFpd({}, {global: {}}, {data: Promise.resolve(mockData)}) + .then(({global}) => { + receiveMessage(evt); + let segments = new Map(safeJSONParse(storage.getDataFromLocalStorage(topicStorageName))); + expect(segments.get('pubmatic')[2206021246].segment.length).to.equal(1); + }); + }); +}) From bd4a6703b43f25168865ef6eea18efbabb9bda8f Mon Sep 17 00:00:00 2001 From: jsfledd Date: Fri, 16 Dec 2022 03:35:56 -0800 Subject: [PATCH 207/367] Nativo Bid Adapter: added ntv_url qs param value validation (#9334) * Initial nativoBidAdapter document creation (js, md and spec) * Fulling working prebid using nativoBidAdapter. Support for GDPR and CCPA in user syncs. * Added defult size settings based on the largest ad unit. Added response body validation. Added consent to request url qs params. * Changed bidder endpoint url * Changed double quotes to single quotes. * Reverted package-json.lock to remove modifications from PR * Added optional bidder param 'url' so the ad server can force- match an existing placement * Lint fix. Added space after if. * Added new QS param to send various adUnit data to adapter endpopint * Updated unit test for new QS param * Added qs param to keep track of ad unit refreshes * Updated bidMap key default value * Updated refresh increment logic * Refactored spread operator for IE11 support * Updated isBidRequestValid check * Refactored Object.enties to use Object.keys to fix CircleCI testing errors * Updated bid mapping key creation to prioritize ad unit code over placementId * Added filtering by ad, advertiser and campaign. * Merged master * Added more robust bidDataMap with multiple key access * Deduped filer values * Rolled back package.json * Duped upstream/master's package.lock file ... not sure how it got changed in the first place * Small refactor of filterData length check. Removed comparison with 0 since a length value of 0 is already falsy. * Added bid sizes to request * Fixed function name in spec. Added unit tests. * Added priceFloor module support * Added protection agains empty url parameter * Changed ntv_url QS param to use referrer.location instead of referrer.page * Removed testing 'only' flag * Added ntv_url QS param value validation --- modules/nativoBidAdapter.js | 56 +++++++++++---- test/spec/modules/nativoBidAdapter_spec.js | 84 ++++++++++++++++++++++ 2 files changed, 128 insertions(+), 12 deletions(-) diff --git a/modules/nativoBidAdapter.js b/modules/nativoBidAdapter.js index 7eb37ea8b82..a92168492d0 100644 --- a/modules/nativoBidAdapter.js +++ b/modules/nativoBidAdapter.js @@ -140,13 +140,9 @@ export const spec = { const floorPriceData = {} let placementId, pageUrl validBidRequests.forEach((bidRequest) => { - pageUrl = deepAccess( - bidRequest, - 'params.url', - ) - if (pageUrl == undefined || pageUrl === '') { - pageUrl = bidderRequest.refererInfo.location - } + pageUrl = + getPageUrlFromBidRequest(bidRequest) || + bidderRequest.refererInfo.location placementId = deepAccess(bidRequest, 'params.placementId') @@ -380,10 +376,12 @@ export const spec = { return syncs } - body = - typeof response.body === 'string' - ? JSON.parse(response.body) - : response.body + try { + body = + typeof response.body === 'string' + ? JSON.parse(response.body) + : response.body + } catch (err) { return } // Make sure we have valid content if (!body || !body.seatbid || body.seatbid.length === 0) return @@ -465,7 +463,7 @@ export function parseFloorPriceData(bidRequest) { // Setup price floor data per media type let mediaTypeData = bidMediaTypes[mediaType] let mediaTypeFloorPriceData = {} - let mediaTypeSizes = mediaTypeData.sizes || mediaTypeData.playerSize || []; + let mediaTypeSizes = mediaTypeData.sizes || mediaTypeData.playerSize || [] // Step through each size of the media type so we can get floor data for each size per media type mediaTypeSizes.forEach((size) => { // Get floor price data per the getFloor method and respective media type / size combination @@ -634,3 +632,37 @@ function appendFilterData(filter, filterData) { filterData.forEach((ad) => filter.add(ad)) } } + +export function getPageUrlFromBidRequest(bidRequest) { + let paramPageUrl = deepAccess(bidRequest, 'params.url') + + if (paramPageUrl == undefined) return + + if (hasProtocol(paramPageUrl)) return paramPageUrl + + paramPageUrl = addProtocol(paramPageUrl) + + try { + const url = new URL(paramPageUrl) + return url.href + } catch (err) {} +} + +export function hasProtocol(url) { + const protocolRegexp = /^http[s]?\:/ + return protocolRegexp.test(url) +} + +export function addProtocol(url) { + if (hasProtocol(url)) { + return url + } + + let protocolPrefix = 'https:' + + if (url.indexOf('//') !== 0) { + protocolPrefix += '//' + } + + return `${protocolPrefix}${url}` +} diff --git a/test/spec/modules/nativoBidAdapter_spec.js b/test/spec/modules/nativoBidAdapter_spec.js index 4cd4c92281b..4d70e6f7071 100644 --- a/test/spec/modules/nativoBidAdapter_spec.js +++ b/test/spec/modules/nativoBidAdapter_spec.js @@ -5,6 +5,9 @@ import { getMediaWildcardPrices, sizeToString, parseFloorPriceData, + getPageUrlFromBidRequest, + hasProtocol, + addProtocol, } from '../../../modules/nativoBidAdapter' describe('bidDataMap', function () { @@ -647,3 +650,84 @@ describe('parseFloorPriceData', () => { }) }) }) + +describe('hasProtocol', () => { + it('https://www.testpage.com', () => { + expect(hasProtocol('https://www.testpage.com')).to.be.true + }) + it('http://www.testpage.com', () => { + expect(hasProtocol('http://www.testpage.com')).to.be.true + }) + it('//www.testpage.com', () => { + expect(hasProtocol('//www.testpage.com')).to.be.false + }) + it('www.testpage.com', () => { + expect(hasProtocol('www.testpage.com')).to.be.false + }) + it('httpsgsjhgflih', () => { + expect(hasProtocol('httpsgsjhgflih')).to.be.false + }) +}) + +describe('addProtocol', () => { + it('www.testpage.com', () => { + expect(addProtocol('www.testpage.com')).to.be.equal('https://www.testpage.com') + }) + it('//www.testpage.com', () => { + expect(addProtocol('//www.testpage.com')).to.be.equal('https://www.testpage.com') + }) + it('http://www.testpage.com', () => { + expect(addProtocol('http://www.testpage.com')).to.be.equal('http://www.testpage.com') + }) + it('https://www.testpage.com', () => { + expect(addProtocol('https://www.testpage.com')).to.be.equal('https://www.testpage.com') + }) +}) + +describe('getPageUrlFromBidRequest', () => { + const bidRequest = {} + + beforeEach(() => { + bidRequest.params = {} + }) + + it('Returns undefined for no url param', () => { + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).to.be.undefined + }) + + it('@testUrl', () => { + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).to.be.undefined + }) + + it('https://www.testpage.com', () => { + bidRequest.params.url = 'https://www.testpage.com' + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).not.to.be.undefined + }) + + it('https://www.testpage.com/test/path', () => { + bidRequest.params.url = 'https://www.testpage.com/test/path' + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).not.to.be.undefined + }) + + it('www.testpage.com', () => { + bidRequest.params.url = 'www.testpage.com' + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).not.to.be.undefined + }) + + it('http://www.testpage.com', () => { + bidRequest.params.url = 'http://www.testpage.com' + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).not.to.be.undefined + }) + + it('//www.testpage.com', () => { + bidRequest.params.url = '//www.testpage.com' + const url = getPageUrlFromBidRequest(bidRequest) + expect(url).not.to.be.undefined + }) +}) From 75d0c737d6493f49f19cdb9c1cccc0fee30cee15 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 16 Dec 2022 15:01:38 +0000 Subject: [PATCH 208/367] Prebid 7.29.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 006b8bcdcab..f5bf3feb080 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.29.0-pre", + "version": "7.29.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 5ee4cb728b1..acda15c2d0e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.29.0-pre", + "version": "7.29.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 37259fc9d8fead5e9d0783202f31f96e32c49e2d Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 16 Dec 2022 15:01:38 +0000 Subject: [PATCH 209/367] Increment version to 7.30.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f5bf3feb080..c903795e59d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.29.0", + "version": "7.30.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index acda15c2d0e..490303874f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.29.0", + "version": "7.30.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From a531b20b5d6a72ab9e299c1d73a2e9cf959a5abd Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Mon, 19 Dec 2022 15:01:09 -0700 Subject: [PATCH 210/367] Build system: set up `hook` for tests (#9350) --- karma.conf.maker.js | 2 +- test/helpers/hookSetup.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 test/helpers/hookSetup.js diff --git a/karma.conf.maker.js b/karma.conf.maker.js index 692db7755e8..e05d5b08afd 100644 --- a/karma.conf.maker.js +++ b/karma.conf.maker.js @@ -110,7 +110,7 @@ module.exports = function(codeCoverage, browserstack, watchMode, file, disableFe var webpackConfig = newWebpackConfig(codeCoverage, disableFeatures); var plugins = newPluginsArray(browserstack); - var files = file ? ['test/test_deps.js', file].flatMap(f => f) : ['test/test_index.js']; + var files = file ? ['test/test_deps.js', file, 'test/helpers/hookSetup.js'].flatMap(f => f) : ['test/test_index.js']; // This file opens the /debug.html tab automatically. // It has no real value unless you're running --watch, and intend to do some debugging in the browser. if (watchMode) { diff --git a/test/helpers/hookSetup.js b/test/helpers/hookSetup.js new file mode 100644 index 00000000000..2de35bb1dd4 --- /dev/null +++ b/test/helpers/hookSetup.js @@ -0,0 +1,5 @@ +import {hook} from '../../src/hook.js'; + +before(() => { + hook.ready(); +}); From 33d6acd784eee9c632396841b94694d191095784 Mon Sep 17 00:00:00 2001 From: Vic R <103455651+victorlassomarketing@users.noreply.github.com> Date: Mon, 19 Dec 2022 14:03:34 -0800 Subject: [PATCH 211/367] add encoding for device param (#9352) --- modules/lassoBidAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/lassoBidAdapter.js b/modules/lassoBidAdapter.js index fafaa4dd9dc..ad25cbe1e85 100644 --- a/modules/lassoBidAdapter.js +++ b/modules/lassoBidAdapter.js @@ -40,14 +40,14 @@ export const spec = { auctionId: bidRequest.auctionId, bidId: bidRequest.bidId, transactionId: bidRequest.transactionId, - device: JSON.stringify(getDeviceData()), + device: encodeURIComponent(JSON.stringify(getDeviceData())), sizes, aimXR, uid: '$UID', params: JSON.stringify(bidRequest.params), crumbs: JSON.stringify(bidRequest.crumbs), prebidVersion: '$prebid.version$', - version: 2, + version: 3, coppa: config.getConfig('coppa') == true ? 1 : 0, ccpa: bidderRequest.uspConsent || undefined } From 40450ab7b30fd983356d00c7369acf0c53711380 Mon Sep 17 00:00:00 2001 From: onetag-dev <38786435+onetag-dev@users.noreply.github.com> Date: Tue, 20 Dec 2022 00:11:00 +0100 Subject: [PATCH 212/367] OneTag Bid Adapter: add use of refererInfo Prebid object and Network API (#9306) * OneTag Bid Adapter: add use of refererInfo Prebid object and Network Information API * Replace refererInfo.location with refererInfo.page Co-authored-by: federico --- modules/onetagBidAdapter.js | 49 +++++++++----------- test/spec/modules/onetagBidAdapter_spec.js | 52 ++++++++++++---------- 2 files changed, 49 insertions(+), 52 deletions(-) diff --git a/modules/onetagBidAdapter.js b/modules/onetagBidAdapter.js index 40ef6d596be..b5217e77cd6 100644 --- a/modules/onetagBidAdapter.js +++ b/modules/onetagBidAdapter.js @@ -3,7 +3,7 @@ import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { INSTREAM, OUTSTREAM } from '../src/video.js'; import { Renderer } from '../src/Renderer.js'; -import {find} from '../src/polyfill.js'; +import { find } from '../src/polyfill.js'; import { getStorageManager } from '../src/storageManager.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { deepClone, logError, deepAccess } from '../src/utils.js'; @@ -13,7 +13,7 @@ const USER_SYNC_ENDPOINT = 'https://onetag-sys.com/usync/'; const BIDDER_CODE = 'onetag'; const GVLID = 241; -const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE}); +const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }); /** * Determines whether or not the given bid request is valid. @@ -53,7 +53,7 @@ export function isValid(type, bid) { function buildRequests(validBidRequests, bidderRequest) { const payload = { bids: requestsToBids(validBidRequests), - ...getPageInfo() + ...getPageInfo(bidderRequest) }; if (bidderRequest && bidderRequest.gdprConsent) { payload.gdprConsent = { @@ -74,7 +74,10 @@ function buildRequests(validBidRequests, bidderRequest) { if (storage.hasLocalStorage()) { payload.onetagSid = storage.getDataFromLocalStorage('onetag_sid'); } - } catch (e) {} + } catch (e) { } + const connection = navigator.connection || navigator.webkitConnection; + payload.networkConnectionType = (connection && connection.type) ? connection.type : null; + payload.networkEffectiveConnectionType = (connection && connection.effectiveType) ? connection.effectiveType : null; return { method: 'POST', url: ENDPOINT, @@ -112,7 +115,7 @@ function interpretResponse(serverResponse, bidderRequest) { if (bid.mediaType === BANNER) { responseBid.ad = bid.ad; } else if (bid.mediaType === VIDEO) { - const {context, adUnitCode} = find(requestData.bids, (item) => + const { context, adUnitCode } = find(requestData.bids, (item) => item.bidId === bid.requestId && item.type === VIDEO ); @@ -141,7 +144,7 @@ function createRenderer(bid, rendererOptions = {}) { loaded: false }); try { - renderer.setRender(({renderer, width, height, vastXml, adUnitCode}) => { + renderer.setRender(({ renderer, width, height, vastXml, adUnitCode }) => { renderer.push(() => { window.onetag.Player.init({ ...bid, @@ -162,7 +165,6 @@ function createRenderer(bid, rendererOptions = {}) { function getFrameNesting() { let topmostFrame = window; let parent = window.parent; - let currentFrameNesting = 0; try { while (topmostFrame !== topmostFrame.parent) { parent = topmostFrame.parent; @@ -170,13 +172,8 @@ function getFrameNesting() { parent.location.href; topmostFrame = topmostFrame.parent; } - } catch (e) { - currentFrameNesting = parent === topmostFrame.top ? 1 : 2; - } - return { - topmostFrame, - currentFrameNesting - } + } catch (e) { } + return topmostFrame; } function getDocumentVisibility(window) { @@ -197,21 +194,15 @@ function getDocumentVisibility(window) { /** * Returns information about the page needed by the server in an object to be converted in JSON - * @returns {{location: *, referrer: (*|string), masked: *, wWidth: (*|Number), wHeight: (*|Number), sWidth, sHeight, date: string, timeOffset: number}} + * @returns {{location: *, referrer: (*|string), stack: (*|Array.), numIframes: (*|Number), wWidth: (*|Number), wHeight: (*|Number), sWidth, sHeight, date: string, timeOffset: number}} */ -function getPageInfo() { - const { topmostFrame, currentFrameNesting } = getFrameNesting(); +function getPageInfo(bidderRequest) { + const topmostFrame = getFrameNesting(); return { - location: topmostFrame.location.href, - referrer: - topmostFrame.document.referrer !== '' - ? topmostFrame.document.referrer - : null, - ancestorOrigin: - window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0 - ? window.location.ancestorOrigins[window.location.ancestorOrigins.length - 1] - : null, - masked: currentFrameNesting, + location: deepAccess(bidderRequest, 'refererInfo.page', null), + referrer: deepAccess(bidderRequest, 'refererInfo.ref', null), + stack: deepAccess(bidderRequest, 'refererInfo.stack', []), + numIframes: deepAccess(bidderRequest, 'refererInfo.numIframes', 0), wWidth: topmostFrame.innerWidth, wHeight: topmostFrame.innerHeight, oWidth: topmostFrame.outerWidth, @@ -230,7 +221,7 @@ function getPageInfo() { timing: getTiming(), version: { prebid: '$prebid.version$', - adapter: '1.1.0' + adapter: '1.1.1' } }; } @@ -344,7 +335,7 @@ function getSizes(sizes) { const ret = []; for (let i = 0; i < sizes.length; i++) { const size = sizes[i]; - ret.push({width: size[0], height: size[1]}) + ret.push({ width: size[0], height: size[1] }) } return ret; } diff --git a/test/spec/modules/onetagBidAdapter_spec.js b/test/spec/modules/onetagBidAdapter_spec.js index 2dc0a43bbb0..71e897c7f9e 100644 --- a/test/spec/modules/onetagBidAdapter_spec.js +++ b/test/spec/modules/onetagBidAdapter_spec.js @@ -1,8 +1,8 @@ import { spec, isValid, hasTypeVideo, isSchainValid } from 'modules/onetagBidAdapter.js'; import { expect } from 'chai'; -import {find} from 'src/polyfill.js'; +import { find } from 'src/polyfill.js'; import { BANNER, VIDEO } from 'src/mediaTypes.js'; -import {INSTREAM, OUTSTREAM} from 'src/video.js'; +import { INSTREAM, OUTSTREAM } from 'src/video.js'; describe('onetag', function () { function createBid() { @@ -122,14 +122,14 @@ describe('onetag', function () { it('Should return true when correct multi format bid is passed', function () { expect(spec.isBidRequestValid(createMultiFormatBid())).to.be.true; }); - it('Should split multi format bid into two single format bid with same bidId', function() { - const bids = JSON.parse(spec.buildRequests([ createMultiFormatBid() ]).data).bids; + it('Should split multi format bid into two single format bid with same bidId', function () { + const bids = JSON.parse(spec.buildRequests([createMultiFormatBid()]).data).bids; expect(bids.length).to.equal(2); expect(bids[0].bidId).to.equal(bids[1].bidId); }); - it('Should retrieve correct request bid when extracting video request data', function() { + it('Should retrieve correct request bid when extracting video request data', function () { const requestBid = createMultiFormatBid(); - const multiFormatRequest = spec.buildRequests([ requestBid ]); + const multiFormatRequest = spec.buildRequests([requestBid]); const serverResponse = { body: { bids: [ @@ -173,24 +173,30 @@ describe('onetag', function () { const data = JSON.parse(d); it('Should contain all keys', function () { expect(data).to.be.an('object'); - expect(data).to.include.all.keys('location', 'referrer', 'masked', 'sHeight', 'sWidth', 'docHeight', 'wHeight', 'wWidth', 'oHeight', 'oWidth', 'aWidth', 'aHeight', 'sLeft', 'sTop', 'hLength', 'bids', 'docHidden', 'xOffset', 'yOffset', 'timing', 'version'); - expect(data.location).to.be.a('string'); - expect(data.masked).to.be.oneOf([0, 1, 2]); + expect(data).to.include.all.keys('location', 'referrer', 'stack', 'numIframes', 'sHeight', 'sWidth', 'docHeight', 'wHeight', 'wWidth', 'oHeight', 'oWidth', 'aWidth', 'aHeight', 'sLeft', 'sTop', 'hLength', 'bids', 'docHidden', 'xOffset', 'yOffset', 'networkConnectionType', 'networkEffectiveConnectionType', 'timing', 'version'); + expect(data.location).to.satisfy(function (value) { + return value === null || typeof value === 'string'; + }); expect(data.referrer).to.satisfy(referrer => referrer === null || typeof referrer === 'string'); + expect(data.stack).to.be.an('array'); + expect(data.numIframes).to.be.a('number'); expect(data.sHeight).to.be.a('number'); expect(data.sWidth).to.be.a('number'); expect(data.wWidth).to.be.a('number'); expect(data.wHeight).to.be.a('number'); expect(data.oHeight).to.be.a('number'); expect(data.oWidth).to.be.a('number'); - expect(data.ancestorOrigin).to.satisfy(function (value) { - return value === null || typeof value === 'string'; - }); expect(data.aWidth).to.be.a('number'); expect(data.aHeight).to.be.a('number'); expect(data.sLeft).to.be.a('number'); expect(data.sTop).to.be.a('number'); expect(data.hLength).to.be.a('number'); + expect(data.networkConnectionType).to.satisfy(function (value) { + return value === null || typeof value === 'string' + }); + expect(data.networkEffectiveConnectionType).to.satisfy(function (value) { + return value === null || typeof value === 'string' + }); expect(data.bids).to.be.an('array'); expect(data.version).to.have.all.keys('prebid', 'adapter'); const bids = data['bids']; @@ -231,14 +237,14 @@ describe('onetag', function () { expect(bid.pubId).to.be.a('string'); } }); - } catch (e) {} + } 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) {} + } catch (e) { } }); it('should send GDPR consent data', function () { let consentString = 'consentString'; @@ -287,7 +293,7 @@ describe('onetag', function () { 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); + 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'); @@ -321,7 +327,7 @@ describe('onetag', function () { describe('getUserSyncs', function () { const sync_endpoint = 'https://onetag-sys.com/usync/'; it('Returns an iframe if iframeEnabled is true', function () { - const syncs = spec.getUserSyncs({iframeEnabled: true}); + const syncs = spec.getUserSyncs({ iframeEnabled: true }); expect(syncs).to.be.an('array'); expect(syncs.length).to.equal(1); expect(syncs[0].type).to.equal('iframe'); @@ -383,16 +389,16 @@ describe('onetag', function () { expect(isSchainValid(undefined)).to.be.false; }); it('Should return false when schain is missing nodes key', function () { - const schain = {'otherKey': 'otherValue'}; + const schain = { 'otherKey': 'otherValue' }; expect(isSchainValid(schain)).to.be.false; }); it('Should return false when schain is missing one of the required SupplyChainNode attribute', function () { - const missingAsiNode = {'sid': '00001', 'hp': 1}; - const missingSidNode = {'asi': 'indirectseller.com', 'hp': 1}; - const missingHpNode = {'asi': 'indirectseller.com', 'sid': '00001'}; - expect(isSchainValid({'config': {'nodes': [missingAsiNode]}})).to.be.false; - expect(isSchainValid({'config': {'nodes': [missingSidNode]}})).to.be.false; - expect(isSchainValid({'config': {'nodes': [missingHpNode]}})).to.be.false; + const missingAsiNode = { 'sid': '00001', 'hp': 1 }; + const missingSidNode = { 'asi': 'indirectseller.com', 'hp': 1 }; + const missingHpNode = { 'asi': 'indirectseller.com', 'sid': '00001' }; + expect(isSchainValid({ 'config': { 'nodes': [missingAsiNode] } })).to.be.false; + expect(isSchainValid({ 'config': { 'nodes': [missingSidNode] } })).to.be.false; + expect(isSchainValid({ 'config': { 'nodes': [missingHpNode] } })).to.be.false; }); it('Should return true when schain contains all required attributes', function () { const validSchain = { From c56d78a2cca3ef46a2cb7a33fec40b35545d8b0a Mon Sep 17 00:00:00 2001 From: TheMediaGrid <44166371+TheMediaGrid@users.noreply.github.com> Date: Tue, 20 Dec 2022 16:11:56 +0300 Subject: [PATCH 213/367] TheMediaGrid: fix tmax value (#9339) --- modules/gridBidAdapter.js | 3 +-- test/spec/modules/gridBidAdapter_spec.js | 18 ------------------ 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index b300c5c58c0..aa6c0ab668f 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -94,8 +94,7 @@ export const spec = { let {bidderRequestId, auctionId, gdprConsent, uspConsent, timeout, refererInfo} = bidderRequest || {}; const referer = refererInfo ? encodeURIComponent(refererInfo.page) : ''; - const bidderTimeout = config.getConfig('bidderTimeout') || timeout; - const tmax = timeout ? Math.min(bidderTimeout, timeout) : bidderTimeout; + const tmax = timeout || config.getConfig('bidderTimeout'); const imp = []; const bidsMap = {}; const requests = []; diff --git a/test/spec/modules/gridBidAdapter_spec.js b/test/spec/modules/gridBidAdapter_spec.js index 4b93c287fee..d411f33ab50 100644 --- a/test/spec/modules/gridBidAdapter_spec.js +++ b/test/spec/modules/gridBidAdapter_spec.js @@ -840,24 +840,6 @@ describe('TheMediaGrid Adapter', function () { expect(payload.site.content.id).to.equal(contentId); }); - it('should be right tmax when timeout in config is less then timeout in bidderRequest', function() { - const getConfigStub = sinon.stub(config, 'getConfig').callsFake( - arg => arg === 'bidderTimeout' ? 2000 : null); - const [request] = spec.buildRequests([bidRequests[0]], bidderRequest); - expect(request.data).to.be.an('string'); - const payload = parseRequest(request.data); - expect(payload.tmax).to.equal(2000); - getConfigStub.restore(); - }); - it('should be right tmax when timeout in bidderRequest is less then timeout in config', function() { - const getConfigStub = sinon.stub(config, 'getConfig').callsFake( - arg => arg === 'bidderTimeout' ? 5000 : null); - const [request] = spec.buildRequests([bidRequests[0]], bidderRequest); - expect(request.data).to.be.an('string'); - const payload = parseRequest(request.data); - expect(payload.tmax).to.equal(3000); - getConfigStub.restore(); - }); it('should contain regs.coppa if coppa is true in config', function () { const getConfigStub = sinon.stub(config, 'getConfig').callsFake( arg => arg === 'coppa' ? true : null); From 5950984cf2aebdc1ea0f18c14ee057ddd79f1df7 Mon Sep 17 00:00:00 2001 From: geoffray-viously <95097046+geoffray-viously@users.noreply.github.com> Date: Wed, 21 Dec 2022 06:32:14 +0100 Subject: [PATCH 214/367] Viously Bid Adapter : New Adapter (#9076) * Add viously Bid Adapter * Mod: viously documentation * MR fixes --- modules/viouslyBidAdapter.js | 209 +++++++++++ modules/viouslyBidAdapter.md | 35 ++ test/spec/modules/ViouslyBidAdapter_spec.js | 378 ++++++++++++++++++++ 3 files changed, 622 insertions(+) create mode 100644 modules/viouslyBidAdapter.js create mode 100644 modules/viouslyBidAdapter.md create mode 100644 test/spec/modules/ViouslyBidAdapter_spec.js diff --git a/modules/viouslyBidAdapter.js b/modules/viouslyBidAdapter.js new file mode 100644 index 00000000000..f18c9c7b3db --- /dev/null +++ b/modules/viouslyBidAdapter.js @@ -0,0 +1,209 @@ +import { deepAccess, logError, parseUrl, parseSizesInput, triggerPixel } from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { VIDEO } from '../src/mediaTypes.js'; +import find from 'core-js-pure/features/array/find.js'; // eslint-disable-line prebid/validate-imports + +const BIDDER_CODE = 'viously'; +// const GVLID = 1028; +const CURRENCY = 'EUR'; +const TTL = 60; +const HTTP_METHOD = 'POST'; +const REQUEST_URL = 'https://bidder.viously.com/bid'; +const REQUIRED_VIDEO_PARAMS = ['context', 'playbackmethod', 'playerSize']; +const REQUIRED_VIOUSLY_PARAMS = ['pid']; + +export const spec = { + code: BIDDER_CODE, + // gvlid: GVLID, + 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 videoParams = deepAccess(bid, 'mediaTypes.video'); + + if (!bid.params) { + logError('The bid params are missing'); + return false; + } + + if (!videoParams) { + logError('The placement must be of video type'); + return false; + } + + /** + * VIDEO checks + */ + + let areParamsValid = true; + + REQUIRED_VIDEO_PARAMS.forEach(function(videoParam) { + if (typeof videoParams[videoParam] === 'undefined') { + logError('mediaTypes.video.' + videoParam + ' must be set for video placement.'); + areParamsValid = false; + } + }); + + if (parseSizesInput(videoParams.playerSize).length === 0) { + logError('mediaTypes.video.playerSize must be set for video placement at the right format.'); + return false; + } + + /** + * Viously checks + */ + + REQUIRED_VIOUSLY_PARAMS.forEach(function(viouslyParam) { + if (typeof bid.params[viouslyParam] === 'undefined') { + logError('The ' + viouslyParam + ' is missing.'); + areParamsValid = false; + } + }); + + if (!areParamsValid) { + return false; + } + + return true; + }, + + buildRequests: function(validBidRequests, bidderRequest) { + let payload = {}; + + /** Viously Publisher ID */ + if (validBidRequests[0].params.pid) { + payload.pid = validBidRequests[0].params.pid; + } + + // Referer Info + if (config.getConfig('pageUrl')) { + let parsedUrl = parseUrl(config.getConfig('pageUrl')); + + payload.domain = parsedUrl.hostname; + payload.page_domain = config.getConfig('pageUrl'); + } else if (bidderRequest && bidderRequest.refererInfo) { + let parsedUrl = parseUrl(bidderRequest.refererInfo.page); + + payload.domain = parsedUrl.hostname; + payload.page_domain = bidderRequest.refererInfo.page; + } + if (payload.domain) { + /** Make sur that the scheme is not part of the domain */ + payload.domain = payload.domain.replace(/(^\w+:|^)\/\//, ''); + payload.domain = payload.domain.replace(/\/$/, ''); + } + + // Handle GDPR + if (bidderRequest && bidderRequest.gdprConsent) { + payload.gdpr = bidderRequest.gdprConsent.gdprApplies; + payload.gdpr_consent = bidderRequest.gdprConsent.consentString; + if (bidderRequest.gdprConsent.addtlConsent && bidderRequest.gdprConsent.addtlConsent.indexOf('~') !== -1) { + payload.addtl_consent = bidderRequest.gdprConsent.addtlConsent; + } + } + + // US Privacy + if (bidderRequest && bidderRequest.uspConsent) { + payload.us_privacy = bidderRequest.uspConsent; + } + + // Schain + if (validBidRequests[0].schain) { + payload.schain = validBidRequests[0].schain; + } + // Currency + payload.currency_code = CURRENCY; + + // User IDs + if (validBidRequests[0].userIdAsEids) { + payload.users_uid = validBidRequests[0].userIdAsEids; + } + + // Placements + payload.placements = validBidRequests.map(bidRequest => { + let request = { + id: bidRequest.adUnitCode, + bid_id: bidRequest.bidId + }; + + request.video_params = { + context: deepAccess(bidRequest, 'mediaTypes.video.context'), + playbackmethod: deepAccess(bidRequest, 'mediaTypes.video.playbackmethod'), + size: parseSizesInput(deepAccess(bidRequest, 'mediaTypes.video.playerSize')) + }; + + return request; + }); + + return { + method: HTTP_METHOD, + url: validBidRequests[0].params.endpoint ? validBidRequests[0].params.endpoint : REQUEST_URL, + data: payload + }; + }, + + interpretResponse: function(serverResponse, requests) { + const bidResponses = []; + const responseBody = serverResponse.body; + + if (responseBody.ads && responseBody.ads.length > 0) { + responseBody.ads.forEach(function(bidResponse) { + if (bidResponse.bid) { + let bidRequest = find(requests.data.placements, bid => bid.bid_id === bidResponse.bid_id); + + if (bidRequest) { + let sizes = bidResponse.size.split('x'); + + const bid = { + requestId: bidRequest.bid_id, + id: bidResponse.id, + cpm: bidResponse.cpm, + width: sizes[0], + height: sizes[1], + creativeId: bidResponse.creative_id || '', + currency: CURRENCY, + netRevenue: true, + ttl: TTL, + mediaType: 'video', + meta: {}, + // Tracking data + nurl: bidResponse.nurl ? bidResponse.nurl : [] + }; + + if (bidResponse.ad_url) { + bid.vastUrl = bidResponse.ad_url; + } else { + bid.vastXml = bidResponse.ad; + } + + bidResponses.push(bid); + } + } + }); + } + + return bidResponses; + }, + + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {}, + + onTimeout: function(timeoutData) {}, + + onBidWon: function(bid) { + if (bid && bid.nurl && bid.nurl.length > 0) { + bid.nurl.forEach(function(winUrl) { + triggerPixel(winUrl, null); + }); + } + }, + + onSetTargeting: function(bid) {} +}; + +registerBidder(spec); diff --git a/modules/viouslyBidAdapter.md b/modules/viouslyBidAdapter.md new file mode 100644 index 00000000000..0d15525cc72 --- /dev/null +++ b/modules/viouslyBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +``` +Module Name: Viously Bidder Adapter +Module Type: Bidder Adapter +Maintainer: prebid@viously.com +``` + +# Description + +Module that connects to Viously's demand sources + +# Test Parameters +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + video: { + playerSize: [640, 360], + context: 'instream', + playbackmethod: [1, 2, 3, 4, 5, 6] + } + }, + bids: [ + { + bidder: 'viously', + params: { + pid: '20d30b78-43ec-11ed-b878-0242ac120002' + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/test/spec/modules/ViouslyBidAdapter_spec.js b/test/spec/modules/ViouslyBidAdapter_spec.js new file mode 100644 index 00000000000..612c5f87138 --- /dev/null +++ b/test/spec/modules/ViouslyBidAdapter_spec.js @@ -0,0 +1,378 @@ +import {expect} from 'chai'; + +import { deepClone, mergeDeep } from 'src/utils'; +import { createEidsArray } from 'modules/userId/eids.js'; + +import {spec as adapter} from 'modules/viouslyBidAdapter'; + +import sinon from 'sinon'; +import { config } from 'src/config.js'; + +const CURRENCY = 'EUR'; +const TTL = 60; +const HTTP_METHOD = 'POST'; +const REQUEST_URL = 'https://bidder.viously.com/bid'; + +const VALID_BID_VIDEO = { + bidder: 'viously', + bidId: '5e6f7g8h', + adUnitCode: 'id-5678', + params: { + pid: '123e4567-e89b-12d3-a456-426614174001' + }, + mediaTypes: { + video: { + playerSize: [640, 360], + context: 'instream', + playbackmethod: [1, 2, 3, 4] + } + } +}; + +const VALID_REQUEST_VIDEO = { + method: HTTP_METHOD, + url: REQUEST_URL, + data: { + pid: '123e4567-e89b-12d3-a456-426614174001', + currency_code: CURRENCY, + placements: [ + { + id: 'id-5678', + bid_id: '5e6f7g8h', + video_params: { + context: 'instream', + playbackmethod: [1, 2, 3, 4], + size: ['640x360'] + } + } + ] + } +}; + +const VALID_GDPR = { + gdprApplies: true, + apiVersion: 2, + consentString: 'abcdefgh', + addtlConsent: '1~12345678', + vendorData: { + purpose: { + consents: { + 1: true + } + } + } +}; +const US_PRIVACY = '1YNN'; + +describe('ViouslyAdapter', function () { + describe('isBidRequestValid', function () { + describe('Check method return', function () { + it('should return true', function () { + expect(adapter.isBidRequestValid(VALID_BID_VIDEO)).to.equal(true); + }); + + it('should return false because the pid is missing', function () { + let wrongBid = deepClone(VALID_BID_VIDEO); + delete wrongBid.params.pid; + + expect(adapter.isBidRequestValid(wrongBid)).to.equal(false); + }); + + it('should return false because the video context parameter is missing', function () { + let wrongBid = deepClone(VALID_BID_VIDEO); + + delete wrongBid.mediaTypes.video.context; + expect(adapter.isBidRequestValid(wrongBid)).to.equal(false); + }); + }); + }); + + describe('buildRequests', function () { + describe('Check method return', function () { + it('should return the right formatted video requests', function() { + expect(adapter.buildRequests([VALID_BID_VIDEO])).to.deep.equal(VALID_REQUEST_VIDEO); + }); + + it('should return the right formatted request with the referer info', function() { + let bidderRequest = { + refererInfo: { + page: 'https://www.example.com/test' + } + }; + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + domain: 'www.example.com', + page_domain: 'https://www.example.com/test' + } + }); + + expect(adapter.buildRequests([VALID_BID_VIDEO], bidderRequest)).to.deep.equal(requests); + }); + + it('should return the right formatted request with the referer info from config', function() { + /** Mock the config.getConfig method */ + sinon.stub(config, 'getConfig') + .withArgs('pageUrl') + .returns('https://www.example.com/page'); + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + domain: 'www.example.com', + page_domain: 'https://www.example.com/page' + } + }); + + expect(adapter.buildRequests([VALID_BID_VIDEO])).to.deep.equal(requests); + + config.getConfig.restore(); + }); + + it('should return the right formatted request with GDPR Consent info', function() { + let bidderRequest = { + gdprConsent: VALID_GDPR + }; + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + gdpr: true, + gdpr_consent: 'abcdefgh', + addtl_consent: '1~12345678' + } + }); + + expect(adapter.buildRequests([VALID_BID_VIDEO], bidderRequest)).to.deep.equal(requests); + }); + + it('should return the right formatted request with US Privacy info', function() { + let bidderRequest = { + uspConsent: US_PRIVACY + }; + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + us_privacy: US_PRIVACY + } + }); + + expect(adapter.buildRequests([VALID_BID_VIDEO], bidderRequest)).to.deep.equal(requests); + }); + + // TODO: Supply chain + it('should return the right formatted request with Supply Chain info', function() { + let schain = { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'test1.com', + 'sid': '00001', + 'hp': 1 + }, + { + 'asi': 'test2-2.com', + 'sid': '00002', + 'hp': 2 + } + ] + }; + + let bid = mergeDeep(deepClone(VALID_BID_VIDEO), { + schain: schain + }); + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + schain: schain + } + }); + + expect(adapter.buildRequests([bid])).to.deep.equal(requests); + }); + + it('should return the right formatted request with User Ids info', function() { + let userIds = { + idl_env: '1234-5678-9012-3456', // Liveramp + netId: 'testnetid123', // NetId + IDP: 'userIDP000', // IDP + fabrickId: 'fabrickId9000', // FabrickId + uid2: { id: 'testuid2' } // UID 2.0 + }; + + let bid = mergeDeep(deepClone(VALID_BID_VIDEO), { + userIds: userIds + }, { + userIdAsEids: createEidsArray(userIds) + }); + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO), { + data: { + users_uid: createEidsArray(userIds) + } + }); + + expect(adapter.buildRequests([bid])).to.deep.equal(requests); + }); + + it('should return the right formatted request with endpint test', function() { + let endpoint = 'https://bid-test.viously.com/prebid'; + + let bid = mergeDeep(deepClone(VALID_BID_VIDEO), { + params: { + endpoint: endpoint + } + }); + + let requests = mergeDeep(deepClone(VALID_REQUEST_VIDEO)); + + requests.url = endpoint; + + expect(adapter.buildRequests([bid])).to.deep.equal(requests); + }); + + // TODO: Floor + }); + }); + + describe('interpretResponse', function() { + describe('Check method return', function () { + it('should return the right formatted response', function() { + let response = { + body: { + ads: [ + { + bid: false, + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-0', + bid_id: '1234' + }, + { + bid: true, + creative_id: '2468', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-1', + bid_id: '5678', + cpm: 8, + ad: 'vast xml', + ad_url: 'http://www.example.com/vast', + type: 'video', + size: '640x480', + nurl: [ + 'win.domain.com' + ] + }, + { + bid: true, + creative_id: '1469', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-3', + bid_id: '2570', + cpm: 4, + ad: 'vast xml', + type: 'video', + size: '640x480', + } + ] + } + }; + let requests = { + data: { + placements: [ + { + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-0', + bid_id: '1234' + }, + { + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-1', + bid_id: '5678' + }, + { + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-3', + bid_id: '2570' + } + ] + } + }; + + let formattedReponse = [ + { + requestId: '5678', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-1', + cpm: 8, + width: '640', + height: '480', + creativeId: '2468', + currency: CURRENCY, + netRevenue: true, + ttl: TTL, + mediaType: 'video', + meta: {}, + vastUrl: 'http://www.example.com/vast', + nurl: [ + 'win.domain.com' + ] + }, + { + requestId: '2570', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-3', + cpm: 4, + width: '640', + height: '480', + creativeId: '1469', + currency: CURRENCY, + netRevenue: true, + ttl: TTL, + mediaType: 'video', + meta: {}, + vastXml: 'vast xml', + nurl: [] + } + ]; + + expect(adapter.interpretResponse(response, requests)).to.deep.equal(formattedReponse); + }); + }); + }); + + describe('onBidWon', function() { + describe('Check methods succeed', function () { + it('should not throw error', function() { + let bids = [ + { + requestId: '5678', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-1', + cpm: 8, + width: '640', + height: '480', + creativeId: '2468', + currency: CURRENCY, + netRevenue: true, + ttl: TTL, + mediaType: 'video', + meta: {}, + vastUrl: 'http://www.example.com/vast', + nurl: [ + 'win.domain.com' + ] + }, + { + requestId: '2570', + id: 'id-0157324f-bee4-5390-a14c-47a7da3eb73c-3', + cpm: 4, + width: '640', + height: '480', + creativeId: '1469', + currency: CURRENCY, + netRevenue: true, + ttl: TTL, + mediaType: 'video', + meta: {}, + vastXml: 'vast xml', + nurl: [] + } + ]; + + bids.forEach(function(bid) { + expect(adapter.onBidWon.bind(adapter, bid)).to.not.throw(); + }); + }); + }); + }); +}); From 681e2c7fa81fca27f39df81c56f8d162e1815fd2 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 20 Dec 2022 23:09:19 -0700 Subject: [PATCH 215/367] Topics FPD module: fix tests (#9354) --- test/spec/modules/topicsFpdModule_spec.js | 63 +++++++++++++++-------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/test/spec/modules/topicsFpdModule_spec.js b/test/spec/modules/topicsFpdModule_spec.js index 69e7cc16ca8..958489f2728 100644 --- a/test/spec/modules/topicsFpdModule_spec.js +++ b/test/spec/modules/topicsFpdModule_spec.js @@ -1,4 +1,12 @@ -import {getTopics, getTopicsData, processFpd, hasGDPRConsent, getCachedTopics, receiveMessage, topicStorageName} from '../../../modules/topicsFpdModule.js'; +import { + getTopics, + getTopicsData, + processFpd, + hasGDPRConsent, + getCachedTopics, + receiveMessage, + topicStorageName +} from '../../../modules/topicsFpdModule.js'; import {deepClone, safeJSONParse} from '../../../src/utils.js'; import {gdprDataHandler} from 'src/adapterManager.js'; import {getCoreStorageManager} from 'src/storageManager.js'; @@ -9,14 +17,14 @@ describe('getTopicsData', () => { topic, taxonomyVersion: taxv, modelVersion: modelv - } + }; } function byTaxClass(segments) { return segments.reduce((memo, segment) => { memo[`${segment.ext.segtax}:${segment.ext.segclass}`] = segment; return memo; - }, {}) + }, {}); } [ @@ -146,16 +154,16 @@ describe('getTopicsData', () => { Object.entries(byTaxClass(actual)).forEach(([key, datum]) => { sinon.assert.match(datum, expected[key]); expect(datum.name).to.equal('mockName'); - }) + }); }); it('should not set name if null', () => { getTopicsData(null, topics).forEach((data) => { expect(data.hasOwnProperty('name')).to.be.false; - }) - }) - }) - }) + }); + }); + }); + }); }); describe('getTopics', () => { @@ -169,11 +177,13 @@ describe('getTopics', () => { 'document that throws on featurePolicy': { browsingTopics: sinon.stub(), get featurePolicy() { - throw new Error() + throw new Error(); } }, 'document that throws on browsingTopics': { - browsingTopics: sinon.stub().callsFake(() => { throw new Error(); }), + browsingTopics: sinon.stub().callsFake(() => { + throw new Error(); + }), featurePolicy: { allowsFeature: sinon.stub().returns(true) } @@ -183,11 +193,11 @@ describe('getTopics', () => { return getTopics(doc).then((topics) => { expect(topics).to.eql([]); }); - }) + }); }); it('should call `document.browsingTopics` when allowed', () => { - const topics = ['t1', 't2'] + const topics = ['t1', 't2']; return getTopics({ browsingTopics: sinon.stub().returns(Promise.resolve(topics)), featurePolicy: { @@ -195,9 +205,9 @@ describe('getTopics', () => { } }).then((actual) => { expect(actual).to.eql(topics); - }) - }) -}) + }); + }); +}); describe('processFpd', () => { const mockData = [ @@ -244,7 +254,7 @@ describe('Topics Module GDPR consent check', () => { let gdprDataHdlrStub; beforeEach(() => { gdprDataHdlrStub = sinon.stub(gdprDataHandler, 'getConsentData'); - }) + }); afterEach(() => { gdprDataHdlrStub.restore(); @@ -261,7 +271,7 @@ describe('Topics Module GDPR consent check', () => { expect(hasGDPRConsent()).to.equal(false); }); - it("should return true when GDPR doesn't apply", () => { + it('should return true when GDPR doesn\'t apply', () => { const consentString = 'CPi8wgAPi8wgAADABBENCrCsAP_AAH_AAAAAISNB7D=='; const consentConfig = { consentString: consentString, @@ -365,7 +375,7 @@ describe('getCachedTopics()', () => { const evt = { data: '{"segment":{"domain":"ads.pubmatic.com","topics":[{"configVersion":"chrome.1","modelVersion":"2206021246","taxonomyVersion":"1","topic":165,"version":"chrome.1:1:2206021246"}],"bidder":"pubmatic"},"date":1669743901858}', origin: 'https://ads.pubmatic.com' - } + }; let gdprDataHdlrStub; beforeEach(() => { @@ -378,14 +388,23 @@ describe('getCachedTopics()', () => { }); it('should return segments for bidder if GDPR consent is true and there is cached segments stored which is not expired', () => { - let storedSegments = '[["pubmatic",{"2206021246":{"ext":{"segtax":600,"segclass":"2206021246"},"segment":[{"id":"243"},{"id":"265"}],"name":"ads.pubmatic.com"},"lastUpdated":1669719242027}]]'; + const storedSegments = JSON.stringify( + [['pubmatic', { + '2206021246': { + 'ext': {'segtax': 600, 'segclass': '2206021246'}, + 'segment': [{'id': '243'}, {'id': '265'}], + 'name': 'ads.pubmatic.com' + }, + 'lastUpdated': new Date().getTime() + }]] + ); storage.setDataInLocalStorage(topicStorageName, storedSegments); gdprDataHdlrStub.returns(consentConfig); assert.deepEqual(getCachedTopics(), expected); }); it('should return empty segments for bidder if GDPR consent is true and there is cached segments stored which is expired', () => { - let storedSegments = '[["pubmatic",{"2206021246":{"ext":{"segtax":600,"segclass":"2206021246"},"segment":[{"id":"243"},{"id":"265"}],"name":"ads.pubmatic.com"},"lastUpdated":1659719242027}]]'; + let storedSegments = '[["pubmatic",{"2206021246":{"ext":{"segtax":600,"segclass":"2206021246"},"segment":[{"id":"243"},{"id":"265"}],"name":"ads.pubmatic.com"},"lastUpdated":10}]]'; storage.setDataInLocalStorage(topicStorageName, storedSegments); gdprDataHdlrStub.returns(consentConfig); assert.deepEqual(getCachedTopics(), []); @@ -394,7 +413,7 @@ describe('getCachedTopics()', () => { it('should stored segments if receiveMessage event is triggerred with segment data', () => { return processFpd({}, {global: {}}, {data: Promise.resolve(mockData)}) .then(({global}) => { - receiveMessage(evt) + receiveMessage(evt); let segments = new Map(safeJSONParse(storage.getDataFromLocalStorage(topicStorageName))); expect(segments.has('pubmatic')).to.equal(true); }); @@ -410,4 +429,4 @@ describe('getCachedTopics()', () => { expect(segments.get('pubmatic')[2206021246].segment.length).to.equal(1); }); }); -}) +}); From 77647180e5fc3c8058adcf5d642499ad3146b495 Mon Sep 17 00:00:00 2001 From: mjaworskiccx <50406214+mjaworskiccx@users.noreply.github.com> Date: Wed, 21 Dec 2022 16:39:56 +0100 Subject: [PATCH 216/367] Ccx Bid Adapter: Add GVLID param (#9359) * adomain support * adomain support * adomain support * adomain support * adomain support * video params * docs changes * Clickonometrics adapter update * Revert "Revert "Clickonometrics Bid Adapter : add gvlid (#9198)" (#9216)" This reverts commit 6d114e83725b403fadd889202b449de225db7275. --- modules/ccxBidAdapter.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/ccxBidAdapter.js b/modules/ccxBidAdapter.js index 7c6b0411023..efdb8992669 100644 --- a/modules/ccxBidAdapter.js +++ b/modules/ccxBidAdapter.js @@ -5,6 +5,7 @@ import {getStorageManager} from '../src/storageManager.js'; const BIDDER_CODE = 'ccx' const storage = getStorageManager({bidderCode: BIDDER_CODE}); const BID_URL = 'https://delivery.clickonometrics.pl/ortb/prebid/bid' +const GVLID = 773; const SUPPORTED_VIDEO_PROTOCOLS = [2, 3, 5, 6] const SUPPORTED_VIDEO_MIMES = ['video/mp4', 'video/x-flv'] const SUPPORTED_VIDEO_PLAYBACK_METHODS = [1, 2, 3, 4] @@ -19,8 +20,7 @@ function _getDeviceObj () { function _getSiteObj (bidderRequest) { let site = {} - // TODO: does the fallback to window.location make sense? - let url = bidderRequest?.refererInfo?.page || window.location.href + let url = bidderRequest?.refererInfo?.page if (url.length > 0) { url = url.split('?')[0] } @@ -140,6 +140,7 @@ function _buildResponse (bid, currency, ttl) { export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: ['banner', 'video'], isBidRequestValid: function (bid) { From 51c984e7088a7bdf13da4c36c988938711f0089a Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Wed, 21 Dec 2022 11:52:06 -0500 Subject: [PATCH 217/367] Revert "Ccx Bid Adapter: Add GVLID param (#9359)" (#9363) This reverts commit 77647180e5fc3c8058adcf5d642499ad3146b495. Co-authored-by: Demetrio Girardi --- modules/ccxBidAdapter.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/ccxBidAdapter.js b/modules/ccxBidAdapter.js index efdb8992669..7c6b0411023 100644 --- a/modules/ccxBidAdapter.js +++ b/modules/ccxBidAdapter.js @@ -5,7 +5,6 @@ import {getStorageManager} from '../src/storageManager.js'; const BIDDER_CODE = 'ccx' const storage = getStorageManager({bidderCode: BIDDER_CODE}); const BID_URL = 'https://delivery.clickonometrics.pl/ortb/prebid/bid' -const GVLID = 773; const SUPPORTED_VIDEO_PROTOCOLS = [2, 3, 5, 6] const SUPPORTED_VIDEO_MIMES = ['video/mp4', 'video/x-flv'] const SUPPORTED_VIDEO_PLAYBACK_METHODS = [1, 2, 3, 4] @@ -20,7 +19,8 @@ function _getDeviceObj () { function _getSiteObj (bidderRequest) { let site = {} - let url = bidderRequest?.refererInfo?.page + // TODO: does the fallback to window.location make sense? + let url = bidderRequest?.refererInfo?.page || window.location.href if (url.length > 0) { url = url.split('?')[0] } @@ -140,7 +140,6 @@ function _buildResponse (bid, currency, ttl) { export const spec = { code: BIDDER_CODE, - gvlid: GVLID, supportedMediaTypes: ['banner', 'video'], isBidRequestValid: function (bid) { From e2cfc185345b5f552d18d50cba8c880b4a9ecae7 Mon Sep 17 00:00:00 2001 From: jsnellbaker <31102355+jsnellbaker@users.noreply.github.com> Date: Wed, 21 Dec 2022 12:33:22 -0500 Subject: [PATCH 218/367] GPP consent module: phase one release (#9321) * GPP consent module phase 1 * various updates and added test pages * revise calling CMP, remove provisionalConsent, remove cmpDisplayStatus check, update pbs usersync * change callback check to be more strict * update logic on adding gpp data to ortb2 * update gpp metadata --- .../gpt/gpp_us_hello_world.html | 124 ++++ .../gpt/gpp_us_hello_world_iframe.html | 12 + .../gpp_us_hello_world_iframe_subpage.html | 140 +++++ modules/appnexusBidAdapter.js | 25 +- modules/bidViewability.js | 7 +- modules/consentManagement.js | 8 +- modules/consentManagementGpp.js | 386 ++++++++++++ modules/dfpAdServerVideo.js | 7 +- modules/prebidServerBidAdapter/index.js | 27 +- modules/rtdModule/index.js | 3 +- src/adapterManager.js | 21 +- src/adapters/bidderFactory.js | 10 +- src/consentHandler.js | 11 + src/prebid.js | 3 +- test/spec/modules/appnexusBidAdapter_spec.js | 46 ++ .../spec/modules/consentManagementGpp_spec.js | 577 ++++++++++++++++++ 16 files changed, 1374 insertions(+), 33 deletions(-) create mode 100644 integrationExamples/gpt/gpp_us_hello_world.html create mode 100644 integrationExamples/gpt/gpp_us_hello_world_iframe.html create mode 100644 integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html create mode 100644 modules/consentManagementGpp.js create mode 100644 test/spec/modules/consentManagementGpp_spec.js diff --git a/integrationExamples/gpt/gpp_us_hello_world.html b/integrationExamples/gpt/gpp_us_hello_world.html new file mode 100644 index 00000000000..28be86127fc --- /dev/null +++ b/integrationExamples/gpt/gpp_us_hello_world.html @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+ +
+ +
+ + + \ No newline at end of file diff --git a/integrationExamples/gpt/gpp_us_hello_world_iframe.html b/integrationExamples/gpt/gpp_us_hello_world_iframe.html new file mode 100644 index 00000000000..c0a62f9d72e --- /dev/null +++ b/integrationExamples/gpt/gpp_us_hello_world_iframe.html @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html b/integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html new file mode 100644 index 00000000000..8c2096d614d --- /dev/null +++ b/integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+ +
+ +
+ + + \ No newline at end of file diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index 77ffe0f6b94..919831b8515 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -304,6 +304,18 @@ export const spec = { payload.us_privacy = bidderRequest.uspConsent; } + if (bidderRequest?.gppConsent) { + payload.privacy = { + gpp: bidderRequest.gppConsent.gppString, + gpp_sid: bidderRequest.gppConsent.applicableSections + } + } else if (bidderRequest?.ortb2?.regs?.gpp) { + payload.privacy = { + gpp: bidderRequest.ortb2.regs.gpp, + gpp_sid: bidderRequest.ortb2.regs.gpp_sid + } + } + if (bidderRequest && bidderRequest.refererInfo) { let refererinfo = { // TODO: are these the correct referer values? @@ -424,8 +436,17 @@ export const spec = { } }, - getUserSyncs: function (syncOptions, responses, gdprConsent) { - if (syncOptions.iframeEnabled && hasPurpose1Consent(gdprConsent)) { + getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent, gppConsent) { + function checkGppStatus(gppConsent) { + // this is a temporary measure to supress usersync in US-based GPP regions + // this logic will be revised when proper signals (akin to purpose1 from TCF2) can be determined for US GPP + if (gppConsent && Array.isArray(gppConsent.applicableSections)) { + return gppConsent.applicableSections.every(sec => typeof sec === 'number' && sec <= 5); + } + return true; + } + + if (syncOptions.iframeEnabled && hasPurpose1Consent(gdprConsent) && checkGppStatus(gppConsent)) { return [{ type: 'iframe', url: 'https://acdn.adnxs.com/dmp/async_usersync.html' diff --git a/modules/bidViewability.js b/modules/bidViewability.js index 362401e6d1c..a5cab99b1a7 100644 --- a/modules/bidViewability.js +++ b/modules/bidViewability.js @@ -7,7 +7,7 @@ import * as events from '../src/events.js'; import CONSTANTS from '../src/constants.json'; import {isFn, logWarn, triggerPixel} from '../src/utils.js'; import {getGlobal} from '../src/prebidGlobal.js'; -import adapterManager, {gdprDataHandler, uspDataHandler} from '../src/adapterManager.js'; +import adapterManager, {gdprDataHandler, uspDataHandler, gppDataHandler} from '../src/adapterManager.js'; import {find} from '../src/polyfill.js'; const MODULE_NAME = 'bidViewability'; @@ -44,6 +44,11 @@ export let fireViewabilityPixels = (globalModuleConfig, bid) => { const uspConsent = uspDataHandler.getConsentData(); if (uspConsent) { queryParams.us_privacy = uspConsent; } + const gppConsent = gppDataHandler.getConsentData(); + if (gppConsent) { + // TODO - need to know what to set here for queryParams... + } + bid[BID_VURL_ARRAY].forEach(url => { // add '?' if not present in URL if (Object.keys(queryParams).length > 0 && url.indexOf('?') === -1) { diff --git a/modules/consentManagement.js b/modules/consentManagement.js index 6ca12010c74..217ceecb1c4 100644 --- a/modules/consentManagement.js +++ b/modules/consentManagement.js @@ -94,7 +94,7 @@ function lookupIabConsent({onSuccess, onError}) { const { cmpFrame, cmpFunction } = findCMP(); if (!cmpFrame) { - return onError('CMP not found.'); + return onError('TCF2 CMP not found.'); } // 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) @@ -314,11 +314,11 @@ export function resetConsentData() { * @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. + // if `config.gdpr`, `config.usp` or `config.gpp` exist, assume new config format. // else for backward compatability, just use `config` - config = config && (config.gdpr || config.usp ? config.gdpr : config); + config = config && (config.gdpr || config.usp || config.gpp ? config.gdpr : config); if (!config || typeof config !== 'object') { - logWarn('consentManagement config not defined, exiting consent manager'); + logWarn('consentManagement (gdpr) config not defined, exiting consent manager'); return; } if (isStr(config.cmpApi)) { diff --git a/modules/consentManagementGpp.js b/modules/consentManagementGpp.js new file mode 100644 index 00000000000..8a9c3f999f0 --- /dev/null +++ b/modules/consentManagementGpp.js @@ -0,0 +1,386 @@ +/** + * This module adds GPP consentManagement support to prebid.js. It interacts with + * supported CMPs (Consent Management Platforms) to grab the user's consent information + * and make it available for any GPP supported adapters to read/pass this information to + * their system and for various other features/modules in Prebid.js. + */ +import {deepSetValue, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js'; +import {config} from '../src/config.js'; +import {gppDataHandler} from '../src/adapterManager.js'; +import {includes} from '../src/polyfill.js'; +import {timedAuctionHook} from '../src/utils/perfMetrics.js'; +import { enrichFPD } from '../src/fpd/enrichment.js'; + +const DEFAULT_CMP = 'iab'; +const DEFAULT_CONSENT_TIMEOUT = 10000; +const CMP_VERSION = 1; + +export let userCMP; +export let consentTimeout; +export let staticConsentData; + +let consentData; +let addedConsentHook = false; + +// add new CMPs here, with their dedicated lookup function +const cmpCallMap = { + 'iab': lookupIabConsent, + 'static': lookupStaticConsentData +}; + +/** + * This function checks the state of the IAB gppData's applicableSection field (to ensure it's populated and has a valid value). + * section === 0 represents a CMP's default value when CMP is loading, it shoud not be used a real user's section. + * + * TODO --- The initial version of the GPP CMP API spec used this naming convention, but it was later changed as an update to the spec. + * CMPs should adjust their logic to use the new format (applicableSecctions), but that may not be the case with the initial release. + * Added support just in case for this transition period, can likely be removed at a later date... + * @param gppData represents the IAB gppData object + * @returns true|false + */ +function checkApplicableSectionIsReady(gppData) { + return gppData && Array.isArray(gppData.applicableSection) && gppData.applicableSection.length > 0 && gppData.applicableSection[0] !== 0; +} + +/** + * This function checks the state of the IAB gppData's applicableSections field (to ensure it's populated and has a valid value). + * section === 0 represents a CMP's default value when CMP is loading, it shoud not be used a real user's section. + * @param gppData represents the IAB gppData object + * @returns true|false + */ +function checkApplicableSectionsIsReady(gppData) { + return gppData && Array.isArray(gppData.applicableSections) && gppData.applicableSections.length > 0 && gppData.applicableSections[0] !== 0; +} + +/** + * This function reads the consent string from the config to obtain the consent information of the user. + * @param {function({})} onSuccess acts as a success callback when the value is read from config; pass along consentObject from CMP + */ +function lookupStaticConsentData({onSuccess, onError}) { + processCmpData(staticConsentData, {onSuccess, onError}); +} + +/** + * This function handles interacting with an IAB compliant CMP to obtain the consent information of the user. + * Given the async nature of the CMP's API, we pass in acting success/error callback functions to exit this function + * based on the appropriate result. + * @param {function({})} onSuccess acts as a success callback when CMP returns a value; pass along consentObjectfrom CMP + * @param {function(string, ...{}?)} cmpError acts as an error callback while interacting with CMP; pass along an error message (string) and any extra error arguments (purely for logging) + */ +function lookupIabConsent({onSuccess, onError}) { + const cmpApiName = '__gpp'; + const cmpCallbacks = {}; + let registeredPostMessageResponseListener = false; + + function findCMP() { + let f = window; + let cmpFrame; + let cmpDirectAccess = false; + while (true) { + try { + if (typeof f[cmpApiName] === 'function') { + cmpFrame = f; + cmpDirectAccess = true; + 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['__gppLocator']) { + cmpFrame = f; + break; + } + } catch (e) {} + + if (f === window.top) break; + f = f.parent; + } + + return { + cmpFrame, + cmpDirectAccess + }; + } + + const {cmpFrame, cmpDirectAccess} = findCMP(); + + if (!cmpFrame) { + return onError('GPP CMP not found.'); + } + + const invokeCMP = (cmpDirectAccess) ? invokeCMPDirect : invokeCMPFrame; + + function invokeCMPDirect({command, callback, parameter, version = CMP_VERSION}, resultCb) { + if (typeof resultCb === 'function') { + resultCb(cmpFrame[cmpApiName](command, callback, parameter, version)); + } else { + cmpFrame[cmpApiName](command, callback, parameter, version); + } + } + + function invokeCMPFrame({command, callback, parameter, version = CMP_VERSION}, resultCb) { + const callName = `${cmpApiName}Call`; + if (!registeredPostMessageResponseListener) { + // when we get the return message, call the stashed callback; + window.addEventListener('message', readPostMessageResponse, false); + registeredPostMessageResponseListener = true; + } + + // call CMP via postMessage + const callId = Math.random().toString(); + const msg = { + [callName]: { + command: command, + parameter, + version, + callId: callId + } + }; + + // TODO? - add logic to check if random was already used in the same session, and roll another if so? + cmpCallbacks[callId] = (typeof callback === 'function') ? callback : resultCb; + cmpFrame.postMessage(msg, '*'); + + function readPostMessageResponse(event) { + const cmpDataPkgName = `${cmpApiName}Return`; + const json = (typeof event.data === 'string' && event.data.includes(cmpDataPkgName)) ? JSON.parse(event.data) : event.data; + if (json[cmpDataPkgName] && json[cmpDataPkgName].callId) { + const payload = json[cmpDataPkgName]; + + if (cmpCallbacks.hasOwnProperty(payload.callId)) { + cmpCallbacks[payload.callId](payload.returnValue); + } + } + } + } + + const startupMsg = (cmpDirectAccess) ? 'Detected GPP CMP API is directly accessible, calling it now...' + : 'Detected GPP CMP is outside the current iframe where Prebid.js is located, calling it now...'; + logInfo(startupMsg); + + invokeCMP({ + command: 'addEventListener', + callback: function (evt) { + if (evt) { + logInfo(`Received a ${(cmpDirectAccess ? 'direct' : 'postmsg')} response from GPP CMP for event`, evt); + if (evt.eventName === 'sectionChange' || evt.pingData.cmpStatus === 'loaded') { + invokeCMP({command: 'getGPPData'}, function (gppData) { + logInfo(`Received a ${cmpDirectAccess ? 'direct' : 'postmsg'} response from GPP CMP for getGPPData`, gppData); + processCmpData(gppData, {onSuccess, onError}); + }); + } else if (evt.pingData.cmpStatus === 'error') { + onError('CMP returned with a cmpStatus:error response. Please check CMP setup.'); + } + } + } + }); +} + +/** + * Look up consent data and store it in the `consentData` global as well as `adapterManager.js`' gdprDataHandler. + * + * @param cb A callback that takes: a boolean that is true if the auction should be canceled; an error message and extra + * error arguments that will be undefined if there's no error. + */ +function loadConsentData(cb) { + let isDone = false; + let timer = null; + + function done(consentData, shouldCancelAuction, errMsg, ...extraArgs) { + if (timer != null) { + clearTimeout(timer); + } + isDone = true; + gppDataHandler.setConsentData(consentData); + if (typeof cb === 'function') { + cb(shouldCancelAuction, errMsg, ...extraArgs); + } + } + + if (!includes(Object.keys(cmpCallMap), userCMP)) { + done(null, false, `GPP CMP framework (${userCMP}) is not a supported framework. Aborting consentManagement module and resuming auction.`); + return; + } + + const callbacks = { + onSuccess: (data) => done(data, false), + onError: function (msg, ...extraArgs) { + done(null, true, msg, ...extraArgs); + } + } + cmpCallMap[userCMP](callbacks); + + if (!isDone) { + const onTimeout = () => { + const continueToAuction = (data) => { + done(data, false, 'GPP CMP did not load, continuing auction...'); + } + processCmpData(consentData, { + onSuccess: continueToAuction, + onError: () => continueToAuction(storeConsentData(undefined)) + }) + } + if (consentTimeout === 0) { + onTimeout(); + } else { + timer = setTimeout(onTimeout, consentTimeout); + } + } +} + +/** + * Like `loadConsentData`, but cache and re-use previously loaded data. + * @param cb + */ +function loadIfMissing(cb) { + if (consentData) { + logInfo('User consent information already known. Pulling internally stored information...'); + // eslint-disable-next-line standard/no-callback-literal + cb(false); + } else { + loadConsentData(cb); + } +} + +/** + * If consentManagement module is enabled (ie included in setConfig), this hook function will attempt to fetch the + * user's encoded consent string from the supported CMP. Once obtained, the module will store this + * data as part of a gppConsent object which gets transferred to adapterManager's gppDataHandler object. + * This information is later added into the bidRequest object for any supported adapters to read/pass along to their system. + * @param {object} reqBidsConfigObj required; This is the same param that's used in pbjs.requestBids. + * @param {function} fn required; The next function in the chain, used by hook.js + */ +export const requestBidsHook = timedAuctionHook('gpp', function requestBidsHook(fn, reqBidsConfigObj) { + loadIfMissing(function (shouldCancelAuction, errMsg, ...extraArgs) { + if (errMsg) { + let log = logWarn; + if (shouldCancelAuction) { + log = logError; + errMsg = `${errMsg} Canceling auction as per consentManagement config.`; + } + log(errMsg, ...extraArgs); + } + + if (shouldCancelAuction) { + fn.stopTiming(); + if (typeof reqBidsConfigObj.bidsBackHandler === 'function') { + reqBidsConfigObj.bidsBackHandler(); + } else { + logError('Error executing bidsBackHandler'); + } + } else { + fn.call(this, reqBidsConfigObj); + } + }); +}); + +/** + * This function checks the consent data provided by CMP to ensure it's in an expected state. + * If it's bad, we call `onError` + * If it's good, then we store the value and call `onSuccess` + */ +function processCmpData(consentObject, {onSuccess, onError}) { + function checkData() { + const gppString = consentObject && consentObject.gppString; + const gppSection = (checkApplicableSectionsIsReady(consentObject)) ? consentObject.applicableSections + : (checkApplicableSectionIsReady(consentObject)) ? consentObject.applicableSection : []; + + return !!( + (!Array.isArray(gppSection)) || + (Array.isArray(gppSection) && (!gppString || !isStr(gppString))) + ); + } + + if (checkData()) { + onError(`CMP returned unexpected value during lookup process.`, consentObject); + } else { + onSuccess(storeConsentData(consentObject)); + } +} + +/** + * Stores CMP data locally in module to make information available in adaptermanager.js for later in the auction + * @param {object} cmpConsentObject required; an object representing user's consent choices (can be undefined in certain use-cases for this function only) + */ +function storeConsentData(cmpConsentObject) { + consentData = { + gppString: (cmpConsentObject) ? cmpConsentObject.gppString : undefined, + + fullGppData: (cmpConsentObject) || undefined, + }; + consentData.applicableSections = (checkApplicableSectionsIsReady(cmpConsentObject)) ? cmpConsentObject.applicableSections + : (checkApplicableSectionIsReady(cmpConsentObject)) ? cmpConsentObject.applicableSection : []; + consentData.apiVersion = CMP_VERSION; + return consentData; +} + +/** + * Simply resets the module's consentData variable back to undefined, mainly for testing purposes + */ +export function resetConsentData() { + consentData = undefined; + userCMP = undefined; + consentTimeout = undefined; + gppDataHandler.reset(); +} + +/** + * A configuration function that initializes some module variables, as well as add a hook into the requestBids function + * @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) { + config = config && config.gpp; + if (!config || typeof config !== 'object') { + logWarn('consentManagement.gpp config not defined, exiting consent manager module'); + return; + } + + if (isStr(config.cmpApi)) { + userCMP = config.cmpApi; + } else { + userCMP = DEFAULT_CMP; + logInfo(`consentManagement.gpp config did not specify cmp. Using system default setting (${DEFAULT_CMP}).`); + } + + if (isNumber(config.timeout)) { + consentTimeout = config.timeout; + } else { + consentTimeout = DEFAULT_CONSENT_TIMEOUT; + logInfo(`consentManagement.gpp config did not specify timeout. Using system default setting (${DEFAULT_CONSENT_TIMEOUT}).`); + } + + if (userCMP === 'static') { + if (isPlainObject(config.consentData)) { + staticConsentData = config.consentData; + consentTimeout = 0; + } else { + logError(`consentManagement.gpp config with cmpApi: 'static' did not specify consentData. No consents will be available to adapters.`); + } + } + + logInfo('consentManagement.gpp module has been activated...'); + + if (!addedConsentHook) { + $$PREBID_GLOBAL$$.requestBids.before(requestBidsHook, 50); + } + addedConsentHook = true; + gppDataHandler.enable(); + loadConsentData(); // immediately look up consent data to make it available without requiring an auction +} +config.getConfig('consentManagement', config => setConsentConfig(config.consentManagement)); + +export function enrichFPDHook(next, fpd) { + return next(fpd.then(ortb2 => { + const consent = gppDataHandler.getConsentData(); + if (consent) { + if (Array.isArray(consent.applicableSections)) { + deepSetValue(ortb2, 'regs.gpp_sid', consent.applicableSections); + } + deepSetValue(ortb2, 'regs.gpp', consent.gppString); + } + return ortb2; + })); +} + +enrichFPD.before(enrichFPDHook); diff --git a/modules/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js index 072715b4bd6..71c9c7aa341 100644 --- a/modules/dfpAdServerVideo.js +++ b/modules/dfpAdServerVideo.js @@ -8,7 +8,7 @@ import { deepAccess, isEmpty, logError, parseSizesInput, formatQS, parseUrl, bui import { config } from '../src/config.js'; import { getHook, submodule } from '../src/hook.js'; import { auctionManager } from '../src/auctionManager.js'; -import { gdprDataHandler, uspDataHandler } from '../src/adapterManager.js'; +import { gdprDataHandler, uspDataHandler, gppDataHandler } from '../src/adapterManager.js'; import * as events from '../src/events.js'; import CONSTANTS from '../src/constants.json'; import {getPPID} from '../src/adserver.js'; @@ -119,6 +119,11 @@ export function buildDfpVideoUrl(options) { const uspConsent = uspDataHandler.getConsentData(); if (uspConsent) { queryParams.us_privacy = uspConsent; } + const gppConsent = gppDataHandler.getConsentData(); + if (gppConsent) { + // TODO - need to know what to set here for queryParams... + } + if (!queryParams.ppid) { const ppid = getPPID(); if (ppid != null) { diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 072c280aecf..b609d1a54ec 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -216,7 +216,7 @@ export function resetSyncedStatus() { /** * @param {Array} bidderCodes list of bidders to request user syncs for. */ -function queueSync(bidderCodes, gdprConsent, uspConsent, s2sConfig) { +function queueSync(bidderCodes, gdprConsent, uspConsent, gppConsent, s2sConfig) { if (_s2sConfigs.length === _syncCount) { return; } @@ -246,6 +246,15 @@ function queueSync(bidderCodes, gdprConsent, uspConsent, s2sConfig) { payload.us_privacy = uspConsent; } + if (gppConsent) { + // proposing the following formatting, can adjust if needed... + // update - leaving this param as an array, since it's part of a POST payload where the [] characters shouldn't matter too much + payload.gpp_sid = gppConsent.applicableSections + // should we add check if applicableSections was not equal to -1 (where user was out of scope)? + // this would be similar to what was done above for TCF + payload.gpp = gppConsent.gppString; + } + if (typeof s2sConfig.coopSync === 'boolean') { payload.coopSync = s2sConfig.coopSync; } @@ -330,7 +339,7 @@ function doBidderSync(type, url, bidder, done, timeout) { * * @param {Array} bidders a list of bidder names */ -function doClientSideSyncs(bidders, gdprConsent, uspConsent) { +function doClientSideSyncs(bidders, gdprConsent, uspConsent, gppConsent) { bidders.forEach(bidder => { let clientAdapter = adapterManager.getBidAdapter(bidder); if (clientAdapter && clientAdapter.registerSyncs) { @@ -341,7 +350,8 @@ function doClientSideSyncs(bidders, gdprConsent, uspConsent) { clientAdapter, [], gdprConsent, - uspConsent + uspConsent, + gppConsent ) ); } @@ -411,12 +421,13 @@ function getMatchingConsentUrl(urlProp, gdprConsent) { } function getConsentData(bidRequests) { - let gdprConsent, uspConsent; + let gdprConsent, uspConsent, gppConsent; if (Array.isArray(bidRequests) && bidRequests.length > 0) { gdprConsent = bidRequests[0].gdprConsent; uspConsent = bidRequests[0].uspConsent; + gppConsent = bidRequests[0].gppConsent; } - return { gdprConsent, uspConsent }; + return { gdprConsent, uspConsent, gppConsent }; } /** @@ -433,7 +444,7 @@ export function PrebidServer() { done = adapterMetrics.startTiming('total').stopBefore(done); bidRequests.forEach(req => useMetrics(req.metrics).join(adapterMetrics, {continuePropagation: false})); - let { gdprConsent, uspConsent } = getConsentData(bidRequests); + let { gdprConsent, uspConsent, gppConsent } = getConsentData(bidRequests); if (Array.isArray(_s2sConfigs)) { if (s2sBidRequest.s2sConfig && s2sBidRequest.s2sConfig.syncEndpoint && getMatchingConsentUrl(s2sBidRequest.s2sConfig.syncEndpoint, gdprConsent)) { @@ -441,7 +452,7 @@ export function PrebidServer() { .map(bidder => adapterManager.aliasRegistry[bidder] || bidder) .filter((bidder, index, array) => (array.indexOf(bidder) === index)); - queueSync(syncBidders, gdprConsent, uspConsent, s2sBidRequest.s2sConfig); + queueSync(syncBidders, gdprConsent, uspConsent, gppConsent, s2sBidRequest.s2sConfig); } processPBSRequest(s2sBidRequest, bidRequests, ajax, { @@ -450,7 +461,7 @@ export function PrebidServer() { bidRequests.forEach(bidderRequest => events.emit(CONSTANTS.EVENTS.BIDDER_DONE, bidderRequest)); } done(); - doClientSideSyncs(requestedBidders, gdprConsent, uspConsent); + doClientSideSyncs(requestedBidders, gdprConsent, uspConsent, gppConsent); }, onError: done, onBid: function ({adUnit, bid}) { diff --git a/modules/rtdModule/index.js b/modules/rtdModule/index.js index 876da8dda37..05594c63132 100644 --- a/modules/rtdModule/index.js +++ b/modules/rtdModule/index.js @@ -163,7 +163,7 @@ import {getHook, module} from '../../src/hook.js'; import {logError, logInfo, logWarn} from '../../src/utils.js'; import * as events from '../../src/events.js'; import CONSTANTS from '../../src/constants.json'; -import adapterManager, {gdprDataHandler, uspDataHandler} from '../../src/adapterManager.js'; +import adapterManager, {gdprDataHandler, uspDataHandler, gppDataHandler} from '../../src/adapterManager.js'; import {find} from '../../src/polyfill.js'; import {timedAuctionHook} from '../../src/utils/perfMetrics.js'; @@ -246,6 +246,7 @@ function getConsentData() { return { gdpr: gdprDataHandler.getConsentData(), usp: uspDataHandler.getConsentData(), + gpp: gppDataHandler.getConsentData(), coppa: !!(config.getConfig('coppa')) } } diff --git a/src/adapterManager.js b/src/adapterManager.js index eb6a74a82a4..f4f9e59fb84 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -31,7 +31,7 @@ import {hook} from './hook.js'; import {find, includes} from './polyfill.js'; import {adunitCounter} from './adUnits.js'; import {getRefererInfo} from './refererDetection.js'; -import {GdprConsentHandler, UspConsentHandler} from './consentHandler.js'; +import {GdprConsentHandler, UspConsentHandler, GppConsentHandler} from './consentHandler.js'; import * as events from './events.js'; import CONSTANTS from './constants.json'; import {useMetrics} from './utils/perfMetrics.js'; @@ -161,6 +161,7 @@ function getAdUnitCopyForClientAdapters(adUnits) { export let gdprDataHandler = new GdprConsentHandler(); export let uspDataHandler = new UspConsentHandler(); +export let gppDataHandler = new GppConsentHandler(); export let coppaDataHandler = { getCoppa: function() { @@ -309,17 +310,17 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a } }); - if (gdprDataHandler.getConsentData()) { - bidRequests.forEach(bidRequest => { + bidRequests.forEach(bidRequest => { + if (gdprDataHandler.getConsentData()) { bidRequest['gdprConsent'] = gdprDataHandler.getConsentData(); - }); - } - - if (uspDataHandler.getConsentData()) { - bidRequests.forEach(bidRequest => { + } + if (uspDataHandler.getConsentData()) { bidRequest['uspConsent'] = uspDataHandler.getConsentData(); - }); - } + } + if (gppDataHandler.getConsentData()) { + bidRequest['gppConsent'] = gppDataHandler.getConsentData(); + } + }); bidRequests.forEach(bidRequest => { config.runWithBidder(bidRequest.bidderCode, () => { diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index 7e66b849783..55c84e57062 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -214,7 +214,7 @@ export function newBidder(spec) { done(); config.runWithBidder(spec.code, () => { events.emit(CONSTANTS.EVENTS.BIDDER_DONE, bidderRequest); - registerSyncs(responses, bidderRequest.gdprConsent, bidderRequest.uspConsent); + registerSyncs(responses, bidderRequest.gdprConsent, bidderRequest.uspConsent, bidderRequest.gppConsent); }); } @@ -295,8 +295,8 @@ export function newBidder(spec) { return false; } - function registerSyncs(responses, gdprConsent, uspConsent) { - registerSyncInner(spec, responses, gdprConsent, uspConsent); + function registerSyncs(responses, gdprConsent, uspConsent, gppConsent) { + registerSyncInner(spec, responses, gdprConsent, uspConsent, gppConsent); } function filterAndWarn(bid) { @@ -448,14 +448,14 @@ export const processBidderRequests = hook('sync', function (spec, bids, bidderRe }) }, 'processBidderRequests') -export const registerSyncInner = hook('async', function(spec, responses, gdprConsent, uspConsent) { +export const registerSyncInner = hook('async', function(spec, responses, gdprConsent, uspConsent, gppConsent) { 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); + }, responses, gdprConsent, uspConsent, gppConsent); if (syncs) { if (!Array.isArray(syncs)) { syncs = [syncs]; diff --git a/src/consentHandler.js b/src/consentHandler.js index 01470a4b38c..b1b2a04c043 100644 --- a/src/consentHandler.js +++ b/src/consentHandler.js @@ -107,3 +107,14 @@ export class GdprConsentHandler extends ConsentHandler { } } } + +export class GppConsentHandler extends ConsentHandler { + getConsentMeta() { + const consentData = this.getConsentData(); + if (consentData && this.generatedTime) { + return { + generatedAt: this.generatedTime, + } + } + } +} diff --git a/src/prebid.js b/src/prebid.js index f30b4ea9bbe..a4abceb01d5 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -45,7 +45,7 @@ import {executeRenderer, isRendererRequired} from './Renderer.js'; import {createBid} from './bidfactory.js'; import {storageCallbacks} from './storageManager.js'; import {emitAdRenderFail, emitAdRenderSucceeded} from './adRendering.js'; -import {default as adapterManager, gdprDataHandler, getS2SBidderSet, uspDataHandler} from './adapterManager.js'; +import {default as adapterManager, gdprDataHandler, getS2SBidderSet, gppDataHandler, uspDataHandler} from './adapterManager.js'; import CONSTANTS from './constants.json'; import * as events from './events.js'; import {newMetrics, useMetrics} from './utils/perfMetrics.js'; @@ -336,6 +336,7 @@ function getConsentMetadata() { return { gdpr: gdprDataHandler.getConsentMeta(), usp: uspDataHandler.getConsentMeta(), + gpp: gppDataHandler.getConsentMeta(), coppa: !!(config.getConfig('coppa')) } } diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index 5cd189da9a1..1ab8feceaeb 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -985,6 +985,52 @@ describe('AppNexusAdapter', function () { expect(payload.us_privacy).to.exist.and.to.equal(consentString); }); + it('should add gpp information to the request via bidderRequest.gppConsent', function () { + let consentString = 'abc1234'; + let bidderRequest = { + 'bidderCode': 'appnexus', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gppConsent': { + 'gppString': consentString, + 'applicableSections': [8] + } + }; + bidderRequest.bids = bidRequests; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.privacy).to.exist; + expect(payload.privacy.gpp).to.equal(consentString); + expect(payload.privacy.gpp_sid).to.deep.equal([8]); + }); + + it('should add gpp information to the request via bidderRequest.ortb2.regs', function () { + let consentString = 'abc1234'; + let bidderRequest = { + 'bidderCode': 'appnexus', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'ortb2': { + 'regs': { + 'gpp': consentString, + 'gpp_sid': [7] + } + } + }; + bidderRequest.bids = bidRequests; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.privacy).to.exist; + expect(payload.privacy.gpp).to.equal(consentString); + expect(payload.privacy.gpp_sid).to.deep.equal([7]); + }); + it('supports sending hybrid mobile app parameters', function () { let appRequest = Object.assign({}, bidRequests[0], diff --git a/test/spec/modules/consentManagementGpp_spec.js b/test/spec/modules/consentManagementGpp_spec.js new file mode 100644 index 00000000000..1170f418caf --- /dev/null +++ b/test/spec/modules/consentManagementGpp_spec.js @@ -0,0 +1,577 @@ +import { setConsentConfig, requestBidsHook, resetConsentData, userCMP, consentTimeout, staticConsentData } from 'modules/consentManagementGpp.js'; +import { gppDataHandler } from 'src/adapterManager.js'; +import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; +import 'src/prebid.js'; + +let expect = require('chai').expect; + +describe('consentManagementGpp', function () { + describe('setConsentConfig tests:', function () { + describe('empty setConsentConfig value', function () { + beforeEach(function () { + sinon.stub(utils, 'logInfo'); + sinon.stub(utils, 'logWarn'); + }); + + afterEach(function () { + utils.logInfo.restore(); + utils.logWarn.restore(); + config.resetConfig(); + resetConsentData(); + }); + + it('should use system default values', function () { + setConsentConfig({ + gpp: {} + }); + expect(userCMP).to.be.equal('iab'); + expect(consentTimeout).to.be.equal(10000); + sinon.assert.callCount(utils.logInfo, 3); + }); + + 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 consentManagement module if config is "undefined"', function () { + setConsentConfig(undefined); + expect(userCMP).to.be.undefined; + sinon.assert.calledOnce(utils.logWarn); + }); + + it('should not produce any consent metadata', function () { + setConsentConfig(undefined) + let consentMetadata = gppDataHandler.getConsentMeta(); + expect(consentMetadata).to.be.undefined; + sinon.assert.calledOnce(utils.logWarn); + }) + + it('should immediately look up consent data', () => { + setConsentConfig({ + gpp: { + cmpApi: 'invalid' + } + }); + expect(gppDataHandler.ready).to.be.true; + }) + }); + + describe('valid setConsentConfig value', function () { + afterEach(function () { + config.resetConfig(); + }); + + it('results in all user settings overriding system defaults', function () { + let allConfig = { + gpp: { + cmpApi: 'iab', + timeout: 7500 + } + }; + + setConsentConfig(allConfig); + expect(userCMP).to.be.equal('iab'); + expect(consentTimeout).to.be.equal(7500); + }); + + it('should recognize config.gpp, with default cmpApi and timeout', function () { + setConsentConfig({ + gpp: {} + }); + + expect(userCMP).to.be.equal('iab'); + expect(consentTimeout).to.be.equal(10000); + }); + + it('should enable gppDataHandler', () => { + setConsentConfig({ + gpp: {} + }); + expect(gppDataHandler.enabled).to.be.true; + }); + }); + + describe('static consent string setConsentConfig value', () => { + afterEach(() => { + config.resetConfig(); + }); + + it('results in user settings overriding system defaults for v2 spec', () => { + let staticConfig = { + gpp: { + cmpApi: 'static', + timeout: 7500, + consentData: { + applicableSections: [7], + gppString: 'ABCDEFG1234', + gppVersion: 1, + sectionId: 3, + sectionList: [] + } + } + }; + + setConsentConfig(staticConfig); + expect(userCMP).to.be.equal('static'); + expect(consentTimeout).to.be.equal(0); // should always return without a timeout when config is used + const consent = gppDataHandler.getConsentData(); + expect(consent.gppString).to.eql(staticConfig.gpp.consentData.gppString); + expect(consent.fullGppData).to.eql(staticConfig.gpp.consentData); + expect(staticConsentData).to.be.equal(staticConfig.gpp.consentData); + }); + }); + }); + + describe('requestBidsHook tests:', function () { + let goodConfig = { + gpp: { + cmpApi: 'iab', + timeout: 7500, + } + }; + + const staticConfig = { + gpp: { + cmpApi: 'static', + timeout: 7500, + consentData: { + gppString: 'abc12345', + applicableSections: [7] + } + } + } + + let didHookReturn; + + beforeEach(resetConsentData); + after(resetConsentData); + + describe('error checks:', function () { + beforeEach(function () { + didHookReturn = false; + sinon.stub(utils, 'logWarn'); + sinon.stub(utils, 'logError'); + }); + + afterEach(function () { + utils.logWarn.restore(); + utils.logError.restore(); + config.resetConfig(); + }); + + it('should throw a warning and return to hooked function when an unknown CMP framework ID is used', function () { + let badCMPConfig = { + gpp: { + cmpApi: 'bad' + } + }; + setConsentConfig(badCMPConfig); + expect(userCMP).to.be.equal(badCMPConfig.gpp.cmpApi); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consent = gppDataHandler.getConsentData(); + + sinon.assert.calledOnce(utils.logWarn); + expect(didHookReturn).to.be.true; + expect(consent).to.be.null; + }); + + it('should call gppDataHandler.setConsentData() when unknown CMP api is used', () => { + setConsentConfig({ + gpp: { + cmpApi: 'invalid' + } + }); + let hookRan = false; + requestBidsHook(() => { + hookRan = true; + }, {}); + expect(hookRan).to.be.true; + expect(gppDataHandler.ready).to.be.true; + }) + + it('should throw proper errors when CMP is not found', function () { + setConsentConfig(goodConfig); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consent = gppDataHandler.getConsentData(); + // throw 2 errors; one for no bidsBackHandler and for CMP not being found (this is an error due to gdpr config) + sinon.assert.calledTwice(utils.logError); + expect(didHookReturn).to.be.false; + expect(consent).to.be.null; + expect(gppDataHandler.ready).to.be.true; + }); + + it('should not trip when adUnits have no size', () => { + setConsentConfig(staticConfig); + let ran = false; + requestBidsHook(() => { + ran = true; + }, { + adUnits: [{ + code: 'test', + mediaTypes: { + video: {} + } + }] + }); + return gppDataHandler.promise.then(() => { + expect(ran).to.be.true; + }); + }); + + it('should continue the auction immediately, without consent data, if timeout is 0', (done) => { + setConsentConfig({ + gpp: { + cmpApi: 'iab', + timeout: 0 + } + }); + window.__gpp = function () {}; + try { + requestBidsHook(() => { + const consent = gppDataHandler.getConsentData(); + expect(consent.applicableSections).to.deep.equal([]); + expect(consent.gppString).to.be.undefined; + done(); + }, {}) + } finally { + delete window.__gpp; + } + }); + }); + + describe('already known consentData:', function () { + let cmpStub = sinon.stub(); + + function mockCMP(cmpResponse) { + return function (...args) { + if (args[0] === 'addEventListener') { + args[1](({ + eventName: 'sectionChange' + })); + } else if (args[0] === 'getGPPData') { + return cmpResponse; + } + } + } + + beforeEach(function () { + didHookReturn = false; + window.__gpp = function () {}; + }); + + afterEach(function () { + config.resetConfig(); + cmpStub.restore(); + delete window.__gpp; + resetConsentData(); + }); + + it('should bypass CMP and simply use previously stored consentData', function () { + let testConsentData = { + applicableSections: [7], + gppString: 'xyz', + }; + + cmpStub = sinon.stub(window, '__gpp').callsFake(mockCMP(testConsentData)); + setConsentConfig(goodConfig); + requestBidsHook(() => {}, {}); + cmpStub.reset(); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consent = gppDataHandler.getConsentData(); + + expect(didHookReturn).to.be.true; + expect(consent.gppString).to.equal(testConsentData.gppString); + expect(consent.applicableSections).to.deep.equal(testConsentData.applicableSections); + sinon.assert.notCalled(cmpStub); + }); + }); + + describe('iframe tests', function () { + let cmpPostMessageCb = () => {}; + let stringifyResponse; + + function createIFrameMarker(frameName) { + let ifr = document.createElement('iframe'); + ifr.width = 0; + ifr.height = 0; + ifr.name = frameName; + document.body.appendChild(ifr); + return ifr; + } + + function creatCmpMessageHandler(prefix, returnEvtValue, returnGPPValue) { + return function (event) { + if (event && event.data) { + let data = event.data; + if (data[`${prefix}Call`]) { + let callId = data[`${prefix}Call`].callId; + let response; + if (data[`${prefix}Call`].command === 'addEventListener') { + response = { + [`${prefix}Return`]: { + callId, + returnValue: returnEvtValue, + success: true + } + } + } else if (data[`${prefix}Call`].command === 'getGPPData') { + response = { + [`${prefix}Return`]: { + callId, + returnValue: returnGPPValue, + success: true + } + } + } + event.source.postMessage(stringifyResponse ? JSON.stringify(response) : response, '*'); + } + } + } + } + + function testIFramedPage(testName, messageFormatString, tarConsentString, tarSections) { + it(`should return the consent string from a postmessage + addEventListener response - ${testName}`, (done) => { + stringifyResponse = messageFormatString; + setConsentConfig(goodConfig); + requestBidsHook(() => { + let consent = gppDataHandler.getConsentData(); + sinon.assert.notCalled(utils.logError); + expect(consent.gppString).to.equal(tarConsentString); + expect(consent.applicableSections).to.deep.equal(tarSections); + done(); + }, {}); + }); + } + + beforeEach(function () { + sinon.stub(utils, 'logError'); + sinon.stub(utils, 'logWarn'); + }); + + afterEach(function () { + utils.logError.restore(); + utils.logWarn.restore(); + config.resetConfig(); + resetConsentData(); + }); + + describe('v2 CMP workflow for iframe pages:', function () { + stringifyResponse = false; + let ifr2 = null; + + beforeEach(function () { + ifr2 = createIFrameMarker('__gppLocator'); + cmpPostMessageCb = creatCmpMessageHandler('__gpp', { + eventName: 'sectionChange' + }, { + gppString: 'abc12345234', + applicableSections: [7] + }); + window.addEventListener('message', cmpPostMessageCb, false); + }); + + afterEach(function () { + delete window.__gpp; // 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', [7]); + testIFramedPage('with/String response', true, 'abc12345234', [7]); + }); + }); + + describe('direct calls to CMP API tests', function () { + let cmpStub = sinon.stub(); + + beforeEach(function () { + didHookReturn = false; + sinon.stub(utils, 'logError'); + sinon.stub(utils, 'logWarn'); + }); + + afterEach(function () { + config.resetConfig(); + cmpStub.restore(); + utils.logError.restore(); + utils.logWarn.restore(); + resetConsentData(); + }); + + describe('v2 CMP workflow for normal pages:', function () { + beforeEach(function () { + window.__gpp = function () {}; + }); + + afterEach(function () { + delete window.__gpp; + }); + + it('performs lookup check and stores consentData for a valid existing user', function () { + let testConsentData = { + gppString: 'abc12345234', + applicableSections: [7] + }; + cmpStub = sinon.stub(window, '__gpp').callsFake((...args) => { + if (args[0] === 'addEventListener') { + args[1]({ + eventName: 'sectionChange' + }); + } else if (args[0] === 'getGPPData') { + return testConsentData; + } + }); + + setConsentConfig(goodConfig); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consent = gppDataHandler.getConsentData(); + sinon.assert.notCalled(utils.logError); + expect(didHookReturn).to.be.true; + expect(consent.gppString).to.equal(testConsentData.gppString); + expect(consent.applicableSections).to.deep.equal(testConsentData.applicableSections); + }); + + it('produces gdpr metadata', function () { + let testConsentData = { + gppString: 'abc12345234', + applicableSections: [7] + }; + cmpStub = sinon.stub(window, '__gpp').callsFake((...args) => { + if (args[0] === 'addEventListener') { + args[1]({ + eventName: 'sectionChange' + }); + } else if (args[0] === 'getGPPData') { + return testConsentData; + } + }); + + setConsentConfig(goodConfig); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consentMeta = gppDataHandler.getConsentMeta(); + sinon.assert.notCalled(utils.logError); + expect(consentMeta.generatedAt).to.be.above(1644367751709); + }); + + it('throws an error when processCmpData check fails + does not call requestBids callback', function () { + let testConsentData = {}; + let bidsBackHandlerReturn = false; + + cmpStub = sinon.stub(window, '__gpp').callsFake((...args) => { + if (args[0] === 'addEventListener') { + args[1]({ + eventName: 'sectionChange' + }); + } else if (args[0] === 'getGPPData') { + return testConsentData; + } + }); + + setConsentConfig(goodConfig); + + sinon.assert.notCalled(utils.logWarn); + sinon.assert.notCalled(utils.logError); + + [utils.logWarn, utils.logError].forEach((stub) => stub.reset()); + + requestBidsHook(() => { + didHookReturn = true; + }, { + bidsBackHandler: () => bidsBackHandlerReturn = true + }); + let consent = gppDataHandler.getConsentData(); + + sinon.assert.calledOnce(utils.logError); + sinon.assert.notCalled(utils.logWarn); + expect(didHookReturn).to.be.false; + expect(bidsBackHandlerReturn).to.be.true; + expect(consent).to.be.null; + expect(gppDataHandler.ready).to.be.true; + }); + + describe('when proper consent is not available', () => { + let gppStub; + + function runAuction() { + setConsentConfig({ + gpp: { + cmpApi: 'iab', + timeout: 10, + } + }); + return new Promise((resolve, reject) => { + requestBidsHook(() => { + didHookReturn = true; + }, {}); + setTimeout(() => didHookReturn ? resolve() : reject(new Error('Auction did not run')), 20); + }) + } + + function mockGppCmp(gppdata) { + gppStub.callsFake((api, cb) => { + if (api === 'addEventListener') { + // eslint-disable-next-line standard/no-callback-literal + cb({ + pingData: { + cmpStatus: 'loaded' + } + }, true); + } + if (api === 'getGPPData') { + return gppdata; + } + }); + } + + beforeEach(() => { + gppStub = sinon.stub(window, '__gpp'); + }); + + afterEach(() => { + gppStub.restore(); + }) + + it('should continue auction with null consent when CMP is unresponsive', () => { + return runAuction().then(() => { + const consent = gppDataHandler.getConsentData(); + expect(consent.applicableSections).to.deep.equal([]); + expect(consent.gppString).to.be.undefined; + expect(gppDataHandler.ready).to.be.true; + }); + }); + + it('should use consent provided by events other than sectionChange', () => { + mockGppCmp({ + gppString: 'mock-consent-string', + applicableSections: [7] + }); + return runAuction().then(() => { + const consent = gppDataHandler.getConsentData(); + expect(consent.applicableSections).to.deep.equal([7]); + expect(consent.gppString).to.equal('mock-consent-string'); + expect(gppDataHandler.ready).to.be.true; + }); + }); + }); + }); + }); + }); +}); From b4688316e76d69590c5da46dbec5b47cedea04f4 Mon Sep 17 00:00:00 2001 From: Andrew Slagle <42588549+spotxslagle@users.noreply.github.com> Date: Wed, 21 Dec 2022 10:53:05 -0700 Subject: [PATCH 219/367] Magnite Analytics Adapter : data deletion function (#9351) * add onDeletionRequest functionality to Magnite adapter * Magnite add onDataDeletionRequest unit testing --- modules/magniteAnalyticsAdapter.js | 10 +++- .../modules/magniteAnalyticsAdapter_spec.js | 50 +++++++++++++------ 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/modules/magniteAnalyticsAdapter.js b/modules/magniteAnalyticsAdapter.js index 99f384e9eff..c6911897e84 100644 --- a/modules/magniteAnalyticsAdapter.js +++ b/modules/magniteAnalyticsAdapter.js @@ -643,7 +643,15 @@ magniteAdapter.disableAnalytics = function () { accountId = undefined; resetConfs(); magniteAdapter.originDisableAnalytics(); -} +}; + +magniteAdapter.onDataDeletionRequest = function () { + if (storage.localStorageIsEnabled()) { + storage.removeDataFromLocalStorage(COOKIE_NAME); + } else { + throw Error('Unable to access local storage, no data deleted'); + } +}; magniteAdapter.MODULE_INITIALIZED_TIME = Date.now(); magniteAdapter.referrerHostname = ''; diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js index 69fd7794ced..3606b4b4550 100644 --- a/test/spec/modules/magniteAnalyticsAdapter_spec.js +++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js @@ -306,7 +306,7 @@ const ANALYTICS_MESSAGE = { describe('magnite analytics adapter', function () { let sandbox; let clock; - let getDataFromLocalStorageStub, setDataInLocalStorageStub, localStorageIsEnabledStub; + let getDataFromLocalStorageStub, setDataInLocalStorageStub, localStorageIsEnabledStub, removeDataFromLocalStorageStub; let gptSlot0; let gptSlotRenderEnded0; beforeEach(function () { @@ -325,6 +325,7 @@ describe('magnite analytics adapter', function () { getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); setDataInLocalStorageStub = sinon.stub(storage, 'setDataInLocalStorage'); localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled'); + removeDataFromLocalStorageStub = sinon.stub(storage, 'removeDataFromLocalStorage') sandbox = sinon.sandbox.create(); localStorageIsEnabledStub.returns(true); @@ -355,6 +356,7 @@ describe('magnite analytics adapter', function () { getDataFromLocalStorageStub.restore(); setDataInLocalStorageStub.restore(); localStorageIsEnabledStub.restore(); + removeDataFromLocalStorageStub.restore(); magniteAdapter.disableAnalytics(); }); @@ -1932,19 +1934,21 @@ describe('magnite analytics adapter', function () { }); }); - 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'); + describe('getHostNameFromReferer', () => { + it('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'); + }); }); describe(`handle currency conversions`, () => { @@ -1985,4 +1989,22 @@ describe('magnite analytics adapter', function () { expect(bidResponseObj.bidPriceUSD).to.equal(0); }); }); + + describe('onDataDeletionRequest', () => { + it('attempts to delete the magnite cookie when local storage is enabled', () => { + magniteAdapter.onDataDeletionRequest(); + + expect(removeDataFromLocalStorageStub.getCall(0).args[0]).to.equal('mgniSession'); + }); + + it('throws an error if it cannot access the cookie', (done) => { + localStorageIsEnabledStub.returns(false); + try { + magniteAdapter.onDataDeletionRequest(); + } catch (error) { + expect(error.message).to.equal('Unable to access local storage, no data deleted'); + done(); + } + }) + }); }); From d5746c39c437b5e04505cdd75bdef3791eb28566 Mon Sep 17 00:00:00 2001 From: Bill Newman Date: Wed, 21 Dec 2022 19:56:48 +0200 Subject: [PATCH 220/367] Colosuss Bid Adapter: add support First Party Data (#9340) * add video&native traffic colossus ssp * Native obj validation * Native obj validation #2 * Added size field in requests * fixed test * fix merge conflicts * move to 3.0 * move to 3.0 * fix IE11 new URL issue * fix IE11 new URL issue * fix IE11 new URL issue * https for 3.0 * add https test * add ccp and schain features * fix test * sync with upstream, fix conflicts * Update colossussspBidAdapter.js remove commented code * Update colossussspBidAdapter.js lint fix * identity extensions * identity extensions * fix * fix * fix * fix * fix * add tests for user ids * fix * fix * fix * fix * fix * fix * fix * add gdpr support * add gdpr support * id5id support * Update colossussspBidAdapter.js add bidfloor parameter * Update colossussspBidAdapter.js check bidfloor * Update colossussspBidAdapter.js * Update colossussspBidAdapter.js * Update colossussspBidAdapter.js * Update colossussspBidAdapter_spec.js * use floor module * Revert "use floor module" This reverts commit f0c5c248627567e669d8eed4f2bb9a26a857e2ad. * use floor module * update to 5v * fix * add uid2 and bidFloor support * fix * add pbadslot support * fix conflicts * add onBidWon * refactor * add test for onBidWon() * fix * add group_id * Trigger circleci * fix * update user sync * fix window.location * fix test * updates * fix conflict * fix * updates * remove traffic param * add transactionId to request data for colossusssp adapter * Send tid in placements array * update user sync * updated tests * remove changes package-lock file * fix * add First Party Data Co-authored-by: Vladislav Isaiko Co-authored-by: Aiholkin Co-authored-by: Mykhailo Yaremchuk --- modules/colossussspBidAdapter.js | 8 ++ .../modules/colossussspBidAdapter_spec.js | 91 ++++++++++++++++++- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/modules/colossussspBidAdapter.js b/modules/colossussspBidAdapter.js index 75e73ffda89..082fb0ac4db 100644 --- a/modules/colossussspBidAdapter.js +++ b/modules/colossussspBidAdapter.js @@ -87,6 +87,11 @@ export const spec = { logMessage(e); } + const firstPartyData = bidderRequest.ortb2 || {}; + const userObj = firstPartyData.user; + const siteObj = firstPartyData.site; + const appObj = firstPartyData.app; + // TODO: does the fallback to window.location make sense? const location = refferLocation || winLocation; let placements = []; @@ -97,6 +102,9 @@ export const spec = { secure: location.protocol === 'https:' ? 1 : 0, host: location.host, page: location.pathname, + userObj, + siteObj, + appObj, placements: placements }; diff --git a/test/spec/modules/colossussspBidAdapter_spec.js b/test/spec/modules/colossussspBidAdapter_spec.js index 71e94f0da32..adb9137d892 100644 --- a/test/spec/modules/colossussspBidAdapter_spec.js +++ b/test/spec/modules/colossussspBidAdapter_spec.js @@ -56,6 +56,93 @@ describe('ColossussspAdapter', function () { referer: 'http://www.example.com', reachedTop: true, }, + ortb2: { + app: { + name: 'myappname', + keywords: 'power tools, drills', + content: { + data: [ + { + name: 'www.dataprovider1.com', + ext: { + segtax: 6 + }, + segment: [ + { + id: '687' + }, + { + id: '123' + } + ] + }, + { + name: 'www.dataprovider1.com', + ext: { + segtax: 7 + }, + segment: [ + { + id: '456' + }, + { + id: '789' + } + ] + } + ] + } + }, + site: { + name: 'example', + domain: 'page.example.com', + cat: ['IAB2'], + sectioncat: ['IAB2-2'], + pagecat: ['IAB2-2'], + page: 'https://page.example.com/here.html', + ref: 'https://ref.example.com', + keywords: 'power tools, drills', + search: 'drill', + content: { + userrating: '4', + data: [{ + name: 'www.dataprovider1.com', + ext: { + segtax: 7, + cids: ['iris_c73g5jq96mwso4d8'] + }, + segment: [ + { id: '687' }, + { id: '123' } + ] + }] + }, + ext: { + data: { + pageType: 'article', + category: 'repair' + } + } + }, + user: { + yob: 1985, + gender: 'm', + keywords: 'a,b', + data: [{ + name: 'dataprovider.com', + ext: { segtax: 4 }, + segment: [ + { id: '1' } + ] + }], + ext: { + data: { + registered: true, + interests: ['cars'] + } + } + } + }, bids: [bid] } @@ -91,7 +178,7 @@ describe('ColossussspAdapter', function () { 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', 'ccpa', 'gdpr_consent', 'gdpr_require'); + expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'ccpa', 'gdpr_consent', 'gdpr_require', 'userObj', 'siteObj', 'appObj'); expect(data.deviceWidth).to.be.a('number'); expect(data.deviceHeight).to.be.a('number'); expect(data.language).to.be.a('string'); @@ -132,7 +219,7 @@ describe('ColossussspAdapter', function () { let data = serverRequest.data; expect(data).to.be.an('object'); - expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'ccpa', 'gdpr_consent', 'gdpr_require'); + expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'ccpa', 'gdpr_consent', 'gdpr_require', 'userObj', 'siteObj', 'appObj'); expect(data.deviceWidth).to.be.a('number'); expect(data.deviceHeight).to.be.a('number'); expect(data.language).to.be.a('string'); From 9c3abaea97f282e9e62f3a5b80bcfdbaefc7cb88 Mon Sep 17 00:00:00 2001 From: mjaworskiccx <50406214+mjaworskiccx@users.noreply.github.com> Date: Thu, 22 Dec 2022 20:10:49 +0100 Subject: [PATCH 221/367] Clickonometrics Bid Adapter: gvlid (#9367) * adomain support * adomain support * adomain support * adomain support * adomain support * video params * docs changes * Clickonometrics adapter update * Revert "Revert "Clickonometrics Bid Adapter : add gvlid (#9198)" (#9216)" This reverts commit 6d114e83725b403fadd889202b449de225db7275. * Test fix --- modules/ccxBidAdapter.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/ccxBidAdapter.js b/modules/ccxBidAdapter.js index 7c6b0411023..28f3fe3a166 100644 --- a/modules/ccxBidAdapter.js +++ b/modules/ccxBidAdapter.js @@ -5,6 +5,7 @@ import {getStorageManager} from '../src/storageManager.js'; const BIDDER_CODE = 'ccx' const storage = getStorageManager({bidderCode: BIDDER_CODE}); const BID_URL = 'https://delivery.clickonometrics.pl/ortb/prebid/bid' +const GVLID = 773; const SUPPORTED_VIDEO_PROTOCOLS = [2, 3, 5, 6] const SUPPORTED_VIDEO_MIMES = ['video/mp4', 'video/x-flv'] const SUPPORTED_VIDEO_PLAYBACK_METHODS = [1, 2, 3, 4] @@ -19,8 +20,7 @@ function _getDeviceObj () { function _getSiteObj (bidderRequest) { let site = {} - // TODO: does the fallback to window.location make sense? - let url = bidderRequest?.refererInfo?.page || window.location.href + let url = bidderRequest?.refererInfo?.page || '' if (url.length > 0) { url = url.split('?')[0] } @@ -140,6 +140,7 @@ function _buildResponse (bid, currency, ttl) { export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: ['banner', 'video'], isBidRequestValid: function (bid) { From e5bcdaa059a3ad675ff3e3dae78423bb558f498e Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 23 Dec 2022 17:14:37 +0000 Subject: [PATCH 222/367] Prebid 7.30.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c903795e59d..51491f04fbe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.30.0-pre", + "version": "7.30.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 490303874f7..6ffdac7d3a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.30.0-pre", + "version": "7.30.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 4e45ba34c76ad03b417942320c376749c9f96b44 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 23 Dec 2022 17:14:37 +0000 Subject: [PATCH 223/367] Increment version to 7.31.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 51491f04fbe..7de32ef7102 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.30.0", + "version": "7.31.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 6ffdac7d3a6..f96909cc6b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.30.0", + "version": "7.31.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 684691bb69263fcdda1d31b3fabe3db859e609b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Dec 2022 09:29:25 -0500 Subject: [PATCH 224/367] Bump parse-url from 7.0.2 to 8.1.0 (#9372) Bumps [parse-url](https://github.com/IonicaBizau/parse-url) from 7.0.2 to 8.1.0. - [Release notes](https://github.com/IonicaBizau/parse-url/releases) - [Commits](https://github.com/IonicaBizau/parse-url/compare/7.0.2...8.1.0) --- updated-dependencies: - dependency-name: parse-url dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 84 ++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7de32ef7102..2b703493403 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.28.0-pre", + "version": "7.31.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -8534,9 +8534,9 @@ } }, "node_modules/documentation": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/documentation/-/documentation-14.0.0.tgz", - "integrity": "sha512-4AwFzdiseEdtqR0KKLrruIQ5fvh7n5epg47P0ZyOidA5Fes5am+6xjqkDECHPwcv4pxJ6zITaHwzCoGblP0+JQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/documentation/-/documentation-14.0.1.tgz", + "integrity": "sha512-Y/brACCE3sNnDJPFiWlhXrqGY+NelLYVZShLGse5bT1KdohP4JkPf5T2KNq1YWhIEbDYl/1tebRLC0WYbPQxVw==", "dev": true, "dependencies": { "@babel/core": "^7.18.10", @@ -8548,7 +8548,7 @@ "chokidar": "^3.5.3", "diff": "^5.1.0", "doctrine-temporary-fork": "2.1.0", - "git-url-parse": "^12.0.0", + "git-url-parse": "^13.1.0", "github-slugger": "1.4.0", "glob": "^8.0.3", "globals-docs": "^2.4.1", @@ -11261,22 +11261,22 @@ } }, "node_modules/git-up": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-6.0.0.tgz", - "integrity": "sha512-6RUFSNd1c/D0xtGnyWN2sxza2bZtZ/EmI9448n6rCZruFwV/ezeEn2fJP7XnUQGwf0RAtd/mmUCbtH6JPYA2SA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", + "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", "dev": true, "dependencies": { "is-ssh": "^1.4.0", - "parse-url": "^7.0.2" + "parse-url": "^8.1.0" } }, "node_modules/git-url-parse": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-12.0.0.tgz", - "integrity": "sha512-I6LMWsxV87vysX1WfsoglXsXg6GjQRKq7+Dgiseo+h0skmp5Hp2rzmcEIRQot9CPA+uzU7x1x7jZdqvTFGnB+Q==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz", + "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==", "dev": true, "dependencies": { - "git-up": "^6.0.0" + "git-up": "^7.0.0" } }, "node_modules/github-slugger": { @@ -19420,24 +19420,21 @@ } }, "node_modules/parse-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-5.0.0.tgz", - "integrity": "sha512-qOpH55/+ZJ4jUu/oLO+ifUKjFPNZGfnPJtzvGzKN/4oLMil5m9OH4VpOj6++9/ytJcfks4kzH2hhi87GL/OU9A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz", + "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==", "dev": true, "dependencies": { "protocols": "^2.0.0" } }, "node_modules/parse-url": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-7.0.2.tgz", - "integrity": "sha512-PqO4Z0eCiQ08Wj6QQmrmp5YTTxpYfONdOEamrtvK63AmzXpcavIVQubGHxOEwiIoDZFb8uDOoQFS0NCcjqIYQg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", + "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", "dev": true, "dependencies": { - "is-ssh": "^1.4.0", - "normalize-url": "^6.1.0", - "parse-path": "^5.0.0", - "protocols": "^2.0.1" + "parse-path": "^7.0.0" } }, "node_modules/parseurl": { @@ -31782,9 +31779,9 @@ } }, "documentation": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/documentation/-/documentation-14.0.0.tgz", - "integrity": "sha512-4AwFzdiseEdtqR0KKLrruIQ5fvh7n5epg47P0ZyOidA5Fes5am+6xjqkDECHPwcv4pxJ6zITaHwzCoGblP0+JQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/documentation/-/documentation-14.0.1.tgz", + "integrity": "sha512-Y/brACCE3sNnDJPFiWlhXrqGY+NelLYVZShLGse5bT1KdohP4JkPf5T2KNq1YWhIEbDYl/1tebRLC0WYbPQxVw==", "dev": true, "requires": { "@babel/core": "^7.18.10", @@ -31797,7 +31794,7 @@ "chokidar": "^3.5.3", "diff": "^5.1.0", "doctrine-temporary-fork": "2.1.0", - "git-url-parse": "^12.0.0", + "git-url-parse": "^13.1.0", "github-slugger": "1.4.0", "glob": "^8.0.3", "globals-docs": "^2.4.1", @@ -33988,22 +33985,22 @@ } }, "git-up": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-6.0.0.tgz", - "integrity": "sha512-6RUFSNd1c/D0xtGnyWN2sxza2bZtZ/EmI9448n6rCZruFwV/ezeEn2fJP7XnUQGwf0RAtd/mmUCbtH6JPYA2SA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", + "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", "dev": true, "requires": { "is-ssh": "^1.4.0", - "parse-url": "^7.0.2" + "parse-url": "^8.1.0" } }, "git-url-parse": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-12.0.0.tgz", - "integrity": "sha512-I6LMWsxV87vysX1WfsoglXsXg6GjQRKq7+Dgiseo+h0skmp5Hp2rzmcEIRQot9CPA+uzU7x1x7jZdqvTFGnB+Q==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz", + "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==", "dev": true, "requires": { - "git-up": "^6.0.0" + "git-up": "^7.0.0" } }, "github-slugger": { @@ -40244,24 +40241,21 @@ "dev": true }, "parse-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-5.0.0.tgz", - "integrity": "sha512-qOpH55/+ZJ4jUu/oLO+ifUKjFPNZGfnPJtzvGzKN/4oLMil5m9OH4VpOj6++9/ytJcfks4kzH2hhi87GL/OU9A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz", + "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==", "dev": true, "requires": { "protocols": "^2.0.0" } }, "parse-url": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-7.0.2.tgz", - "integrity": "sha512-PqO4Z0eCiQ08Wj6QQmrmp5YTTxpYfONdOEamrtvK63AmzXpcavIVQubGHxOEwiIoDZFb8uDOoQFS0NCcjqIYQg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", + "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", "dev": true, "requires": { - "is-ssh": "^1.4.0", - "normalize-url": "^6.1.0", - "parse-path": "^5.0.0", - "protocols": "^2.0.1" + "parse-path": "^7.0.0" } }, "parseurl": { From a5ea3097aacb6052a030220bdf87131d4ae5d59b Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Mon, 26 Dec 2022 07:34:57 -0700 Subject: [PATCH 225/367] Prebid core: filter adUnits (by `adUnitCodes`) before sending them to RTD and FPD modules (#9355) --- src/prebid.js | 15 +++++++-------- test/spec/unit/pbjs_api_spec.js | 11 +++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/prebid.js b/src/prebid.js index a4abceb01d5..3fb131fb02c 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -629,6 +629,13 @@ $$PREBID_GLOBAL$$.requestBids = (function() { events.emit(REQUEST_BIDS); const cbTimeout = timeout || config.getConfig('bidderTimeout'); logInfo('Invoking $$PREBID_GLOBAL$$.requestBids', arguments); + if (adUnitCodes && adUnitCodes.length) { + // if specific adUnitCodes supplied filter adUnits for those codes + adUnits = adUnits.filter(unit => includes(adUnitCodes, unit.code)); + } else { + // otherwise derive adUnitCodes from adUnits + adUnitCodes = adUnits && adUnits.map(unit => unit.code); + } const ortb2Fragments = { global: mergeDeep({}, config.getAnyConfig('ortb2') || {}, ortb2 || {}), bidder: Object.fromEntries(Object.entries(config.getBidderConfig()).map(([bidder, cfg]) => [bidder, cfg.ortb2]).filter(([_, ortb2]) => ortb2 != null)) @@ -661,14 +668,6 @@ export const startAuction = hook('async', function ({ bidsBackHandler, timeout: const s2sBidders = getS2SBidderSet(config.getConfig('s2sConfig') || []); adUnits = useMetrics(metrics).measureTime('requestBids.validate', () => checkAdUnitSetup(adUnits)); - if (adUnitCodes && adUnitCodes.length) { - // if specific adUnitCodes supplied filter adUnits for those codes - adUnits = adUnits.filter(unit => includes(adUnitCodes, unit.code)); - } else { - // otherwise derive adUnitCodes from adUnits - adUnitCodes = adUnits && adUnits.map(unit => unit.code); - } - function auctionDone(bids, timedOut, auctionId) { if (typeof bidsBackHandler === 'function') { try { diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 9d8ea70e200..ae9ea09908a 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -1810,6 +1810,16 @@ describe('Unit: Prebid Module', function () { }) }); + it('filtering adUnits by adUnitCodes', () => { + $$PREBID_GLOBAL$$.requestBids({ + adUnits: [{code: 'one'}, {code: 'two'}], + adUnitCodes: 'two' + }); + sinon.assert.calledWith(startAuctionStub, sinon.match({ + adUnits: [{code: 'two'}] + })); + }); + it('passing bidder-specific FPD as ortb2Fragments.bidder', () => { configObj.setBidderConfig({ bidders: ['bidderA', 'bidderC'], @@ -1869,6 +1879,7 @@ describe('Unit: Prebid Module', function () { mediaTypes: {banner: {sizes: [[300, 250]]}}, bids: [{bidder: 'bd'}] }], + adUnitCodes: ['au'], ortb2Fragments }); sinon.assert.calledWith(newAuctionStub, sinon.match({ From fdab2f10459bb81fb61d4441a1c64ff749791d6b Mon Sep 17 00:00:00 2001 From: Jason Quaccia Date: Mon, 26 Dec 2022 06:36:12 -0800 Subject: [PATCH 226/367] Prebid Server: Include adUnitCode in PBS Adapter Requests (#9337) * changes * added support to pass adunitcode to pbs * updated comment * removed console log statements * addressed feedback --- .../pbsExtensions/processors/adUnitCode.js | 13 +++++++++++ libraries/pbsExtensions/processors/pbs.js | 5 ++++ .../prebidServerBidAdapter/ortbConverter.js | 1 + .../pbsExtensions/adUnitCode_spec.js | 23 +++++++++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 libraries/pbsExtensions/processors/adUnitCode.js create mode 100644 test/spec/ortbConverter/pbsExtensions/adUnitCode_spec.js diff --git a/libraries/pbsExtensions/processors/adUnitCode.js b/libraries/pbsExtensions/processors/adUnitCode.js new file mode 100644 index 00000000000..f936e0f662f --- /dev/null +++ b/libraries/pbsExtensions/processors/adUnitCode.js @@ -0,0 +1,13 @@ +import {deepSetValue} from '../../../src/utils.js'; + +export function setImpAdUnitCode(imp, bidRequest) { + const adUnitCode = bidRequest.adUnitCode; + + if (adUnitCode) { + deepSetValue( + imp, + `ext.prebid.adunitcode`, + adUnitCode + ); + } +} diff --git a/libraries/pbsExtensions/processors/pbs.js b/libraries/pbsExtensions/processors/pbs.js index 56a2a391c76..0ed2d12fad8 100644 --- a/libraries/pbsExtensions/processors/pbs.js +++ b/libraries/pbsExtensions/processors/pbs.js @@ -3,6 +3,7 @@ import {deepAccess, isPlainObject, isStr, mergeDeep} from '../../../src/utils.js import {extPrebidMediaType} from './mediaType.js'; import {setRequestExtPrebidAliases} from './aliases.js'; import {setImpBidParams} from './params.js'; +import {setImpAdUnitCode} from './adUnitCode.js'; import {setRequestExtPrebid, setRequestExtPrebidChannel} from './requestExtPrebid.js'; import {setBidResponseVideoCache} from './video.js'; @@ -26,6 +27,10 @@ export const PBS_PROCESSORS = { // sets bid ext.prebid.bidder.[bidderCode] with bidRequest.params, passed through transformBidParams if necessary fn: setImpBidParams }, + adUnitCode: { + // sets bid ext.prebid.adunitcode + fn: setImpAdUnitCode + } }, [BID_RESPONSE]: { mediaType: { diff --git a/modules/prebidServerBidAdapter/ortbConverter.js b/modules/prebidServerBidAdapter/ortbConverter.js index 0aee261c25d..83335f81bc2 100644 --- a/modules/prebidServerBidAdapter/ortbConverter.js +++ b/modules/prebidServerBidAdapter/ortbConverter.js @@ -246,6 +246,7 @@ export function buildPBSRequest(s2sBidRequest, bidderRequests, adUnits, requeste impIds.add(impId) proxyBidRequests.push({ ...adUnit, + adUnitCode: adUnit.code, ...getDefinedParams(actualBidRequests.values().next().value || {}, ['userId', 'userIdAsEids', 'schain']), pbsData: {impId, actualBidRequests, adUnit} }); diff --git a/test/spec/ortbConverter/pbsExtensions/adUnitCode_spec.js b/test/spec/ortbConverter/pbsExtensions/adUnitCode_spec.js new file mode 100644 index 00000000000..e17f9e856b0 --- /dev/null +++ b/test/spec/ortbConverter/pbsExtensions/adUnitCode_spec.js @@ -0,0 +1,23 @@ +import {setImpAdUnitCode} from '../../../../libraries/pbsExtensions/processors/adUnitCode.js'; + +describe('pbjs -> ortb adunit code to imp[].ext.prebid.adunitcode', () => { + function setImp(bidRequest) { + const imp = {}; + setImpAdUnitCode(imp, bidRequest); + return imp; + } + + it('it sets adunitcode in ext.prebid.adunitcode when adUnitCode is present', () => { + expect(setImp({bidder: 'mockBidder', adUnitCode: 'mockAdUnit'})).to.eql({ + 'ext': { + 'prebid': { + 'adunitcode': 'mockAdUnit' + } + } + }) + }); + + it('does not set adunitcode in ext.prebid.adunitcode if adUnit is undefined', () => { + expect(setImp({bidder: 'mockBidder'})).to.eql({}); + }); +}); From 5a424e4b992aabad0d5ffa0b87d66fc078790f5e Mon Sep 17 00:00:00 2001 From: couchcrew-thomas Date: Mon, 26 Dec 2022 15:47:35 +0100 Subject: [PATCH 227/367] Feedad Bid Adapter: fixed usersync parsing (#9353) * added file scaffold * added isBidRequestValid implementation * added local prototype of ad integration * added implementation for placement ID validation * fixed video context filter * applied lint to feedad bid adapter * added unit test for bid request validation * added buildRequest unit test * added unit tests for timeout and bid won callbacks * updated bid request to FeedAd API * added parsing of feedad api bid response * added transmisison of tracking events to FeedAd Api * code cleanup * updated feedad unit tests for buildRequest method * added unit tests for event tracking implementation * added unit test for interpretResponse method * added adapter documentation * added dedicated feedad example page * updated feedad adapter to use live system * updated FeedAd adapter placement ID regex * removed groups from FeedAd adapter placement ID regex * removed dedicated feedad example page * updated imports in FeedAd adapter file to use relative paths * updated FeedAd adapter unit test to use sinon.useFakeXMLHttpRequest() * added GDPR fields to the FeedAd bid request * removed video from supported media types of the FeedAd adapter * increased version code of FeedAd adapter to 1.0.2 * removed unnecessary check of bidder request * fixed unit test testing for old FeedAd version * removed video media type example from documentation file * added gvlid to FeedAd adapter * added decoration parameter to adapter documentation * added pass through of additional bid parameters * added user syncs to FeedAd bid adapter * increased FeedAd bid adapter version * lint pass over FeedAd bid adapter * fixed parsing of user syncs from server response * increased FeedAd bid adapter version * fixed version code in test file --- modules/feedadBidAdapter.js | 14 ++++-- test/spec/modules/feedadBidAdapter_spec.js | 51 ++++++++++++++++------ 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/modules/feedadBidAdapter.js b/modules/feedadBidAdapter.js index 0ab6def38ae..ef2e57c553f 100644 --- a/modules/feedadBidAdapter.js +++ b/modules/feedadBidAdapter.js @@ -7,7 +7,7 @@ import {ajax} from '../src/ajax.js'; * Version of the FeedAd bid adapter * @type {string} */ -const VERSION = '1.0.3'; +const VERSION = '1.0.4'; /** * @typedef {object} FeedAdApiBidRequest @@ -294,12 +294,20 @@ function trackingHandlerFactory(klass) { /** * Reads the user syncs off the server responses and converts them into Prebid.JS format * @param {SyncOptions} syncOptions - * @param {FeedAdApiBidResponse[]} serverResponses + * @param {ServerResponse[]} serverResponses * @param gdprConsent * @param uspConsent */ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { - return serverResponses.map(response => response.ext) + return serverResponses.map(response => { + // validate response format + const ext = deepAccess(response, 'body.ext', []); + if (ext == null) { + return null; + } + return ext; + }) + .filter(ext => ext != null) .flatMap(extension => { // extract user syncs from extension const pixels = syncOptions.pixelEnabled && extension.pixels ? extension.pixels : []; diff --git a/test/spec/modules/feedadBidAdapter_spec.js b/test/spec/modules/feedadBidAdapter_spec.js index 6db0b88a9bf..6aed670a563 100644 --- a/test/spec/modules/feedadBidAdapter_spec.js +++ b/test/spec/modules/feedadBidAdapter_spec.js @@ -358,14 +358,20 @@ describe('FeedAdAdapter', function () { const pixelSync2 = {type: 'image', url: 'the pixel url 2'}; const iFrameSync1 = {type: 'iframe', url: 'the iFrame url 1'}; const iFrameSync2 = {type: 'iframe', url: 'the iFrame url 2'}; + const mockServerResponse = (content) => { + if (!(content instanceof Array)) { + content = [content]; + } + return content.map(it => ({body: it})); + }; it('should pass through the syncs out of the extension fields of the server response', function () { - const serverResponse = [{ + const serverResponse = mockServerResponse([{ ext: { pixels: [pixelSync1, pixelSync2], iframes: [iFrameSync1, iFrameSync2], } - }]; + }]); const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse) expect(result).to.deep.equal([ pixelSync1, @@ -376,7 +382,7 @@ describe('FeedAdAdapter', function () { }); it('should concat the syncs of all responses', function () { - const serverResponse = [{ + const serverResponse = mockServerResponse([{ ext: { pixels: [pixelSync1], iframes: [iFrameSync2], @@ -391,7 +397,7 @@ describe('FeedAdAdapter', function () { ext: { pixels: [pixelSync2], } - }]; + }]); const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse); expect(result).to.deep.equal([ pixelSync1, @@ -402,7 +408,7 @@ describe('FeedAdAdapter', function () { }); it('should filter out duplicates', function () { - const serverResponse = [{ + const serverResponse = mockServerResponse([{ ext: { pixels: [pixelSync1, pixelSync1], iframes: [iFrameSync2, iFrameSync2], @@ -411,7 +417,7 @@ describe('FeedAdAdapter', function () { ext: { iframes: [iFrameSync2, iFrameSync2], } - }]; + }]); const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse); expect(result).to.deep.equal([ pixelSync1, @@ -420,12 +426,12 @@ describe('FeedAdAdapter', function () { }); it('should not include iFrame syncs if the option is disabled', function () { - const serverResponse = [{ + const serverResponse = mockServerResponse([{ ext: { pixels: [pixelSync1, pixelSync2], iframes: [iFrameSync1, iFrameSync2], } - }]; + }]); const result = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, serverResponse); expect(result).to.deep.equal([ pixelSync1, @@ -434,12 +440,12 @@ describe('FeedAdAdapter', function () { }); it('should not include pixel syncs if the option is disabled', function () { - const serverResponse = [{ + const serverResponse = mockServerResponse([{ ext: { pixels: [pixelSync1, pixelSync2], iframes: [iFrameSync1, iFrameSync2], } - }]; + }]); const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, serverResponse); expect(result).to.deep.equal([ iFrameSync1, @@ -448,15 +454,34 @@ describe('FeedAdAdapter', function () { }); it('should not include any syncs if the sync options are disabled or missing', function () { - const serverResponse = [{ + const serverResponse = mockServerResponse([{ ext: { pixels: [pixelSync1, pixelSync2], iframes: [iFrameSync1, iFrameSync2], } - }]; + }]); const result = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false}, serverResponse); expect(result).to.deep.equal([]); }); + + it('should handle empty responses', function () { + const serverResponse = mockServerResponse([]); + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse) + expect(result).to.deep.equal([]); + }); + + it('should not throw if the server response is weird', function () { + const responses = [ + mockServerResponse(null), + mockServerResponse('null'), + mockServerResponse(1234), + mockServerResponse({}), + mockServerResponse([{}, 123]), + ]; + responses.forEach(it => { + expect(() => spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, it)).not.to.throw; + }); + }); }); describe('event tracking calls', function () { @@ -592,7 +617,7 @@ describe('FeedAdAdapter', function () { prebid_bid_id: bidId, prebid_transaction_id: transactionId, referer, - sdk_version: '1.0.3' + sdk_version: '1.0.4' }; subject(data); expect(server.requests.length).to.equal(1); From f794bce175d49bab6da6435d41335fb2fbf45c9c Mon Sep 17 00:00:00 2001 From: vishal-dw <109065778+vishal-dw@users.noreply.github.com> Date: Mon, 26 Dec 2022 14:49:46 +0000 Subject: [PATCH 228/367] Datawrkz adapter: Using bidRequest.getFloor() method for bid floor (#9366) * New Bid Adapter: datawrkz * New Bid Adapter: datawrkz. Test case formatting * New Bid Adatpter: datawrkz - updated import statements * Datawrkz adapter: Using bidRequest.getFloor() method for bid floor --- modules/datawrkzBidAdapter.js | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/modules/datawrkzBidAdapter.js b/modules/datawrkzBidAdapter.js index 71870d6437d..193a1723403 100644 --- a/modules/datawrkzBidAdapter.js +++ b/modules/datawrkzBidAdapter.js @@ -1,4 +1,4 @@ -import { deepAccess, getBidIdParameter, isArray, getUniqueIdentifierStr, contains } from '../src/utils.js'; +import { deepAccess, getBidIdParameter, isArray, getUniqueIdentifierStr, contains, isFn, isPlainObject } from '../src/utils.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; @@ -84,7 +84,7 @@ export const spec = { /* Generate bid request for banner adunit */ function buildBannerRequest(bidRequest, bidderRequest) { - let bidFloor = Number(getBidIdParameter('bidfloor', bidRequest.params)); + let bidFloor = getBidFloor(bidRequest); let adW = 0; let adH = 0; @@ -135,7 +135,7 @@ function buildNativeRequest(bidRequest, bidderRequest) { let counter = 0; let assets = []; - let bidFloor = Number(getBidIdParameter('bidfloor', bidRequest.params)); + let bidFloor = getBidFloor(bidRequest); let title = deepAccess(bidRequest, 'mediaTypes.native.title'); if (title && title.len) { @@ -196,7 +196,7 @@ function buildNativeRequest(bidRequest, bidderRequest) { /* Generate bid request for video adunit */ function buildVideoRequest(bidRequest, bidderRequest) { - let bidFloor = Number(getBidIdParameter('bidfloor', bidRequest.params)); + let bidFloor = getBidFloor(bidRequest); let sizeObj = getVideoAdUnitSize(bidRequest); @@ -414,6 +414,7 @@ function buildBannerResponse(bidRequest, bidResponse) { } let bidSizes = (deepAccess(bidRequest, 'mediaTypes.banner.sizes')) ? deepAccess(bidRequest, 'mediaTypes.banner.sizes') : bidRequest.sizes; bidResponse.requestId = bidRequest.bidId; + bidResponse.auctionId = bidRequest.auctionId; bidResponse.transactionId = bidRequest.transactionId; bidResponse.placementCode = placementCode; bidResponse.cpm = responseCPM; @@ -455,6 +456,7 @@ function buildNativeResponse(bidRequest, response) { return; } bidResponse.requestId = bidRequest.bidId; + bidResponse.auctionId = bidRequest.auctionId; bidResponse.transactionId = bidRequest.transactionId; bidResponse.placementCode = placementCode; bidResponse.cpm = responseCPM; @@ -507,6 +509,7 @@ function buildVideoResponse(bidRequest, response) { let context = bidRequest.mediaTypes.video.context; bidResponse.requestId = bidRequest.bidId; + bidResponse.auctionId = bidRequest.auctionId; bidResponse.transactionId = bidRequest.transactionId; bidResponse.placementCode = placementCode; bidResponse.cpm = responseCPM; @@ -630,4 +633,21 @@ function getNativeAssestObj(obj, assets) { } } +// BUILD REQUESTS: BIDFLOORS +function getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return (bid.params.bidfloor) ? bid.params.bidfloor : null; + } + + let floor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*' + }); + if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') { + return floor.floor; + } + return null; +} + registerBidder(spec); From b6f9b2effb5c9a51eacc1398f69c5001ab87a14e Mon Sep 17 00:00:00 2001 From: Denis Logachov Date: Mon, 26 Dec 2022 22:35:09 +0200 Subject: [PATCH 229/367] Adkernel Bid Adapter: bidbuddy.co.in alias (#9375) --- modules/adkernelBidAdapter.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js index b0449418a87..5736c7c19ba 100644 --- a/modules/adkernelBidAdapter.js +++ b/modules/adkernelBidAdapter.js @@ -97,7 +97,8 @@ export const spec = { {code: 'motionspots'}, {code: 'sonic_twist'}, {code: 'displayioads'}, - {code: 'rtbdemand_com'} + {code: 'rtbdemand_com'}, + {code: 'bidbuddy'} ], supportedMediaTypes: [BANNER, VIDEO, NATIVE], From 86ed8f0057fa3cb611f3fc0855244d5981d0a2b0 Mon Sep 17 00:00:00 2001 From: denys-berzoy-confiant <50574764+denys-berzoy-confiant@users.noreply.github.com> Date: Tue, 27 Dec 2022 05:58:33 +0300 Subject: [PATCH 230/367] Confiant RTD Module : initial release (#9325) * Confiant's RTD Provider Module * Confiant RTD Module: - updated script injection code to current standard - added Confiant as an exclusion to load external JS * Confiant RTD Provider: - additional param for enabling BillingEvent added - docs updated - outdated unit test removed Co-authored-by: Patrick McCann --- modules/.submodules.json | 1 + modules/confiantRtdProvider.js | 128 ++++++++++++++++++ modules/confiantRtdProvider.md | 45 ++++++ src/adloader.js | 3 +- test/spec/modules/confiantRtdProvider_spec.js | 107 +++++++++++++++ 5 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 modules/confiantRtdProvider.js create mode 100644 modules/confiantRtdProvider.md create mode 100644 test/spec/modules/confiantRtdProvider_spec.js diff --git a/modules/.submodules.json b/modules/.submodules.json index c3016914f1b..deeee91e247 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -58,6 +58,7 @@ "blueconicRtdProvider", "browsiRtdProvider", "captifyRtdProvider", + "confiantRtdProvider", "dgkeywordRtdProvider", "geoedgeRtdProvider", "hadronRtdProvider", diff --git a/modules/confiantRtdProvider.js b/modules/confiantRtdProvider.js new file mode 100644 index 00000000000..4a524b92d75 --- /dev/null +++ b/modules/confiantRtdProvider.js @@ -0,0 +1,128 @@ +/** + * This module provides comprehensive detection of security, quality, and privacy threats by Confiant Inc, + * the industry leader in real-time detecting and blocking of bad ads + * + * The {@link module:modules/realTimeData} module is required + * The module will inject a Confiant Inc. script into the page to monitor ad impressions + * @module modules/cleanioRtdProvider + * @requires module:modules/realTimeData + */ + +import { submodule } from '../src/hook.js'; +import { logError, generateUUID } from '../src/utils.js'; +import { loadExternalScript } from '../src/adloader.js'; +import * as events from '../src/events.js'; +import CONSTANTS from '../src/constants.json'; + +/** + * Injects the Confiant Inc. configuration script into the page, based on proprtyId provided + * @param {string} propertyId + */ +function injectConfigScript(propertyId) { + const scriptSrc = `https://cdn.confiant-integrations.net/${propertyId}/gpt_and_prebid/config.js`; + + loadExternalScript(scriptSrc, 'confiant', () => {}); +} + +/** + * Set up page with Confiant integration + * @param {Object} config + */ +function setupPage(config) { + const propertyId = config?.params?.propertyId; + if (!propertyId) { + logError('Confiant pbjs module: no propertyId provided'); + return false; + } + + const confiant = window.confiant || Object.create(null); + confiant[propertyId] = confiant[propertyId] || Object.create(null); + confiant[propertyId].clientSettings = confiant[propertyId].clientSettings || Object.create(null); + confiant[propertyId].clientSettings.isMGBL = true; + confiant[propertyId].clientSettings.prebidExcludeBidders = config?.params?.prebidExcludeBidders; + confiant[propertyId].clientSettings.prebidNameSpace = config?.params?.prebidNameSpace; + + if (config?.params?.shouldEmitBillableEvent) { + if (window.frames['cnftComm']) { + subscribeToConfiantCommFrame(window); + } else { + setUpMutationObserver(); + } + } + + injectConfigScript(propertyId); + return true; +} + +/** + * Subscribe to window's message events to report Billable events + * @param {Window} targetWindow window instance to subscribe to + */ +function subscribeToConfiantCommFrame(targetWindow) { + targetWindow.addEventListener('message', reportBillableEvents); +} + +let mutationObserver; +/** + * Set up mutation observer to subscribe to Confiant's communication channel ASAP + */ +function setUpMutationObserver() { + mutationObserver = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + mutation.addedNodes.forEach((addedNode) => { + if (addedNode.nodeName === 'IFRAME' && addedNode.name === 'cnftComm' && !addedNode.pbjsModuleSubscribed) { + addedNode.pbjsModuleSubscribed = true; + mutationObserver.disconnect(); + mutationObserver = null; + const iframeWindow = addedNode.contentWindow; + subscribeToConfiantCommFrame(iframeWindow); + } + }); + }); + }); + mutationObserver.observe(document.head, { childList: true, subtree: true }); +} + +/** + * Emit billable event when Confiant integration reports that it has monitored an impression + */ +function reportBillableEvents (e) { + events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + auctionId: e.data.auctionId, + billingId: generateUUID(), + transactionId: e.data.transactionId, + type: 'impression', + vendor: 'confiant' + }); +} + +/** + * Confiant submodule registration + */ +function registerConfiantSubmodule() { + submodule('realTimeData', { + name: 'confiant', + init: (config) => { + try { + return setupPage(config); + } catch (err) { + logError(err.message); + if (mutationObserver) { + mutationObserver.disconnect(); + } + return false; + } + } + }); +} + +registerConfiantSubmodule(); + +export default { + injectConfigScript, + setupPage, + subscribeToConfiantCommFrame, + setUpMutationObserver, + reportBillableEvents, + registerConfiantSubmodule +}; diff --git a/modules/confiantRtdProvider.md b/modules/confiantRtdProvider.md new file mode 100644 index 00000000000..e92c0aabcba --- /dev/null +++ b/modules/confiantRtdProvider.md @@ -0,0 +1,45 @@ +# Overview + +``` +Module Name: Confiant Inc. Rtd provider +Module Type: Rtd Provider +Maintainer: +``` + +Confiant’s module provides comprehensive detection of security, quality, and privacy threats across your ad stack. +Confiant is the industry leader in real-time detecting and blocking of bad ads when it comes to protecting your users and brand reputation. + +To start using this module, please contact [Confiant](https://www.confiant.com/contact) to get an account and customer key. + + +# Integration + +1) Build Prebid bundle with Confiant module included: + + +``` +gulp build --modules=confiantRtdProvider,... +``` + +2) Include the resulting bundle on your page. + +# Configuration + +Configuration of Confiant module is plain simple: + +```javascript +pbjs.setConfig({ + realTimeData: { + dataProviders: [{ + name: 'confiant', + params: { + // so please get in touch with us so we could help you to set up the module with proper parameters + propertyId: '', // required, string param, obtained from Confiant Inc. + prebidExcludeBidders: '', // optional, comma separated list of bidders to exclude from Confiant's prebid.js integration + prebidNameSpace: '', // optional, string param, namespace for prebid.js integration + shouldEmitBillableEvent: false, // optional, boolean param, upon being set to true enables firing of the BillableEvent upon Confiant's impression scanning + } + }] + } +}); +``` diff --git a/src/adloader.js b/src/adloader.js index 64408683e9f..01a77971b93 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -20,7 +20,8 @@ const _approvedLoadExternalJSList = [ 'hadron', 'medianet', 'improvedigital', - 'aaxBlockmeter' + 'aaxBlockmeter', + 'confiant' ] /** diff --git a/test/spec/modules/confiantRtdProvider_spec.js b/test/spec/modules/confiantRtdProvider_spec.js new file mode 100644 index 00000000000..987aca2e020 --- /dev/null +++ b/test/spec/modules/confiantRtdProvider_spec.js @@ -0,0 +1,107 @@ +import * as utils from '../../../src/utils.js'; +import * as hook from '../../../src/hook.js' +import * as events from '../../../src/events.js'; +import CONSTANTS from '../../../src/constants.json'; + +import confiantModule from '../../../modules/confiantRtdProvider.js'; + +const { + injectConfigScript, + setupPage, + subscribeToConfiantCommFrame, + registerConfiantSubmodule +} = confiantModule; + +describe('Confiant RTD module', function () { + describe('setupPage()', function() { + it('should return false if propertId is not present in config', function() { + expect(setupPage({})).to.be.false; + expect(setupPage({ params: {} })).to.be.false; + expect(setupPage({ params: { propertyId: '' } })).to.be.false; + }); + + it('should return true if expected parameters are present', function() { + expect(setupPage({ params: { propertyId: 'clientId' } })).to.be.true; + }); + }); + + describe('Module initialization', function() { + let insertElementStub; + beforeEach(function() { + insertElementStub = sinon.stub(utils, 'insertElement'); + }); + afterEach(function() { + utils.insertElement.restore(); + }); + + it('should subscribe to rovided Window object', function () { + const mockWindow = { addEventListener: sinon.spy() }; + + subscribeToConfiantCommFrame(mockWindow); + + sinon.assert.calledOnce(mockWindow.addEventListener); + }); + + it('should fire BillableEvent as a result for message in comm window', function() { + let listenerCallback; + const mockWindow = { addEventListener: (a, cb) => (listenerCallback = cb) }; + let billableEventsCounter = 0; + + events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, (e) => { + if (e.vendor === 'confiant') { + billableEventsCounter++; + expect(e.type).to.equal('impression'); + expect(e.billingId).to.be.a('number'); + expect(e.auctionId).to.equal('auctionId'); + expect(e.transactionId).to.equal('transactionId'); + } + }); + + subscribeToConfiantCommFrame(mockWindow); + listenerCallback({ + data: { + auctionId: 'auctionId', + transactionId: 'transactionId' + } + }); + listenerCallback({ + data: { + auctionId: 'auctionId', + transactionId: 'transactionId' + } + }); + + expect(billableEventsCounter).to.equal(2); + }); + }); + + describe('Sumbodule execution', function() { + let submoduleStub; + let insertElementStub; + beforeEach(function () { + submoduleStub = sinon.stub(hook, 'submodule'); + insertElementStub = sinon.stub(utils, 'insertElement'); + }); + afterEach(function () { + utils.insertElement.restore(); + submoduleStub.restore(); + }); + + function initModule() { + registerConfiantSubmodule(); + + expect(submoduleStub.calledOnceWith('realTimeData')).to.equal(true); + + const registeredSubmoduleDefinition = submoduleStub.getCall(0).args[1]; + expect(registeredSubmoduleDefinition).to.be.an('object'); + expect(registeredSubmoduleDefinition).to.have.own.property('name', 'confiant'); + expect(registeredSubmoduleDefinition).to.have.own.property('init').that.is.a('function'); + + return registeredSubmoduleDefinition; + } + + it('should register Confiant submodule', function () { + initModule(); + }); + }); +}); From 10cf68607b0e6a646fb5c16b67defa8710811941 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Wed, 28 Dec 2022 17:11:36 +0000 Subject: [PATCH 231/367] Prebid 7.31.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b703493403..c2405970bde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.31.0-pre", + "version": "7.31.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index f96909cc6b4..52138286c36 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.31.0-pre", + "version": "7.31.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From e13592697d17a110e6e94ecc6b2c907cb89eb45c Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Wed, 28 Dec 2022 17:11:36 +0000 Subject: [PATCH 232/367] Increment version to 7.32.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c2405970bde..4bfd2cea1f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.31.0", + "version": "7.32.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 52138286c36..10da88d1c6f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.31.0", + "version": "7.32.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From ff98601bdc868c98627ba023e2907f1611eec6c5 Mon Sep 17 00:00:00 2001 From: denys-berzoy-confiant <50574764+denys-berzoy-confiant@users.noreply.github.com> Date: Wed, 28 Dec 2022 23:38:46 +0300 Subject: [PATCH 233/367] Confiant RTD Provider: (#9382) - fix comment line --- modules/confiantRtdProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/confiantRtdProvider.js b/modules/confiantRtdProvider.js index 4a524b92d75..2c13ad87d75 100644 --- a/modules/confiantRtdProvider.js +++ b/modules/confiantRtdProvider.js @@ -4,7 +4,7 @@ * * The {@link module:modules/realTimeData} module is required * The module will inject a Confiant Inc. script into the page to monitor ad impressions - * @module modules/cleanioRtdProvider + * @module modules/confiantRtdProvider * @requires module:modules/realTimeData */ From 0caca74e57de50daf23854cbeccdd57ecac7a621 Mon Sep 17 00:00:00 2001 From: inna Date: Thu, 29 Dec 2022 15:39:33 +0200 Subject: [PATCH 234/367] Rise Bid Adapter: added isWrapper parameter to adapter request (#9329) * add Rise adapter * fixes * change param isOrg to org * Rise adapter * change email for rise * fix circle failed * bump * bump * bump * remove space * Upgrade Rise adapter to 5.0 * added isWrapper param * addes is_wrapper parameter to documentation * added is_wrapper to test * removed isWrapper Co-authored-by: Noam Tzuberi Co-authored-by: noamtzu Co-authored-by: Noam Tzuberi Co-authored-by: Laslo Chechur Co-authored-by: OronW <41260031+OronW@users.noreply.github.com> Co-authored-by: lasloche <62240785+lasloche@users.noreply.github.com> --- modules/riseBidAdapter.js | 3 ++- modules/riseBidAdapter.md | 2 ++ test/spec/modules/riseBidAdapter_spec.js | 7 +++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/riseBidAdapter.js b/modules/riseBidAdapter.js index 4325a699a3b..0c4d6148f2b 100644 --- a/modules/riseBidAdapter.js +++ b/modules/riseBidAdapter.js @@ -400,7 +400,8 @@ function generateGeneralParams(generalObject, bidderRequest) { dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0, device_type: getDeviceType(navigator.userAgent), ua: navigator.userAgent, - session_id: getBidIdParameter('auctionId', generalObject), + is_wrapper: !!generalBidParams.isWrapper, + session_id: generalBidParams.sessionId || getBidIdParameter('auctionId', generalObject), tmax: timeout }; diff --git a/modules/riseBidAdapter.md b/modules/riseBidAdapter.md index 9dab3ec2a30..f0837cb5508 100644 --- a/modules/riseBidAdapter.md +++ b/modules/riseBidAdapter.md @@ -25,6 +25,8 @@ The adapter supports Video(instream). | `placementId` | optional | String | A unique placement identifier | "12345678" | `testMode` | optional | Boolean | This activates the test mode | false | `rtbDomain` | optional | String | Sets the seller end point | "www.test.com" +| `is_wrapper` | private | Boolean | Please don't use unless your account manager asked you to | false + # Test Parameters ```javascript diff --git a/test/spec/modules/riseBidAdapter_spec.js b/test/spec/modules/riseBidAdapter_spec.js index 37100073407..4fa4ff354ec 100644 --- a/test/spec/modules/riseBidAdapter_spec.js +++ b/test/spec/modules/riseBidAdapter_spec.js @@ -116,6 +116,13 @@ describe('riseAdapter', function () { expect(request.data.bids[0].placementId).to.equal(placementId); }); + it('sends the is_wrapper parameter to ENDPOINT via POST', function() { + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.params).to.be.an('object'); + expect(request.data.params).to.have.property('is_wrapper'); + expect(request.data.params.is_wrapper).to.equal(false); + }); + it('sends bid request to ENDPOINT via POST', function () { const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.url).to.equal(ENDPOINT); From 0b1ba0cecf0d7dd796a0a661c0ecb8f582f55a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udi=20Talias=20=E2=9A=9B=EF=B8=8F?= Date: Thu, 29 Dec 2022 20:12:48 +0200 Subject: [PATCH 235/367] Added video media type support (#9326) --- modules/kueezRtbBidAdapter.js | 29 +++- test/spec/modules/kueezRtbBidAdapter_spec.js | 171 ++++++++++++++++--- 2 files changed, 168 insertions(+), 32 deletions(-) diff --git a/modules/kueezRtbBidAdapter.js b/modules/kueezRtbBidAdapter.js index 1ee3b7331cb..4b0e5055328 100644 --- a/modules/kueezRtbBidAdapter.js +++ b/modules/kueezRtbBidAdapter.js @@ -1,6 +1,6 @@ import { _each, deepAccess, parseSizesInput, parseUrl, uniques, isFn } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER } from '../src/mediaTypes.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { getStorageManager } from '../src/storageManager.js'; const GVLID = 1165; @@ -55,7 +55,7 @@ function isBidRequestValid(bid) { } function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { - const { params, bidId, userId, adUnitCode, schain } = bid; + const { params, bidId, userId, adUnitCode, schain, mediaTypes } = bid; let { bidFloor, ext } = params; const hashUrl = hashCode(topWindowUrl); const uniqueDealId = getUniqueDealId(hashUrl); @@ -89,7 +89,8 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { bidderVersion: BIDDER_VERSION, prebidVersion: '$prebid.version$', res: `${screen.width}x${screen.height}`, - schain: schain + schain: schain, + mediaTypes: mediaTypes }; appendUserIdsToRequestPayload(data, userId); @@ -167,11 +168,12 @@ function interpretResponse(serverResponse, request) { try { results.forEach(result => { - const { creativeId, ad, price, exp, width, height, currency, advertiserDomains } = result; + const { creativeId, ad, price, exp, width, height, currency, advertiserDomains, mediaType = BANNER } = result; if (!ad || !price) { return; } - output.push({ + + const response = { requestId: bidId, cpm: price, width: width, @@ -180,11 +182,22 @@ function interpretResponse(serverResponse, request) { currency: currency || CURRENCY, netRevenue: true, ttl: exp || TTL_SECONDS, - ad: ad, meta: { advertiserDomains: advertiserDomains || [] } - }) + }; + + if (mediaType === BANNER) { + Object.assign(response, { + ad: ad, + }); + } else { + Object.assign(response, { + vastXml: ad, + mediaType: VIDEO + }); + } + output.push(response); }); return output; } catch (e) { @@ -268,7 +281,7 @@ export const spec = { code: BIDDER_CODE, version: BIDDER_VERSION, gvlid: GVLID, - supportedMediaTypes: [BANNER], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid, buildRequests, interpretResponse, diff --git a/test/spec/modules/kueezRtbBidAdapter_spec.js b/test/spec/modules/kueezRtbBidAdapter_spec.js index f9b2cd41a43..30b2a46cefb 100644 --- a/test/spec/modules/kueezRtbBidAdapter_spec.js +++ b/test/spec/modules/kueezRtbBidAdapter_spec.js @@ -1,4 +1,4 @@ -import {expect} from 'chai'; +import { expect } from 'chai'; import { spec as adapter, SUPPORTED_ID_SYSTEMS, @@ -13,8 +13,9 @@ import { getUniqueDealId, } from 'modules/kueezRtbBidAdapter.js'; import * as utils from 'src/utils.js'; -import {version} from 'package.json'; -import {useFakeTimers} from 'sinon'; +import { version } from 'package.json'; +import { useFakeTimers } from 'sinon'; +import { BANNER, VIDEO } from '../../../src/mediaTypes'; const SUB_DOMAIN = 'exchange'; @@ -36,9 +37,42 @@ const BID = { 'sizes': [[300, 250], [300, 600]], 'bidderRequestId': '1fdb5ff1b6eaa7', 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', - 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc' + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'mediaTypes': [BANNER] }; +const VIDEO_BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560', + 'bidderRequestId': '12a8ae9ada9c13', + 'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee', + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '635509f7ff6642d368cb9837', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1 + }, + 'sizes': [[545, 307]], + 'mediaTypes': { + 'video': { + 'playerSize': [[545, 307]], + 'context': 'instream', + 'mimes': [ + 'video/mp4', + 'application/javascript' + ], + 'protocols': [2, 3, 5, 6], + 'maxduration': 60, + 'minduration': 0, + 'startdelay': 0, + 'linearity': 1, + 'api': [2], + 'placement': 1 + } + } +} + const BIDDER_REQUEST = { 'gdprConsent': { 'consentString': 'consent_string', @@ -73,6 +107,23 @@ const SERVER_RESPONSE = { } }; +const VIDEO_SERVER_RESPONSE = { + body: { + 'cid': '635509f7ff6642d368cb9837', + 'results': [{ + 'ad': '', + 'advertiserDomains': ['kueezrtb.com'], + 'exp': 60, + 'width': 545, + 'height': 307, + 'mediaType': 'video', + 'creativeId': '12610997325162499419', + 'price': 2, + 'cookies': [] + }] + } +}; + const REQUEST = { data: { width: 300, @@ -83,7 +134,7 @@ const REQUEST = { function getTopWindowQueryParams() { try { - const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true}); + const parsedUrl = utils.parseUrl(window.top.document.URL, { decodeSearchAsString: true }); return parsedUrl.search; } catch (e) { return ''; @@ -111,6 +162,11 @@ describe('KueezRtbBidAdapter', function () { it('exists and is a string', function () { expect(adapter.code).to.exist.and.to.be.a('string'); }); + + it('exists and contains media types', function () { + expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2); + expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]); + }); }); describe('validate bid requests', function () { @@ -155,7 +211,53 @@ describe('KueezRtbBidAdapter', function () { sandbox.stub(Date, 'now').returns(1000); }); - it('should build request for each size', function () { + it('should build video request', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`, + data: { + adUnitCode: '63550ad1ff6642d368cba59dh5884270560', + bidFloor: 0.1, + bidId: '2d52001cabd527', + bidderVersion: adapter.version, + cb: 1000, + gdpr: 1, + gdprConsent: 'consent_string', + usPrivacy: 'consent_string', + prebidVersion: version, + publisherId: '59ac17c192832d0011283fe3', + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + res: `${window.top.screen.width}x${window.top.screen.height}`, + schain: VIDEO_BID.schain, + sizes: ['545x307'], + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + uqs: getTopWindowQueryParams(), + mediaTypes: { + video: { + api: [2], + context: 'instream', + linearity: 1, + maxduration: 60, + mimes: [ + 'video/mp4', + 'application/javascript' + ], + minduration: 0, + placement: 1, + playerSize: [[545, 307]], + protocols: [2, 3, 5, 6], + startdelay: 0 + } + } + } + }); + }); + + it('should build banner request for each size', function () { const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); const requests = adapter.buildRequests([BID], BIDDER_REQUEST); expect(requests).to.have.length(1); @@ -179,6 +281,7 @@ describe('KueezRtbBidAdapter', function () { prebidVersion: version, schain: BID.schain, res: `${window.top.screen.width}x${window.top.screen.height}`, + mediaTypes: [BANNER], uqs: getTopWindowQueryParams(), 'ext.param1': 'loremipsum', 'ext.param2': 'dolorsitamet', @@ -193,7 +296,7 @@ describe('KueezRtbBidAdapter', function () { }); describe('getUserSyncs', function () { it('should have valid user sync with iframeEnabled', function () { - const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ type: 'iframe', @@ -202,7 +305,7 @@ describe('KueezRtbBidAdapter', function () { }); it('should have valid user sync with cid on response', function () { - const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ type: 'iframe', url: 'https://sync.kueezrtb.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' @@ -210,7 +313,7 @@ describe('KueezRtbBidAdapter', function () { }); it('should have valid user sync with pixelEnabled', function () { - const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({ pixelEnabled: true }, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ 'url': 'https://sync.kueezrtb.com/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=', @@ -226,16 +329,16 @@ describe('KueezRtbBidAdapter', function () { }); it('should return empty array when there is no ad', function () { - const responses = adapter.interpretResponse({price: 1, ad: ''}); + const responses = adapter.interpretResponse({ price: 1, ad: '' }); expect(responses).to.be.empty; }); it('should return empty array when there is no price', function () { - const responses = adapter.interpretResponse({price: null, ad: 'great ad'}); + const responses = adapter.interpretResponse({ price: null, ad: 'great ad' }); expect(responses).to.be.empty; }); - it('should return an array of interpreted responses', function () { + it('should return an array of interpreted banner responses', function () { const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST); expect(responses).to.have.length(1); expect(responses[0]).to.deep.equal({ @@ -254,6 +357,26 @@ describe('KueezRtbBidAdapter', function () { }); }); + it('should return an array of interpreted video responses', function () { + const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 2, + width: 545, + height: 307, + mediaType: 'video', + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 60, + vastXml: '', + meta: { + advertiserDomains: ['kueezrtb.com'] + } + }); + }); + it('should take default TTL', function () { const serverResponse = utils.deepClone(SERVER_RESPONSE); delete serverResponse.body.results[0].exp; @@ -271,11 +394,11 @@ describe('KueezRtbBidAdapter', function () { const userId = (function () { switch (idSystemProvider) { case 'lipb': - return {lipbid: id}; + return { lipbid: id }; case 'parrableId': - return {eid: id}; + return { eid: id }; case 'id5id': - return {uid: id}; + return { uid: id }; default: return id; } @@ -294,18 +417,18 @@ describe('KueezRtbBidAdapter', function () { describe('alternate param names extractors', function () { it('should return undefined when param not supported', function () { - const cid = extractCID({'c_id': '1'}); - const pid = extractPID({'p_id': '1'}); - const subDomain = extractSubDomain({'sub_domain': 'prebid'}); + const cid = extractCID({ 'c_id': '1' }); + const pid = extractPID({ 'p_id': '1' }); + const subDomain = extractSubDomain({ 'sub_domain': 'prebid' }); expect(cid).to.be.undefined; expect(pid).to.be.undefined; expect(subDomain).to.be.undefined; }); it('should return value when param supported', function () { - const cid = extractCID({'cID': '1'}); - const pid = extractPID({'Pid': '2'}); - const subDomain = extractSubDomain({'subDOMAIN': 'prebid'}); + const cid = extractCID({ 'cID': '1' }); + const pid = extractPID({ 'Pid': '2' }); + const subDomain = extractSubDomain({ 'subDOMAIN': 'prebid' }); expect(cid).to.be.equal('1'); expect(pid).to.be.equal('2'); expect(subDomain).to.be.equal('prebid'); @@ -365,7 +488,7 @@ describe('KueezRtbBidAdapter', function () { now }); setStorageItem('myKey', 2020); - const {value, created} = getStorageItem('myKey'); + const { value, created } = getStorageItem('myKey'); expect(created).to.be.equal(now); expect(value).to.be.equal(2020); expect(typeof value).to.be.equal('number'); @@ -381,8 +504,8 @@ describe('KueezRtbBidAdapter', function () { }); it('should parse JSON value', function () { - const data = JSON.stringify({event: 'send'}); - const {event} = tryParseJSON(data); + const data = JSON.stringify({ event: 'send' }); + const { event } = tryParseJSON(data); expect(event).to.be.equal('send'); }); From 57555bc4a0b916bd32dbcdf5030d3ead20a103d1 Mon Sep 17 00:00:00 2001 From: "Adserver.Online" <61009237+adserver-online@users.noreply.github.com> Date: Tue, 3 Jan 2023 17:22:48 +0200 Subject: [PATCH 236/367] Aso Bid Adapter: add bcmint alias (#9387) * Add bcmint alias * kick off tests Co-authored-by: dev Co-authored-by: Chris Huie --- modules/asoBidAdapter.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/asoBidAdapter.js b/modules/asoBidAdapter.js index 83b182e4ca5..39c42f193b2 100644 --- a/modules/asoBidAdapter.js +++ b/modules/asoBidAdapter.js @@ -10,11 +10,11 @@ import { parseSizesInput, tryAppendQueryString } from '../src/utils.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {config} from '../src/config.js'; -import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {Renderer} from '../src/Renderer.js'; -import {parseDomain} from '../src/refererDetection.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { Renderer } from '../src/Renderer.js'; +import { parseDomain } from '../src/refererDetection.js'; const BIDDER_CODE = 'aso'; const DEFAULT_SERVER_URL = 'https://srv.aso1.net'; @@ -27,6 +27,9 @@ export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO], + aliases: [ + {code: 'bcmint'} + ], isBidRequestValid: bid => { return !!bid.params && !!bid.params.zone; From ccc9bba348275e941d39ea32284d4983cbcc20d2 Mon Sep 17 00:00:00 2001 From: Giovanni Sollazzo Date: Tue, 3 Jan 2023 17:02:37 +0100 Subject: [PATCH 237/367] AIDEM Bid Adapter: added wpar and placementId param (#9377) * AIDEM Bid Adapter * Added _spec.js * update * Fix Navigator in _spec.js * Removed timeout handler. * Added publisherId as required bidder params * moved publisherId into site publisher object * Added wpar to environment * Added placementId parameter * added unit tests for the wpar environment object Co-authored-by: darkstar Co-authored-by: AndreaC <67786179+darkstarac@users.noreply.github.com> --- modules/aidemBidAdapter.js | 4 ++++ modules/aidemBidAdapter.md | 1 + test/spec/modules/aidemBidAdapter_spec.js | 12 ++++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 41bf680db1c..081a0324ddb 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -220,6 +220,8 @@ function setPrebidImpressionObject(bidRequests, payload) { deepSetValue(impressionObject, 'id', bidRequest.bidId); // Transaction id deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'transactionId')); + // Placement id + deepSetValue(impressionObject, 'tagid', deepAccess(bidRequest, 'params.placementId', null)); // Publisher id deepSetValue(payload, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); // Site id @@ -265,6 +267,8 @@ function setPrebidRequestEnvironment(payload) { deepSetValue(payload, 'environment.inp.jp', window.JSON.parse.name === 'parse' && typeof window.JSON.parse.prototype === 'undefined'); deepSetValue(payload, 'environment.inp.ofe', window.Object.fromEntries.name === 'fromEntries' && typeof window.Object.fromEntries.prototype === 'undefined'); deepSetValue(payload, 'environment.inp.oa', window.Object.assign.name === 'assign' && typeof window.Object.assign.prototype === 'undefined'); + deepSetValue(payload, 'environment.wpar.innerWidth', window.innerWidth); + deepSetValue(payload, 'environment.wpar.innerHeight', window.innerHeight); } function setPrebidImpressionObjectFloor(bidRequest, impressionObject) { diff --git a/modules/aidemBidAdapter.md b/modules/aidemBidAdapter.md index a5beca97d10..342a264da01 100644 --- a/modules/aidemBidAdapter.md +++ b/modules/aidemBidAdapter.md @@ -18,6 +18,7 @@ This module is GDPR and CCPA compliant, and no 3rd party userIds are allowed. |---------------|----------|---------------------|---------------|----------| | `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | | `publisherId` | required | Unique publisher ID | `'ABCDEF'` | `String` | +| `placementId` | optional | Unique publisher tag ID | `'ABCDEF'` | `String` | ### Banner Bid Params diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 472b226ab8a..71edfcf82fb 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -385,7 +385,7 @@ describe('Aidem adapter', () => { expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_BANNER_REQUESTS.length) expect(payload.imp[0]).to.be.a('object').that.has.all.keys( - 'banner', 'id', 'mediatype', 'imp_ext', 'tid' + 'banner', 'id', 'mediatype', 'imp_ext', 'tid', 'tagid' ) expect(payload.imp[0].banner).to.be.a('object').that.has.all.keys( 'format', 'topframe' @@ -401,7 +401,7 @@ describe('Aidem adapter', () => { expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_VIDEO_REQUESTS.length) expect(payload.imp[0]).to.be.a('object').that.has.all.keys( - 'video', 'id', 'mediatype', 'imp_ext', 'tid' + 'video', 'id', 'mediatype', 'imp_ext', 'tid', 'tagid' ) expect(payload.imp[0].video).to.be.a('object').that.has.all.keys( 'format', 'mimes', 'minDuration', 'maxDuration', 'protocols' @@ -421,6 +421,14 @@ describe('Aidem adapter', () => { 'value', 'currency' ) }); + + it('should hav wpar keys in environment object', function () { + const requests = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + expect(payload).to.have.property('environment') + expect(payload.environment).to.be.a('object').that.have.property('wpar') + expect(payload.environment.wpar).to.be.a('object').that.has.keys('innerWidth', 'innerHeight') + }); }) describe('interpretResponse', () => { From a2172d9aa3b56e8992460e796760843cb9fa947c Mon Sep 17 00:00:00 2001 From: ahmadlob <109217988+ahmadlob@users.noreply.github.com> Date: Tue, 3 Jan 2023 18:54:25 +0200 Subject: [PATCH 238/367] Taboola Bid Adapter: onBidWon, userSyncs, gpp support and FPD (#9376) * on-bid-won * support-fpd * support-fpd * support-fpd * support-fpd * support-fpd * support-fpd * implement-get-user-sync * implement-get-user-sync * implement-get-user-sync * implement-get-user-sync * implement-get-user-sync * implement-get-user-sync * implement-get-user-sync * implement-get-user-sync * implement-get-user-sync * position-pagetype --- modules/taboolaBidAdapter.js | 62 ++++++++-- test/spec/modules/taboolaBidAdapter_spec.js | 124 +++++++++++++++++++- 2 files changed, 172 insertions(+), 14 deletions(-) diff --git a/modules/taboolaBidAdapter.js b/modules/taboolaBidAdapter.js index 670d28ab64e..85adfc31ca5 100644 --- a/modules/taboolaBidAdapter.js +++ b/modules/taboolaBidAdapter.js @@ -3,13 +3,15 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; -import {getWindowSelf} from '../src/utils.js' +import {getWindowSelf, replaceAuctionPrice} from '../src/utils.js' import {getStorageManager} from '../src/storageManager.js'; +import { ajax } from '../src/ajax.js'; const BIDDER_CODE = 'taboola'; const GVLID = 42; const CURRENCY = 'USD'; export const END_POINT_URL = 'https://display.bidder.taboola.com/OpenRTB/TaboolaHB/auction'; +export const USER_SYNC_IMG_URL = 'https://trc.taboola.com/sg/prebidJS/1/cm'; const USER_ID = 'user-id'; const STORAGE_KEY = `taboola global:${USER_ID}`; const COOKIE_KEY = 'trc_cookie_storage'; @@ -81,7 +83,7 @@ export const spec = { const [bidRequest] = validBidRequests; const {refererInfo, gdprConsent = {}, uspConsent} = bidderRequest; const {publisherId} = bidRequest.params; - const site = getSiteProperties(bidRequest.params, refererInfo); + const site = getSiteProperties(bidRequest.params, refererInfo, bidderRequest.ortb2); const device = {ua: navigator.userAgent}; const imps = getImps(validBidRequests); const user = { @@ -102,24 +104,32 @@ export const spec = { regs.ext.us_privacy = uspConsent; } + if (bidderRequest.ortb2?.regs?.gpp) { + regs.ext.gpp = bidderRequest.ortb2.regs.gpp; + regs.ext.gpp_sid = bidderRequest.ortb2.regs.gpp_sid; + } + if (config.getConfig('coppa')) { regs.coppa = 1; } const ortb2 = bidderRequest.ortb2 || { + bcat: [], badv: [], - bcat: [] + wlang: [] }; const request = { id: bidderRequest.auctionId, imp: imps, site, + pageType: ortb2?.ext?.data?.pageType || ortb2?.ext?.data?.section || bidRequest.params.pageType, device, source: {fd: 1}, tmax: bidderRequest.timeout, - bcat: ortb2.bcat, - badv: ortb2.badv, + bcat: ortb2.bcat || bidRequest.params.bcat || [], + badv: ortb2.badv || bidRequest.params.badv || [], + wlang: ortb2.wlang || bidRequest.params.wlang || [], user, regs }; @@ -149,16 +159,45 @@ export const spec = { return bidResponses.map((bidResponse) => getBid(bids, currency, bidResponse)).filter(Boolean); }, + onBidWon: (bid) => { + if (bid.nurl) { + const resolvedNurl = replaceAuctionPrice(bid.nurl, bid.originalCpm); + ajax(resolvedNurl); + } + }, + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) { + const syncs = [] + const queryParams = []; + if (gdprConsent) { + queryParams.push(`gdpr=${Number(gdprConsent.gdprApplies && 1)}&gdpr_consent=${encodeURIComponent(gdprConsent.consentString || '')}`); + } + + if (uspConsent) { + queryParams.push('us_privacy=' + encodeURIComponent(uspConsent)); + } + + if (gppConsent) { + queryParams.push('gpp=' + encodeURIComponent(gppConsent)); + } + + if (syncOptions.pixelEnabled) { + syncs.push({ + type: 'image', + url: USER_SYNC_IMG_URL + (queryParams.length ? '?' + queryParams.join('&') : '') + }); + } + return syncs; + }, }; -function getSiteProperties({publisherId, bcat = []}, refererInfo) { +function getSiteProperties({publisherId}, refererInfo, ortb2) { const {getPageUrl, getReferrer} = internal; return { id: publisherId, name: publisherId, - domain: refererInfo?.domain || window.location?.host, - page: getPageUrl(refererInfo), - ref: getReferrer(refererInfo), + domain: ortb2?.site?.domain || refererInfo?.domain || window.location?.host, + page: ortb2?.site?.page || getPageUrl(refererInfo), + ref: ortb2?.site?.ref || getReferrer(refererInfo), publisher: { id: publisherId }, @@ -170,11 +209,12 @@ function getSiteProperties({publisherId, bcat = []}, refererInfo) { function getImps(validBidRequests) { return validBidRequests.map((bid, id) => { - const {tagId} = bid.params; + const {tagId, position} = bid.params; const imp = { id: id + 1, banner: getBanners(bid), - tagid: tagId + tagid: tagId, + position: position } if (typeof bid.getFloor === 'function') { const floorInfo = bid.getFloor({ diff --git a/test/spec/modules/taboolaBidAdapter_spec.js b/test/spec/modules/taboolaBidAdapter_spec.js index 5bde75cd0b6..a3a765d28cf 100644 --- a/test/spec/modules/taboolaBidAdapter_spec.js +++ b/test/spec/modules/taboolaBidAdapter_spec.js @@ -2,6 +2,7 @@ import {expect} from 'chai'; import {spec, internal, END_POINT_URL, userData} from 'modules/taboolaBidAdapter.js'; import {config} from '../../../src/config' import * as utils from '../../../src/utils' +import {server} from '../../mocks/xhr' describe('Taboola Adapter', function () { let hasLocalStorage, cookiesAreEnabled, getDataFromLocalStorage, localStorageIsEnabled, getCookie, commonBidRequest; @@ -91,6 +92,31 @@ describe('Taboola Adapter', function () { }) }) + describe('onBidWon', function () { + it('onBidWon exist as a function', () => { + expect(spec.onBidWon).to.exist.and.to.be.a('function'); + }); + + it('should resolve price macro in nurl', function () { + const nurl = 'http://win.example.com/${AUCTION_PRICE}'; + const bid = { + requestId: 1, + cpm: 2, + originalCpm: 3.4, + creativeId: 1, + ttl: 60, + netRevenue: true, + mediaType: 'banner', + ad: '...', + width: 300, + height: 250, + nurl: nurl + } + spec.onBidWon(bid); + expect(server.requests[0].url).to.equals('http://win.example.com/3.4') + }); + }); + describe('buildRequests', function () { const defaultBidRequest = { ...createBidRequest(), @@ -137,6 +163,7 @@ describe('Taboola Adapter', function () { 'source': {'fd': 1}, 'bcat': [], 'badv': [], + 'wlang': [], 'user': { 'buyeruid': 0, 'ext': {}, @@ -184,7 +211,7 @@ describe('Taboola Adapter', function () { expect(resData.imp[0].bidfloorcur).to.deep.equal('USD'); }); - it('should pass bid floor even if they is a bid floor param', function () { + it('should pass bid floor even if it is a bid floor param', function () { const optionalParams = { bidfloor: 0.25, bidfloorcur: 'EUR' @@ -206,6 +233,21 @@ describe('Taboola Adapter', function () { expect(resData.imp[0].bidfloorcur).to.deep.equal('USD'); }); + it('should pass impression position', function () { + const optionalParams = { + position: 2 + }; + + const bidRequest = { + ...defaultBidRequest, + params: {...commonBidRequest.params, ...optionalParams} + }; + + const res = spec.buildRequests([bidRequest], commonBidderRequest); + const resData = JSON.parse(res.data); + expect(resData.imp[0].position).to.deep.equal(2); + }); + it('should pass bidder timeout', function () { const bidderRequest = { ...commonBidderRequest, @@ -216,6 +258,40 @@ describe('Taboola Adapter', function () { expect(resData.tmax).to.equal(500); }); + describe('first party data', function () { + it('should parse first party data', function () { + const bidderRequest = { + ...commonBidderRequest, + ortb2: { + bcat: ['EX1', 'EX2', 'EX3'], + badv: ['site.com'], + wlang: ['de'], + } + } + const res = spec.buildRequests([defaultBidRequest], bidderRequest); + const resData = JSON.parse(res.data); + expect(resData.bcat).to.deep.equal(bidderRequest.ortb2.bcat) + expect(resData.badv).to.deep.equal(bidderRequest.ortb2.badv) + expect(resData.wlang).to.deep.equal(bidderRequest.ortb2.wlang) + }); + + it('should pass pageType if exists in ortb2', function () { + const bidderRequest = { + ...commonBidderRequest, + ortb2: { + ext: { + data: { + pageType: 'news' + } + } + } + } + const res = spec.buildRequests([defaultBidRequest], bidderRequest); + const resData = JSON.parse(res.data); + expect(resData.pageType).to.deep.equal(bidderRequest.ortb2.ext.data.pageType); + }); + }); + describe('handle privacy segments when building request', function () { it('should pass GDPR consent', function () { const bidderRequest = { @@ -234,6 +310,20 @@ describe('Taboola Adapter', function () { expect(resData.regs.ext.gdpr).to.equal(1) }); + it('should pass GPP consent if exist in ortb2', function () { + const ortb2 = { + regs: { + gpp: 'testGpp', + gpp_sid: [1, 2, 3] + } + } + + const res = spec.buildRequests([defaultBidRequest], {...commonBidderRequest, ortb2}) + const resData = JSON.parse(res.data) + expect(resData.regs.ext.gpp).to.equal('testGpp') + expect(resData.regs.ext.gpp_sid).to.deep.equal([1, 2, 3]) + }); + it('should pass us privacy consent', function () { const bidderRequest = { refererInfo: { @@ -552,8 +642,36 @@ describe('Taboola Adapter', function () { }); }) - describe('userData', function () { - // todo: add UT for getUserSyncs + describe('getUserSyncs', function () { + const usersyncUrl = 'https://trc.taboola.com/sg/prebidJS/1/cm'; + + it('should not return user sync if pixelEnabled is false', function () { + const res = spec.getUserSyncs({pixelEnabled: false}); + expect(res).to.be.an('array').that.is.empty; + }); + + it('should return user sync if pixelEnabled is true', function () { + const res = spec.getUserSyncs({pixelEnabled: true}); + expect(res).to.deep.equal([{type: 'image', url: usersyncUrl}]); + }); + + it('should pass consent tokens values', function() { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: 'GDPR_CONSENT'}, 'USP_CONSENT')).to.deep.equal([{ + type: 'image', url: `${usersyncUrl}?gdpr=1&gdpr_consent=GDPR_CONSENT&us_privacy=USP_CONSENT` + }]); + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: false, consentString: undefined}, undefined)).to.deep.equal([{ + type: 'image', url: `${usersyncUrl}?gdpr=0&gdpr_consent=` + }]); + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: false, consentString: undefined}, undefined)).to.deep.equal([{ + type: 'image', url: `${usersyncUrl}?gdpr=0&gdpr_consent=` + }]); + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, 'USP_CONSENT')).to.deep.equal([{ + type: 'image', url: `${usersyncUrl}?us_privacy=USP_CONSENT` + }]); + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, 'USP_CONSENT', 'GPP_STRING')).to.deep.equal([{ + type: 'image', url: `${usersyncUrl}?us_privacy=USP_CONSENT&gpp=GPP_STRING` + }]); + }); }) describe('internal functions', function () { From 348ba1da17739175f64c02120ab99cfe853aa49d Mon Sep 17 00:00:00 2001 From: nkloeber <100145701+nkloeber@users.noreply.github.com> Date: Tue, 3 Jan 2023 18:11:12 +0100 Subject: [PATCH 239/367] Yieldlab Bid Adapter: read and pass UserIdsAsEids atype information (#9370) * YieldlabBidAdapter read atype information from UserIdsAsEids and pass it as query parameter (atypes={idprovider}:{atype},{idprovider2}:{atype2},...) * Update type hint and add semi colons Co-authored-by: Christoph Kipping <29540638+kippsterr@users.noreply.github.com> --- modules/yieldlabBidAdapter.js | 16 ++++++++++++++++ test/spec/modules/yieldlabBidAdapter_spec.js | 12 +++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/modules/yieldlabBidAdapter.js b/modules/yieldlabBidAdapter.js index 88e1494d416..6e4f6644140 100644 --- a/modules/yieldlabBidAdapter.js +++ b/modules/yieldlabBidAdapter.js @@ -62,6 +62,7 @@ export const spec = { } if (bid.userIdAsEids && Array.isArray(bid.userIdAsEids)) { query.ids = createUserIdString(bid.userIdAsEids) + query.atypes = createUserIdAtypesString(bid.userIdAsEids) } if (bid.params.customParams && isPlainObject(bid.params.customParams)) { for (const prop in bid.params.customParams) { @@ -303,6 +304,21 @@ function createUserIdString(eids) { return str.join(',') } +/** + * Creates a string from an array of eids with ID provider and atype if atype exists + * @param {Array.<{source: String, uids: Array.<{id: String, atype: Number, ext: Object}>}>} eids + * @returns {String} idprovider:atype,idprovider2:atype2,... + */ +function createUserIdAtypesString(eids) { + const str = []; + for (let i = 0; i < eids.length; i++) { + if (eids[i].uids[0].atype) { + str.push(eids[i].source + ':' + eids[i].uids[0].atype); + } + } + return str.join(','); +} + /** * Creates a querystring out of an object with key-values * @param {Object} obj diff --git a/test/spec/modules/yieldlabBidAdapter_spec.js b/test/spec/modules/yieldlabBidAdapter_spec.js index 5df0e93d34e..07d42df1319 100644 --- a/test/spec/modules/yieldlabBidAdapter_spec.js +++ b/test/spec/modules/yieldlabBidAdapter_spec.js @@ -45,6 +45,12 @@ const DEFAULT_REQUEST = () => ({ id: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg', atype: 1 }] + }, { + source: 'digitrust.de', + uids: [{ + id: 'd8aa10fa-d86c-451d-aad8-5f16162a9e64', + atype: 2 + }] }], schain: { ver: '1.0', @@ -271,7 +277,11 @@ describe('yieldlabBidAdapter', () => { }) it('passes userids to bid request', () => { - expect(request.url).to.include('ids=netid.de%3AfH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg') + expect(request.url).to.include('ids=netid.de%3AfH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg%2Cdigitrust.de%3Ad8aa10fa-d86c-451d-aad8-5f16162a9e64') + }) + + it('passes atype to bid request', () => { + expect(request.url).to.include('atypes=netid.de%3A1%2Cdigitrust.de%3A2') }) it('passes extra params to bid request', () => { From 1960ed811bd923a445aece06b20f06e11589bf1d Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 3 Jan 2023 12:54:41 -0700 Subject: [PATCH 240/367] Medianet RTD module: fix `getTargetingData` to retrieve correct adUnits (#9392) --- modules/medianetRtdProvider.js | 8 ++++---- test/spec/modules/medianetRtdProvider_spec.js | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/medianetRtdProvider.js b/modules/medianetRtdProvider.js index 3e01d0e5631..5a159b39081 100644 --- a/modules/medianetRtdProvider.js +++ b/modules/medianetRtdProvider.js @@ -59,14 +59,14 @@ function onAuctionInitEvent(auctionInit) { }, SOURCE)); } -function getTargetingData(adUnitCode) { - const adUnits = getAdUnits(undefined, adUnitCode); +function getTargetingData(adUnitCodes, config, consent, auction) { + const adUnits = getAdUnits(auction.adUnits, adUnitCodes); let targetingData = {}; if (window.mnjs.loaded && isFn(window.mnjs.getTargetingData)) { - targetingData = window.mnjs.getTargetingData(adUnitCode, adUnits, SOURCE) || {}; + targetingData = window.mnjs.getTargetingData(adUnitCodes, adUnits, SOURCE) || {}; } const targeting = {}; - adUnitCode.forEach(adUnitCode => { + adUnitCodes.forEach(adUnitCode => { targeting[adUnitCode] = targeting[adUnitCode] || {}; targetingData[adUnitCode] = targetingData[adUnitCode] || {}; targeting[adUnitCode] = { diff --git a/test/spec/modules/medianetRtdProvider_spec.js b/test/spec/modules/medianetRtdProvider_spec.js index 7d73ecd5d44..f9d4ef7c2cf 100644 --- a/test/spec/modules/medianetRtdProvider_spec.js +++ b/test/spec/modules/medianetRtdProvider_spec.js @@ -66,12 +66,12 @@ describe('medianet realtime module', function () { describe('getTargeting should work correctly', function () { it('should return empty if not loaded', function () { window.mnjs.loaded = false; - assert.deepEqual(medianetRTD.medianetRtdModule.getTargetingData([]), {}); + assert.deepEqual(medianetRTD.medianetRtdModule.getTargetingData([], {}, {}, {}), {}); }); it('should return ad unit codes when ad units are present', function () { const adUnitCodes = ['code1', 'code2']; - assert.deepEqual(medianetRTD.medianetRtdModule.getTargetingData(adUnitCodes), { + assert.deepEqual(medianetRTD.medianetRtdModule.getTargetingData(adUnitCodes, {}, {}, {}), { code1: {'mnadc': 'code1'}, code2: {'mnadc': 'code2'}, }); @@ -79,7 +79,7 @@ describe('medianet realtime module', function () { it('should call mnjs.getTargetingData if loaded', function () { window.mnjs.loaded = true; - medianetRTD.medianetRtdModule.getTargetingData([]); + medianetRTD.medianetRtdModule.getTargetingData([], {}, {}, {}); assert.equal(getTargetingDataSpy.called, true); }); }); From febd71b40884ebc23dfb448f8a7096168eaffdcb Mon Sep 17 00:00:00 2001 From: Krzysztof Desput Date: Wed, 4 Jan 2023 11:20:42 +0100 Subject: [PATCH 241/367] Holid Bid Adapter: initial release (#9371) * Holid bid adapter * Adjust test to various device sizes * Include first party data from ortb2 object * Remove trailing spaces in test --- modules/holidBidAdapter.js | 170 ++++++++++++++++++++++ modules/holidBidAdapter.md | 36 +++++ test/spec/modules/holidBidAdapter_spec.js | 165 +++++++++++++++++++++ 3 files changed, 371 insertions(+) create mode 100644 modules/holidBidAdapter.js create mode 100644 modules/holidBidAdapter.md create mode 100644 test/spec/modules/holidBidAdapter_spec.js diff --git a/modules/holidBidAdapter.js b/modules/holidBidAdapter.js new file mode 100644 index 00000000000..be5a7a044c3 --- /dev/null +++ b/modules/holidBidAdapter.js @@ -0,0 +1,170 @@ +import { + deepAccess, + getBidIdParameter, + isStr, + logMessage, + triggerPixel, +} from '../src/utils.js' +import * as events from '../src/events.js' +import CONSTANTS from '../src/constants.json' +import { BANNER } from '../src/mediaTypes.js' + +import { registerBidder } from '../src/adapters/bidderFactory.js' + +const BIDDER_CODE = 'holid' +const GVLID = 1177 +const ENDPOINT = 'https://helloworld.holid.io/openrtb2/auction' +const COOKIE_SYNC_ENDPOINT = 'https://null.holid.io/sync.html' +const TIME_TO_LIVE = 300 +let wurlMap = {} + +events.on(CONSTANTS.EVENTS.BID_WON, bidWonHandler) + +export const spec = { + code: BIDDER_CODE, + gvlid: GVLID, + supportedMediaTypes: [BANNER], + + isBidRequestValid: function (bid) { + return !!bid.params.adUnitID + }, + + buildRequests: function (validBidRequests, _bidderRequest) { + return validBidRequests.map((bid) => { + const requestData = { + ...bid.ortb2, + id: bid.auctionId, + imp: [getImp(bid)], + } + + return { + method: 'POST', + url: ENDPOINT, + data: JSON.stringify(requestData), + bidId: bid.bidId, + } + }) + }, + + interpretResponse: function (serverResponse, bidRequest) { + const bidResponses = [] + + if (!serverResponse.body.seatbid) { + return [] + } + + serverResponse.body.seatbid.map((response) => { + response.bid.map((bid) => { + const requestId = bidRequest.bidId + const auctionId = bidRequest.auctionId + const wurl = deepAccess(bid, 'ext.prebid.events.win') + const bidResponse = { + requestId, + cpm: bid.price, + width: bid.w, + height: bid.h, + ad: bid.adm, + creativeId: bid.crid, + currency: serverResponse.body.cur, + netRevenue: true, + ttl: TIME_TO_LIVE, + } + + addWurl({ auctionId, requestId, wurl }) + + bidResponses.push(bidResponse) + }) + }) + + return bidResponses + }, + + getUserSyncs(optionsType, serverResponse, gdprConsent, uspConsent) { + if (!serverResponse || serverResponse.length === 0) { + return [] + } + + const syncs = [] + + if (optionsType.iframeEnabled) { + const queryParams = [] + + queryParams.push('bidders=' + getBidders(serverResponse)) + queryParams.push('gdpr=' + +gdprConsent.gdprApplies) + queryParams.push('gdpr_consent=' + gdprConsent.consentString) + queryParams.push('usp_consent=' + (uspConsent || '')) + + let strQueryParams = queryParams.join('&') + + if (strQueryParams.length > 0) { + strQueryParams = '?' + strQueryParams + } + + syncs.push({ + type: 'iframe', + url: COOKIE_SYNC_ENDPOINT + strQueryParams + '&type=iframe', + }) + + return syncs + } + }, +} + +function getImp(bid) { + const imp = { + ext: { + prebid: { + storedrequest: { + id: getBidIdParameter('adUnitID', bid.params), + }, + }, + }, + } + const sizes = + bid.sizes && !Array.isArray(bid.sizes[0]) ? [bid.sizes] : bid.sizes + + if (deepAccess(bid, 'mediaTypes.banner')) { + imp.banner = { + format: sizes.map((size) => { + return { w: size[0], h: size[1] } + }), + } + } + + return imp +} + +function getBidders(serverResponse) { + const bidders = serverResponse + .map((res) => Object.keys(res.body.ext.responsetimemillis)) + .flat(1) + + return encodeURIComponent(JSON.stringify([...new Set(bidders)])) +} + +function addWurl(auctionId, adId, wurl) { + if ([auctionId, adId].every(isStr)) { + wurlMap[`${auctionId}${adId}`] = wurl + } +} + +function removeWurl(auctionId, adId) { + delete wurlMap[`${auctionId}${adId}`] +} + +function getWurl(auctionId, adId) { + if ([auctionId, adId].every(isStr)) { + return wurlMap[`${auctionId}${adId}`] + } +} + +function bidWonHandler(bid) { + const wurl = getWurl(bid.auctionId, bid.adId) + if (wurl) { + logMessage(`Invoking image pixel for wurl on BID_WIN: "${wurl}"`) + triggerPixel(wurl) + removeWurl(bid.auctionId, bid.adId) + } +} + +registerBidder(spec) diff --git a/modules/holidBidAdapter.md b/modules/holidBidAdapter.md new file mode 100644 index 00000000000..1d83918c00a --- /dev/null +++ b/modules/holidBidAdapter.md @@ -0,0 +1,36 @@ +# Overview + +``` +Module Name: Holid Bid Adapter +Module Type: Bidder Adapter +Maintainer: richard@holid.se +``` + +# Description + +Currently module supports only banner mediaType. + +# Test Parameters + +## Sample Banner Ad Unit + +```js +var adUnits = [ + { + code: 'bannerAdUnit', + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + bids: [ + { + bidder: 'holid', + params: { + adUnitID: '12345', + }, + }, + ], + }, +] +``` diff --git a/test/spec/modules/holidBidAdapter_spec.js b/test/spec/modules/holidBidAdapter_spec.js new file mode 100644 index 00000000000..e18a5ac58f4 --- /dev/null +++ b/test/spec/modules/holidBidAdapter_spec.js @@ -0,0 +1,165 @@ +import { expect } from 'chai' +import { spec } from 'modules/holidBidAdapter.js' + +describe('holidBidAdapterTests', () => { + const bidRequestData = { + bidder: 'holid', + adUnitCode: 'test-div', + bidId: 'bid-id', + auctionId: 'test-id', + params: { adUnitID: '12345' }, + mediaTypes: { banner: {} }, + sizes: [[300, 250]], + ortb2: { + site: { + publisher: { + domain: 'https://foo.bar', + } + }, + regs: { + gdpr: 1, + }, + user: { + ext: { + consent: 'G4ll0p1ng_Un1c0rn5', + } + }, + device: { + h: 410, + w: 1860, + } + } + } + + describe('isBidRequestValid', () => { + const bid = JSON.parse(JSON.stringify(bidRequestData)) + + it('should return true', () => { + expect(spec.isBidRequestValid(bid)).to.equal(true) + }) + + it('should return false when required params are not passed', () => { + const bid = JSON.parse(JSON.stringify(bidRequestData)) + delete bid.params.adUnitID + + expect(spec.isBidRequestValid(bid)).to.equal(false) + }) + }) + + describe('buildRequests', () => { + const bid = JSON.parse(JSON.stringify(bidRequestData)) + const request = spec.buildRequests([bid], bid) + const payload = JSON.parse(request[0].data) + + it('should include ext in imp', () => { + expect(payload.imp[0].ext).to.exist + expect(payload.imp[0].ext).to.deep.equal({ + prebid: { storedrequest: { id: '12345' } }, + }) + }) + + it('should include banner format in imp', () => { + expect(payload.imp[0].banner).to.exist + expect(payload.imp[0].banner).to.deep.equal({ + format: [{ w: 300, h: 250 }], + }) + }) + + it('should include ortb2 first party data', () => { + expect(payload.device.w).to.equal(1860) + expect(payload.device.h).to.equal(410) + expect(payload.user.ext.consent).to.equal('G4ll0p1ng_Un1c0rn5') + expect(payload.regs.gdpr).to.equal(1) + }) + }) + + describe('interpretResponse', () => { + const serverResponse = { + body: { + id: 'test-id', + cur: 'USD', + seatbid: [ + { + bid: [ + { + id: 'testbidid', + price: 0.4, + adm: 'test-ad', + adid: 789456, + crid: 1234, + w: 300, + h: 250, + }, + ], + }, + ], + }, + } + + const interpretedResponse = spec.interpretResponse( + serverResponse, + bidRequestData + ) + + it('should interpret response', () => { + expect(interpretedResponse[0].requestId).to.equal(bidRequestData.bidId) + expect(interpretedResponse[0].cpm).to.equal( + serverResponse.body.seatbid[0].bid[0].price + ) + expect(interpretedResponse[0].ad).to.equal( + serverResponse.body.seatbid[0].bid[0].adm + ) + expect(interpretedResponse[0].creativeId).to.equal( + serverResponse.body.seatbid[0].bid[0].crid + ) + expect(interpretedResponse[0].width).to.equal( + serverResponse.body.seatbid[0].bid[0].w + ) + expect(interpretedResponse[0].height).to.equal( + serverResponse.body.seatbid[0].bid[0].h + ) + expect(interpretedResponse[0].currency).to.equal(serverResponse.body.cur) + }) + }) + + describe('getUserSyncs', () => { + it('should return user sync', () => { + const optionsType = { + iframeEnabled: true, + pixelEnabled: true, + } + const serverResponse = [ + { + body: { + ext: { + responsetimemillis: { + 'test seat 1': 2, + 'test seat 2': 1, + }, + }, + }, + }, + ] + const gdprConsent = { + gdprApplies: 1, + consentString: 'dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig', + } + const uspConsent = 'mkjvbiniwot4827obfoy8sdg8203gb' + const expectedUserSyncs = [ + { + type: 'iframe', + url: 'https://null.holid.io/sync.html?bidders=%5B%22test%20seat%201%22%2C%22test%20seat%202%22%5D&gdpr=1&gdpr_consent=dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig&usp_consent=mkjvbiniwot4827obfoy8sdg8203gb&type=iframe', + }, + ] + + const userSyncs = spec.getUserSyncs( + optionsType, + serverResponse, + gdprConsent, + uspConsent + ) + + expect(userSyncs).to.deep.equal(expectedUserSyncs) + }) + }) +}) From 1238d30cc986d3ac9c378329dc4e7f4bb37a9da7 Mon Sep 17 00:00:00 2001 From: Torsten Date: Thu, 5 Jan 2023 12:16:41 +0100 Subject: [PATCH 242/367] Appnexus Bid Adapter : add video data from the request to the bid response (#9396) * Appnexus adapter: add video data from the request to the bid response * kick off tests * remove change Co-authored-by: Chris Huie --- modules/appnexusBidAdapter.js | 1 + test/spec/modules/appnexusBidAdapter_spec.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index 919831b8515..7465ab15780 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -731,6 +731,7 @@ function newBid(serverBid, rtbBid, bidderRequest) { displayUrl: nativeAd.displayurl, clickTrackers: nativeAd.link.click_trackers, impressionTrackers: nativeAd.impression_trackers, + video: nativeAd.video, javascriptTrackers: jsTrackers }; if (nativeAd.main_img) { diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index 1ab8feceaeb..bae2417c278 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -1630,7 +1630,10 @@ describe('AppNexusAdapter', function () { 'phone': '1234567890', 'address': '28 W 23rd St, New York, NY 10010', 'privacy_link': 'https://appnexus.com/?url=privacy_url', - 'javascriptTrackers': '' + 'javascriptTrackers': '', + 'video': { + 'content': '' + } }; let bidderRequest = { bids: [{ @@ -1644,6 +1647,7 @@ describe('AppNexusAdapter', function () { expect(result[0].native.body).to.equal('Cool description great stuff'); expect(result[0].native.cta).to.equal('Do it'); expect(result[0].native.image.url).to.equal('https://cdn.adnxs.com/img.png'); + expect(result[0].native.video.content).to.equal(''); }); } From 978926d8e318985c04d5c5cc79851a32efb5ffc7 Mon Sep 17 00:00:00 2001 From: Olivier Date: Thu, 5 Jan 2023 17:22:43 +0100 Subject: [PATCH 243/367] AdagioBidAdapter: Remove some params (#9398) --- modules/adagioBidAdapter.js | 4 --- modules/adagioBidAdapter.md | 26 +++---------------- test/spec/modules/adagioBidAdapter_spec.js | 29 +--------------------- 3 files changed, 5 insertions(+), 54 deletions(-) diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js index 4f86a914982..12fd50c6636 100644 --- a/modules/adagioBidAdapter.js +++ b/modules/adagioBidAdapter.js @@ -669,10 +669,8 @@ function autoFillParams(bid) { } // extra params - setExtraParam(bid, 'environment'); setExtraParam(bid, 'pagetype'); setExtraParam(bid, 'category'); - setExtraParam(bid, 'subcategory'); } function getPageDimensions() { @@ -1094,8 +1092,6 @@ export const spec = { bidObj.placement = bidReq.params.placement; bidObj.pagetype = bidReq.params.pagetype; bidObj.category = bidReq.params.category; - bidObj.subcategory = bidReq.params.subcategory; - bidObj.environment = bidReq.params.environment; } bidResponses.push(bidObj); }); diff --git a/modules/adagioBidAdapter.md b/modules/adagioBidAdapter.md index 9b48caa8233..b804a72fea9 100644 --- a/modules/adagioBidAdapter.md +++ b/modules/adagioBidAdapter.md @@ -17,12 +17,10 @@ Below, the list of Adagio params and where they can be set. | Param name | Global config | AdUnit config | | ---------- | ------------- | ------------- | | siteId | x | -| organizationId (obsolete) | | x -| site (obsolete) | | x +| organizationId * | | x +| site * | | x | pagetype | x | x -| environment | x | x | category | x | x -| subcategory | x | x | useAdUnitCodeAsAdUnitElementId | x | x | useAdUnitCodeAsPlacement | x | x | placement | | x @@ -31,6 +29,8 @@ Below, the list of Adagio params and where they can be set. | video | | x | native | | x +_* These params are deprecated in favor the Global configuration setup, see below._ + ### Global configuration The global configuration is used to store params once instead of duplicate them to each adUnit. The values will be used as "params" in the ad-request. @@ -49,9 +49,7 @@ pbjs.setConfig({ // - underscores `_` // Also, each param can have at most 50 unique active values (case-insensitive). pagetype: 'article', // Highly recommended. The pagetype describes what kind of content will be present in the page. - environment: 'mobile', // Recommended. Environment where the page is displayed. category: 'sport', // Recommended. Category of the content displayed in the page. - subcategory: 'handball', // Optional. Subcategory of the content displayed in the page. useAdUnitCodeAsAdUnitElementId: false, // Optional. Use it by-pass adUnitElementId and use the adUnit code as value useAdUnitCodeAsPlacement: false, // Optional. Use it to by-pass placement and use the adUnit code as value }, @@ -62,9 +60,7 @@ pbjs.setConfig({ Adagio will use FPD data as fallback for the params below: - pagetype -- environment - category -- subcategory If the FPD value is an array, the 1st value of this array will be used. @@ -107,9 +103,7 @@ var adUnits = [ debug: true, adagio: { pagetype: 'article', - environment: 'mobile', category: 'sport', - subcategory: 'handball', useAdUnitCodeAsAdUnitElementId: false, useAdUnitCodeAsPlacement: false, } @@ -208,12 +202,6 @@ var adUnits = [ return bidResponse.site; } }, - { - key: "environment", - val: function (bidResponse) { - return bidResponse.environment; - } - }, { key: "placement", val: function (bidResponse) { @@ -231,12 +219,6 @@ var adUnits = [ val: function (bidResponse) { return bidResponse.category; } - }, - { - key: "subcategory", - val: function (bidResponse) { - return bidResponse.subcategory; - } } ] } diff --git a/test/spec/modules/adagioBidAdapter_spec.js b/test/spec/modules/adagioBidAdapter_spec.js index 436d481c4a1..8abdc621922 100644 --- a/test/spec/modules/adagioBidAdapter_spec.js +++ b/test/spec/modules/adagioBidAdapter_spec.js @@ -149,10 +149,8 @@ describe('Adagio bid adapter', () => { site: { ext: { data: { - environment: 'desktop', pagetype: 'abc', - category: ['cat1', 'cat2', 'cat3'], - subcategory: [] + category: ['cat1', 'cat2', 'cat3'] } } } @@ -167,17 +165,11 @@ describe('Adagio bid adapter', () => { return utils.deepAccess(config, key); }); - setExtraParam(bid, 'environment'); - expect(bid.params.environment).to.equal('desktop'); - setExtraParam(bid, 'pagetype') expect(bid.params.pagetype).to.equal('article'); setExtraParam(bid, 'category'); expect(bid.params.category).to.equal('cat1'); // Only the first value is kept - - setExtraParam(bid, 'subcategory'); - expect(bid.params.subcategory).to.be.undefined; }); it('should use the adUnit param unit if defined', function() { @@ -784,8 +776,6 @@ describe('Adagio bid adapter', () => { adUnitElementId: 'gpt-adunit-code', pagetype: 'ARTICLE', category: 'NEWS', - subcategory: 'SPORT', - environment: 'desktop', supportIObs: true }, adUnitCode: 'adunit-code', @@ -833,8 +823,6 @@ describe('Adagio bid adapter', () => { site: 'SITE-NAME', pagetype: 'ARTICLE', category: 'NEWS', - subcategory: 'SPORT', - environment: 'desktop', aDomain: ['advertiser.com'], mediaType: 'banner', meta: { @@ -868,8 +856,6 @@ describe('Adagio bid adapter', () => { site: 'SITE-NAME', pagetype: 'ARTICLE', category: 'NEWS', - subcategory: 'SPORT', - environment: 'desktop', aDomain: ['advertiser.com'], mediaType: 'banner', meta: { @@ -1392,19 +1378,6 @@ describe('Adagio bid adapter', () => { }); describe.skip('optional params auto detection', function() { - it('should auto detect environment', function() { - const getDeviceStub = sandbox.stub(_features, 'getDevice'); - - getDeviceStub.returns(5); - expect(adagio.autoDetectEnvironment()).to.eq('tablet'); - - getDeviceStub.returns(4); - expect(adagio.autoDetectEnvironment()).to.eq('mobile'); - - getDeviceStub.returns(2); - expect(adagio.autoDetectEnvironment()).to.eq('desktop'); - }); - it('should auto detect adUnitElementId when GPT is used', function() { sandbox.stub(utils, 'getGptSlotInfoForAdUnitCode').withArgs('banner').returns({divId: 'gpt-banner'}); expect(adagio.autoDetectAdUnitElementId('banner')).to.eq('gpt-banner'); From 408221b84507cb130de9ef647f021f5f75d05070 Mon Sep 17 00:00:00 2001 From: couchcrew-thomas Date: Thu, 5 Jan 2023 17:34:58 +0100 Subject: [PATCH 244/367] Feedad Bid Adapter: added new bid request parameters (#9397) * added file scaffold * added isBidRequestValid implementation * added local prototype of ad integration * added implementation for placement ID validation * fixed video context filter * applied lint to feedad bid adapter * added unit test for bid request validation * added buildRequest unit test * added unit tests for timeout and bid won callbacks * updated bid request to FeedAd API * added parsing of feedad api bid response * added transmisison of tracking events to FeedAd Api * code cleanup * updated feedad unit tests for buildRequest method * added unit tests for event tracking implementation * added unit test for interpretResponse method * added adapter documentation * added dedicated feedad example page * updated feedad adapter to use live system * updated FeedAd adapter placement ID regex * removed groups from FeedAd adapter placement ID regex * removed dedicated feedad example page * updated imports in FeedAd adapter file to use relative paths * updated FeedAd adapter unit test to use sinon.useFakeXMLHttpRequest() * added GDPR fields to the FeedAd bid request * removed video from supported media types of the FeedAd adapter * increased version code of FeedAd adapter to 1.0.2 * removed unnecessary check of bidder request * fixed unit test testing for old FeedAd version * removed video media type example from documentation file * added gvlid to FeedAd adapter * added decoration parameter to adapter documentation * added pass through of additional bid parameters * added user syncs to FeedAd bid adapter * increased FeedAd bid adapter version * lint pass over FeedAd bid adapter * fixed parsing of user syncs from server response * increased FeedAd bid adapter version * fixed version code in test file * added adapter and prebid version to bid request parameters * removed TODO item * added missing test case for user syncs * increased adapter version to 1.0.5 --- modules/feedadBidAdapter.js | 12 ++++++----- test/spec/modules/feedadBidAdapter_spec.js | 24 +++++++++++++++++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/modules/feedadBidAdapter.js b/modules/feedadBidAdapter.js index ef2e57c553f..7b684efab3c 100644 --- a/modules/feedadBidAdapter.js +++ b/modules/feedadBidAdapter.js @@ -7,7 +7,7 @@ import {ajax} from '../src/ajax.js'; * Version of the FeedAd bid adapter * @type {string} */ -const VERSION = '1.0.4'; +const VERSION = '1.0.5'; /** * @typedef {object} FeedAdApiBidRequest @@ -16,7 +16,8 @@ const VERSION = '1.0.4'; * @property {number} ad_type * @property {string} client_token * @property {string} placement_id - * @property {string} sdk_version + * @property {string} prebid_adapter_version + * @property {string} prebid_sdk_version * @property {boolean} app_hybrid * * @property {string} [app_bundle_id] @@ -181,7 +182,8 @@ function createApiBidRParams(request) { ad_type: 0, client_token: request.params.clientToken, placement_id: request.params.placementId, - sdk_version: `prebid_${VERSION}`, + prebid_adapter_version: VERSION, + prebid_sdk_version: '$prebid.version$', app_hybrid: false, }); } @@ -207,7 +209,6 @@ function buildRequests(validBidRequests, bidderRequest) { }) }); data.bids.forEach(bid => BID_METADATA[bid.bidId] = { - // TODO: is 'page' the right value here? referer: data.refererInfo.page, transactionId: bid.transactionId }); @@ -266,7 +267,8 @@ function createTrackingParams(data, klass) { prebid_bid_id: bidId, prebid_transaction_id: transactionId, referer, - sdk_version: VERSION + prebid_adapter_version: VERSION, + prebid_sdk_version: '$prebid.version$', }; } diff --git a/test/spec/modules/feedadBidAdapter_spec.js b/test/spec/modules/feedadBidAdapter_spec.js index 6aed670a563..8cbd6907890 100644 --- a/test/spec/modules/feedadBidAdapter_spec.js +++ b/test/spec/modules/feedadBidAdapter_spec.js @@ -4,6 +4,7 @@ import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes.js'; import {server} from 'test/mocks/xhr.js'; const CODE = 'feedad'; +const EXPECTED_ADAPTER_VERSION = '1.0.5'; describe('FeedAdAdapter', function () { describe('Public API', function () { @@ -300,6 +301,20 @@ describe('FeedAdAdapter', function () { expect(result.data.gdprApplies).to.equal(request.gdprConsent.gdprApplies); expect(result.data.consentIabTcf).to.equal(request.gdprConsent.consentString); }); + it('should include adapter and prebid version', function () { + let bid = { + code: 'feedad', + mediaTypes: { + banner: { + sizes: [[320, 250]] + } + }, + params: {clientToken: 'clientToken', placementId: 'placement-id'} + }; + let result = spec.buildRequests([bid], bidderRequest); + expect(result.data.bids[0].params.prebid_adapter_version).to.equal(EXPECTED_ADAPTER_VERSION); + expect(result.data.bids[0].params.prebid_sdk_version).to.equal('$prebid.version$'); + }); }); describe('interpretResponse', function () { @@ -482,6 +497,12 @@ describe('FeedAdAdapter', function () { expect(() => spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, it)).not.to.throw; }); }); + + it('should return empty array if the body extension is null', function () { + const response = mockServerResponse({ext: null}); + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, response); + expect(result).to.deep.equal([]); + }); }); describe('event tracking calls', function () { @@ -617,7 +638,8 @@ describe('FeedAdAdapter', function () { prebid_bid_id: bidId, prebid_transaction_id: transactionId, referer, - sdk_version: '1.0.4' + prebid_adapter_version: EXPECTED_ADAPTER_VERSION, + prebid_sdk_version: '$prebid.version$', }; subject(data); expect(server.requests.length).to.equal(1); From 768c1d3c59e855db01d6135efab220cbdc749b39 Mon Sep 17 00:00:00 2001 From: Christoph <29540638+kippsterr@users.noreply.github.com> Date: Fri, 6 Jan 2023 13:07:51 +0100 Subject: [PATCH 245/367] Yieldlab Bid Adapter: code style updates (#9386) * Consistently add trailing comma and semicolons everywhere * Use shorthand object property function definition * Fix typo and update type hint --- modules/yieldlabBidAdapter.js | 270 ++++---- test/spec/modules/yieldlabBidAdapter_spec.js | 610 +++++++++---------- 2 files changed, 440 insertions(+), 440 deletions(-) diff --git a/modules/yieldlabBidAdapter.js b/modules/yieldlabBidAdapter.js index 6e4f6644140..cadeb9c1300 100644 --- a/modules/yieldlabBidAdapter.js +++ b/modules/yieldlabBidAdapter.js @@ -1,17 +1,17 @@ -import { _each, deepAccess, isArray, isFn, isPlainObject, timestamp } from '../src/utils.js' -import { registerBidder } from '../src/adapters/bidderFactory.js' -import { find } from '../src/polyfill.js' -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js' -import { Renderer } from '../src/Renderer.js' +import { _each, deepAccess, isArray, isFn, isPlainObject, timestamp } from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { find } from '../src/polyfill.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { Renderer } from '../src/Renderer.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; -const ENDPOINT = 'https://ad.yieldlab.net' -const BIDDER_CODE = 'yieldlab' -const BID_RESPONSE_TTL_SEC = 300 -const CURRENCY_CODE = 'EUR' -const OUTSTREAMPLAYER_URL = 'https://ad.adition.com/dynamic.ad?a=o193092&ma_loadEvent=ma-start-event' -const GVLID = 70 -const DIMENSION_SIGN = 'x' +const ENDPOINT = 'https://ad.yieldlab.net'; +const BIDDER_CODE = 'yieldlab'; +const BID_RESPONSE_TTL_SEC = 300; +const CURRENCY_CODE = 'EUR'; +const OUTSTREAMPLAYER_URL = 'https://ad.adition.com/dynamic.ad?a=o193092&ma_loadEvent=ma-start-event'; +const GVLID = 70; +const DIMENSION_SIGN = 'x'; export const spec = { code: BIDDER_CODE, @@ -22,11 +22,11 @@ export const spec = { * @param {object} bid * @returns {boolean} */ - isBidRequestValid: function (bid) { + isBidRequestValid(bid) { if (bid && bid.params && bid.params.adslotId && bid.params.supplyId) { - return true + return true; } - return false + return false; }, /** @@ -35,85 +35,85 @@ export const spec = { * @param [bidderRequest] * @returns {ServerRequest|ServerRequest[]} */ - buildRequests: function (validBidRequests, bidderRequest) { + buildRequests(validBidRequests, bidderRequest) { // convert Native ORTB definition to old-style prebid native definition validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); - const adslotIds = [] + const adslotIds = []; const adslotSizes = []; const adslotFloors = []; - const timestamp = Date.now() + const timestamp = Date.now(); const query = { ts: timestamp, - json: true - } + json: true, + }; _each(validBidRequests, function (bid) { - adslotIds.push(bid.params.adslotId) - const sizes = extractSizes(bid) + adslotIds.push(bid.params.adslotId); + const sizes = extractSizes(bid); if (sizes.length > 0) { - adslotSizes.push(bid.params.adslotId + ':' + sizes.join('|')) + adslotSizes.push(bid.params.adslotId + ':' + sizes.join('|')); } if (bid.params.extId) { query.id = bid.params.extId; } if (bid.params.targeting) { - query.t = createTargetingString(bid.params.targeting) + query.t = createTargetingString(bid.params.targeting); } if (bid.userIdAsEids && Array.isArray(bid.userIdAsEids)) { - query.ids = createUserIdString(bid.userIdAsEids) - query.atypes = createUserIdAtypesString(bid.userIdAsEids) + query.ids = createUserIdString(bid.userIdAsEids); + query.atypes = createUserIdAtypesString(bid.userIdAsEids); } if (bid.params.customParams && isPlainObject(bid.params.customParams)) { for (const prop in bid.params.customParams) { - query[prop] = bid.params.customParams[prop] + query[prop] = bid.params.customParams[prop]; } } if (bid.schain && isPlainObject(bid.schain) && Array.isArray(bid.schain.nodes)) { - query.schain = createSchainString(bid.schain) + query.schain = createSchainString(bid.schain); } - const iabContent = getContentObject(bid) + const iabContent = getContentObject(bid); if (iabContent) { - query.iab_content = createIabContentString(iabContent) + query.iab_content = createIabContentString(iabContent); } - const floor = getBidFloor(bid, sizes) + const floor = getBidFloor(bid, sizes); if (floor) { adslotFloors.push(bid.params.adslotId + ':' + floor); } - }) + }); if (bidderRequest) { if (bidderRequest.refererInfo && bidderRequest.refererInfo.page) { // TODO: is 'page' the right value here? - query.pubref = bidderRequest.refererInfo.page + query.pubref = bidderRequest.refererInfo.page; } if (bidderRequest.gdprConsent) { - query.gdpr = (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true + query.gdpr = (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true; if (query.gdpr) { - query.consent = bidderRequest.gdprConsent.consentString + query.consent = bidderRequest.gdprConsent.consentString; } } } - const adslots = adslotIds.join(',') + const adslots = adslotIds.join(','); if (adslotSizes.length > 0) { - query.sizes = adslotSizes.join(',') + query.sizes = adslotSizes.join(','); } if (adslotFloors.length > 0) { - query.floor = adslotFloors.join(',') + query.floor = adslotFloors.join(','); } - const queryString = createQueryString(query) + const queryString = createQueryString(query); return { method: 'GET', url: `${ENDPOINT}/yp/${adslots}?${queryString}`, validBidRequests: validBidRequests, - queryParams: query - } + queryParams: query, + }; }, /** @@ -122,29 +122,29 @@ export const spec = { * @param {BidRequest} originalBidRequest * @returns {Bid[]} */ - interpretResponse: function (serverResponse, originalBidRequest) { - const bidResponses = [] - const timestamp = Date.now() - const reqParams = originalBidRequest.queryParams + interpretResponse(serverResponse, originalBidRequest) { + const bidResponses = []; + const timestamp = Date.now(); + const reqParams = originalBidRequest.queryParams; originalBidRequest.validBidRequests.forEach(function (bidRequest) { if (!serverResponse.body) { - return + return; } const matchedBid = find(serverResponse.body, function (bidResponse) { - return bidRequest.params.adslotId == bidResponse.id - }) + return bidRequest.params.adslotId == bidResponse.id; + }); if (matchedBid) { - const adUnitSize = bidRequest.sizes.length === 2 && !isArray(bidRequest.sizes[0]) ? bidRequest.sizes : bidRequest.sizes[0] - const adSize = bidRequest.params.adSize !== undefined ? parseSize(bidRequest.params.adSize) : (matchedBid.adsize !== undefined) ? parseSize(matchedBid.adsize) : adUnitSize - const extId = bidRequest.params.extId !== undefined ? '&id=' + bidRequest.params.extId : '' - const adType = matchedBid.adtype !== undefined ? matchedBid.adtype : '' - const gdprApplies = reqParams.gdpr ? '&gdpr=' + reqParams.gdpr : '' - const gdprConsent = reqParams.consent ? '&consent=' + reqParams.consent : '' - const pvId = matchedBid.pvid !== undefined ? '&pvid=' + matchedBid.pvid : '' - const iabContent = reqParams.iab_content ? '&iab_content=' + reqParams.iab_content : '' + const adUnitSize = bidRequest.sizes.length === 2 && !isArray(bidRequest.sizes[0]) ? bidRequest.sizes : bidRequest.sizes[0]; + const adSize = bidRequest.params.adSize !== undefined ? parseSize(bidRequest.params.adSize) : (matchedBid.adsize !== undefined) ? parseSize(matchedBid.adsize) : adUnitSize; + const extId = bidRequest.params.extId !== undefined ? '&id=' + bidRequest.params.extId : ''; + const adType = matchedBid.adtype !== undefined ? matchedBid.adtype : ''; + const gdprApplies = reqParams.gdpr ? '&gdpr=' + reqParams.gdpr : ''; + const gdprConsent = reqParams.consent ? '&consent=' + reqParams.consent : ''; + const pvId = matchedBid.pvid !== undefined ? '&pvid=' + matchedBid.pvid : ''; + const iabContent = reqParams.iab_content ? '&iab_content=' + reqParams.iab_content : ''; const bidResponse = { requestId: bidRequest.bidId, @@ -159,38 +159,38 @@ export const spec = { referrer: '', ad: ``, meta: { - advertiserDomains: (matchedBid.advertiser) ? matchedBid.advertiser : 'n/a' - } - } + advertiserDomains: (matchedBid.advertiser) ? matchedBid.advertiser : 'n/a', + }, + }; if (isVideo(bidRequest, adType)) { - const playersize = getPlayerSize(bidRequest) + const playersize = getPlayerSize(bidRequest); if (playersize) { - bidResponse.width = playersize[0] - bidResponse.height = playersize[1] + bidResponse.width = playersize[0]; + bidResponse.height = playersize[1]; } - bidResponse.mediaType = VIDEO - bidResponse.vastUrl = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}${iabContent}` + bidResponse.mediaType = VIDEO; + bidResponse.vastUrl = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}${iabContent}`; if (isOutstream(bidRequest)) { const renderer = Renderer.install({ id: bidRequest.bidId, url: OUTSTREAMPLAYER_URL, - loaded: false - }) - renderer.setRender(outstreamRender) - bidResponse.renderer = renderer + loaded: false, + }); + renderer.setRender(outstreamRender); + bidResponse.renderer = renderer; } } if (isNative(bidRequest, adType)) { // there may be publishers still rely on it - const url = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}` - bidResponse.adUrl = url - bidResponse.mediaType = NATIVE - const nativeImageAssetObj = find(matchedBid.native.assets, e => e.id === 2) + const url = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}`; + bidResponse.adUrl = url; + bidResponse.mediaType = NATIVE; + const nativeImageAssetObj = find(matchedBid.native.assets, e => e.id === 2); const nativeImageAsset = nativeImageAssetObj ? nativeImageAssetObj.img : { url: '', w: 0, h: 0 }; - const nativeTitleAsset = find(matchedBid.native.assets, e => e.id === 1) - const nativeBodyAsset = find(matchedBid.native.assets, e => e.id === 3) + const nativeTitleAsset = find(matchedBid.native.assets, e => e.id === 1); + const nativeBodyAsset = find(matchedBid.native.assets, e => e.id === 3); bidResponse.native = { title: nativeTitleAsset ? nativeTitleAsset.title.text : '', body: nativeBodyAsset ? nativeBodyAsset.data.value : '', @@ -204,10 +204,10 @@ export const spec = { }; } - bidResponses.push(bidResponse) + bidResponses.push(bidResponse); } - }) - return bidResponses + }); + return bidResponses; }, /** @@ -219,13 +219,13 @@ export const spec = { * @param {string} uspConsent Is the US Privacy Consent string. * @return {UserSync[]} The user syncs which should be dropped. */ - getUserSyncs: function (syncOptions, serverResponses, gdprConsent, uspConsent) { + getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { const syncs = []; if (syncOptions.iframeEnabled) { const params = []; params.push(`ts=${timestamp()}`); - params.push(`type=h`) + params.push(`type=h`); if (gdprConsent && (typeof gdprConsent.gdprApplies === 'boolean')) { params.push(`gdpr=${Number(gdprConsent.gdprApplies)}`); } @@ -234,12 +234,12 @@ export const spec = { } syncs.push({ type: 'iframe', - url: `${ENDPOINT}/d/6846326/766/2x2?${params.join('&')}` + url: `${ENDPOINT}/d/6846326/766/2x2?${params.join('&')}`, }); } return syncs; - } + }, }; /** @@ -249,7 +249,7 @@ export const spec = { * @returns {Boolean} */ function isVideo(format, adtype) { - return deepAccess(format, 'mediaTypes.video') && adtype.toLowerCase() === 'video' + return deepAccess(format, 'mediaTypes.video') && adtype.toLowerCase() === 'video'; } /** @@ -259,7 +259,7 @@ function isVideo(format, adtype) { * @returns {Boolean} */ function isNative(format, adtype) { - return deepAccess(format, 'mediaTypes.native') && adtype.toLowerCase() === 'native' + return deepAccess(format, 'mediaTypes.native') && adtype.toLowerCase() === 'native'; } /** @@ -268,8 +268,8 @@ function isNative(format, adtype) { * @returns {Boolean} */ function isOutstream(format) { - const context = deepAccess(format, 'mediaTypes.video.context') - return (context === 'outstream') + const context = deepAccess(format, 'mediaTypes.video.context'); + return (context === 'outstream'); } /** @@ -278,30 +278,30 @@ function isOutstream(format) { * @returns {Array} */ function getPlayerSize(format) { - const playerSize = deepAccess(format, 'mediaTypes.video.playerSize') - return (playerSize && isArray(playerSize[0])) ? playerSize[0] : playerSize + const playerSize = deepAccess(format, 'mediaTypes.video.playerSize'); + return (playerSize && isArray(playerSize[0])) ? playerSize[0] : playerSize; } /** - * Expands a 'WxH' string as a 2-element [W, H] array + * Expands a 'WxH' string to a 2-element [W, H] array * @param {String} size * @returns {Array} */ function parseSize(size) { - return size.split(DIMENSION_SIGN).map(Number) + return size.split(DIMENSION_SIGN).map(Number); } /** * Creates a string out of an array of eids with source and uid - * @param {Array} eids + * @param {Array.<{source: String, uids: Array.<{id: String, atype: Number, ext: Object}>}>} eids * @returns {String} */ function createUserIdString(eids) { - const str = [] + const str = []; for (let i = 0; i < eids.length; i++) { - str.push(eids[i].source + ':' + eids[i].uids[0].id) + str.push(eids[i].source + ':' + eids[i].uids[0].id); } - return str.join(',') + return str.join(','); } /** @@ -325,18 +325,18 @@ function createUserIdAtypesString(eids) { * @returns {String} */ function createQueryString(obj) { - const str = [] + const str = []; for (const p in obj) { if (obj.hasOwnProperty(p)) { - const val = obj[p] + const val = obj[p]; if (p !== 'schain' && p !== 'iab_content') { - str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)) + str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)); } else { - str.push(p + '=' + val) + str.push(p + '=' + val); } } } - return str.join('&') + return str.join('&'); } /** @@ -345,15 +345,15 @@ function createQueryString(obj) { * @returns {String} */ function createTargetingString(obj) { - const str = [] + const str = []; for (const p in obj) { if (obj.hasOwnProperty(p)) { - const key = p - const val = obj[p] - str.push(key + '=' + val) + const key = p; + const val = obj[p]; + str.push(key + '=' + val); } } - return str.join('&') + return str.join('&'); } /** @@ -362,13 +362,13 @@ function createTargetingString(obj) { * @returns {String} */ function createSchainString(schain) { - const ver = schain.ver || '' - const complete = (schain.complete === 1 || schain.complete === 0) ? schain.complete : '' - const keys = ['asi', 'sid', 'hp', 'rid', 'name', 'domain', 'ext'] + const ver = schain.ver || ''; + const complete = (schain.complete === 1 || schain.complete === 0) ? schain.complete : ''; + const keys = ['asi', 'sid', 'hp', 'rid', 'name', 'domain', 'ext']; const nodesString = schain.nodes.reduce((acc, node) => { - return acc += `!${keys.map(key => node[key] ? encodeURIComponentWithBangIncluded(node[key]) : '').join(',')}` - }, '') - return `${ver},${complete}${nodesString}` + return acc += `!${keys.map(key => node[key] ? encodeURIComponentWithBangIncluded(node[key]) : '').join(',')}`; + }, ''); + return `${ver},${complete}${nodesString}`; } /** @@ -380,15 +380,15 @@ function createSchainString(schain) { */ function getContentObject(bid) { if (bid.params.iabContent && isPlainObject(bid.params.iabContent)) { - return bid.params.iabContent + return bid.params.iabContent; } const globalContent = deepAccess(bid, 'ortb2.site') ? deepAccess(bid, 'ortb2.site.content') - : deepAccess(bid, 'ortb2.app.content') + : deepAccess(bid, 'ortb2.app.content'); if (globalContent && isPlainObject(globalContent)) { - return globalContent + return globalContent; } - return undefined + return undefined; } /** @@ -401,15 +401,15 @@ function getContentObject(bid) { * @returns {String} */ function createIabContentString(iabContent) { - const arrKeys = ['keywords', 'cat'] - const str = [] + const arrKeys = ['keywords', 'cat']; + const str = []; const transformObjToParam = (obj = {}, extraKey = '') => { for (const key in obj) { if ((arrKeys.indexOf(key) !== -1 && Array.isArray(obj[key]))) { // Array of defined keyword which have to be joined into one value from "key: [value1, value2, value3]" to "key:value1|value2|value3" - str.push(''.concat(key, ':', obj[key].map(node => encodeURIComponent(node)).join('|'))) + str.push(''.concat(key, ':', obj[key].map(node => encodeURIComponent(node)).join('|'))); } else if (typeof obj[key] !== 'object') { - str.push(''.concat(extraKey + key, ':', encodeURIComponent(obj[key]))) + str.push(''.concat(extraKey + key, ':', encodeURIComponent(obj[key]))); } else { // Object has to be further flattened transformObjToParam(obj[key], ''.concat(extraKey, key, '.')); @@ -417,7 +417,7 @@ function createIabContentString(iabContent) { } return str.join(','); }; - return encodeURIComponent(transformObjToParam(iabContent)) + return encodeURIComponent(transformObjToParam(iabContent)); } /** @@ -426,7 +426,7 @@ function createIabContentString(iabContent) { * @returns {String} */ function encodeURIComponentWithBangIncluded(str) { - return encodeURIComponent(str).replace(/!/g, '%21') + return encodeURIComponent(str).replace(/!/g, '%21'); } /** @@ -435,11 +435,11 @@ function encodeURIComponentWithBangIncluded(str) { */ function outstreamRender(bid) { bid.renderer.push(() => { - window.ma_width = bid.width - window.ma_height = bid.height - window.ma_vastUrl = bid.vastUrl - window.ma_container = bid.adUnitCode - window.document.dispatchEvent(new Event('ma-start-event')) + window.ma_width = bid.width; + window.ma_height = bid.height; + window.ma_vastUrl = bid.vastUrl; + window.ma_container = bid.adUnitCode; + window.document.dispatchEvent(new Event('ma-start-event')); }); } @@ -450,33 +450,33 @@ function outstreamRender(bid) { * @returns {string[]} */ function extractSizes(bid) { - const { mediaTypes } = bid // see https://docs.prebid.org/dev-docs/adunit-reference.html#examples - const sizes = [] + const { mediaTypes } = bid; // see https://docs.prebid.org/dev-docs/adunit-reference.html#examples + const sizes = []; if (isPlainObject(mediaTypes)) { - const { [BANNER]: bannerType } = mediaTypes + const { [BANNER]: bannerType } = mediaTypes; // only applies for multi size Adslots -> BANNER if (bannerType && isArray(bannerType.sizes)) { if (isArray(bannerType.sizes[0])) { // multiple sizes given - sizes.push(bannerType.sizes) + sizes.push(bannerType.sizes); } else { // just one size provided as array -> wrap to uniformly flatten later - sizes.push([bannerType.sizes]) + sizes.push([bannerType.sizes]); } } // The bid top level field `sizes` is deprecated and should not be used anymore. Keeping it for compatibility. } else if (isArray(bid.sizes)) { if (isArray(bid.sizes[0])) { - sizes.push(bid.sizes) + sizes.push(bid.sizes); } else { - sizes.push([bid.sizes]) + sizes.push([bid.sizes]); } } /** @type {Set} */ - const deduplicatedSizeStrings = new Set(sizes.flat().map(([width, height]) => width + DIMENSION_SIGN + height)) + const deduplicatedSizeStrings = new Set(sizes.flat().map(([width, height]) => width + DIMENSION_SIGN + height)); - return Array.from(deduplicatedSizeStrings) + return Array.from(deduplicatedSizeStrings); } /** @@ -497,7 +497,7 @@ function getBidFloor(bid, sizes) { const floor = bid.getFloor({ currency: CURRENCY_CODE, mediaType: mediaType !== undefined && spec.supportedMediaTypes.includes(mediaType) ? mediaType : '*', - size: sizes.length !== 1 ? '*' : sizes[0].split(DIMENSION_SIGN) + size: sizes.length !== 1 ? '*' : sizes[0].split(DIMENSION_SIGN), }); if (floor.currency === CURRENCY_CODE) { return (floor.floor * 100).toFixed(0); @@ -505,4 +505,4 @@ function getBidFloor(bid, sizes) { return undefined; } -registerBidder(spec) +registerBidder(spec); diff --git a/test/spec/modules/yieldlabBidAdapter_spec.js b/test/spec/modules/yieldlabBidAdapter_spec.js index 07d42df1319..e5151cf789c 100644 --- a/test/spec/modules/yieldlabBidAdapter_spec.js +++ b/test/spec/modules/yieldlabBidAdapter_spec.js @@ -1,7 +1,7 @@ import { config } from 'src/config.js'; -import { expect } from 'chai' -import { spec } from 'modules/yieldlabBidAdapter.js' -import { newBidder } from 'src/adapters/bidderFactory.js' +import { expect } from 'chai'; +import { spec } from 'modules/yieldlabBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const DEFAULT_REQUEST = () => ({ bidder: 'yieldlab', @@ -11,11 +11,11 @@ const DEFAULT_REQUEST = () => ({ targeting: { key1: 'value1', key2: 'value2', - notDoubleEncoded: 'value3,value4' + notDoubleEncoded: 'value3,value4', }, customParams: { extraParam: true, - foo: 'bar' + foo: 'bar', }, extId: 'abc', iabContent: { @@ -31,8 +31,8 @@ const DEFAULT_REQUEST = () => ({ cat: ['cat1', 'cat2,ppp', 'cat3|||//'], context: '7', keywords: ['k1,', 'k2..'], - live: '0' - } + live: '0', + }, }, bidderRequestId: '143346cf0f1731', auctionId: '2e41f65424c87c', @@ -43,14 +43,14 @@ const DEFAULT_REQUEST = () => ({ source: 'netid.de', uids: [{ id: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg', - atype: 1 - }] + atype: 1, + }], }, { source: 'digitrust.de', uids: [{ id: 'd8aa10fa-d86c-451d-aad8-5f16162a9e64', - atype: 2 - }] + atype: 2, + }], }], schain: { ver: '1.0', @@ -59,32 +59,32 @@ const DEFAULT_REQUEST = () => ({ { asi: 'indirectseller.com', sid: '1', - hp: 1 + hp: 1, }, { asi: 'indirectseller2.com', name: 'indirectseller2 name with comma , and bang !', sid: '2', - hp: 1 - } - ] - } -}) + hp: 1, + }, + ], + }, +}); const VIDEO_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { mediaTypes: { video: { playerSize: [[640, 480]], - context: 'instream' - } - } -}) + context: 'instream', + }, + }, +}); const NATIVE_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { mediaTypes: { - native: {} - } -}) + native: {}, + }, +}); const IAB_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { params: { @@ -119,7 +119,7 @@ const IAB_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { name: 'bar', cattax: 532, cat: [1, 'foo', true], - domain: 'producer.test' + domain: 'producer.test', }, data: { id: 'foo', @@ -129,8 +129,8 @@ const IAB_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { value: 'bar', ext: { foo: { - bar: 'bar' - } + bar: 'bar', + }, }, }, { name: 'foo2', @@ -139,27 +139,27 @@ const IAB_REQUEST = () => Object.assign(DEFAULT_REQUEST(), { test: { nums: { int: 123, - float: 123.123 + float: 123.123, }, bool: true, - string: 'foo2' - } - } + string: 'foo2', + }, + }, }], }, network: { id: 'foo', name: 'bar', - domain: 'network.test' + domain: 'network.test', }, channel: { id: 'bar', name: 'foo', - domain: 'channel.test' - } - } - } -}) + domain: 'channel.test', + }, + }, + }, +}); const RESPONSE = { advertiser: 'yieldlab', @@ -169,173 +169,173 @@ const RESPONSE = { price: 1, pid: 2222, adsize: '728x90', - adtype: 'BANNER' -} + adtype: 'BANNER', +}; const NATIVE_RESPONSE = Object.assign({}, RESPONSE, { adtype: 'NATIVE', native: { link: { - url: 'https://www.yieldlab.de' + url: 'https://www.yieldlab.de', }, assets: [ { id: 1, title: { - text: 'This is a great headline' - } + text: 'This is a great headline', + }, }, { id: 2, img: { url: 'https://localhost:8080/yl-logo100x100.jpg', w: 100, - h: 100 - } + h: 100, + }, }, { id: 3, data: { - value: 'Native body value' - } - } + value: 'Native body value', + }, + }, ], imptrackers: [ 'http://localhost:8080/ve?d=ODE9ZSY2MTI1MjAzNjMzMzYxPXN0JjA0NWUwZDk0NTY5Yi05M2FiLWUwZTQtOWFjNy1hYWY0MzFiZj1kaXQmMj12', 'http://localhost:8080/md/1111/9efa4e76-2030-4f04-bb9f-322541f8d611?mdata=false&pvid=false&ids=x:1', - 'http://localhost:8080/imp?s=13216&d=2171514&a=12548955&ts=1633363025216&tid=fb134faa-7ca9-4e0e-ba39-b96549d0e540&l=0' - ] - } -}) + 'http://localhost:8080/imp?s=13216&d=2171514&a=12548955&ts=1633363025216&tid=fb134faa-7ca9-4e0e-ba39-b96549d0e540&l=0', + ], + }, +}); const VIDEO_RESPONSE = Object.assign({}, RESPONSE, { - adtype: 'VIDEO' -}) + adtype: 'VIDEO', +}); const PVID_RESPONSE = Object.assign({}, VIDEO_RESPONSE, { - pvid: '43513f11-55a0-4a83-94e5-0ebc08f54a2c' -}) + pvid: '43513f11-55a0-4a83-94e5-0ebc08f54a2c', +}); const REQPARAMS = { json: true, - ts: 1234567890 -} + ts: 1234567890, +}; const REQPARAMS_GDPR = Object.assign({}, REQPARAMS, { gdpr: true, - consent: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA' -}) + consent: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA', +}); const REQPARAMS_IAB_CONTENT = Object.assign({}, REQPARAMS, { - iab_content: 'id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0' -}) + iab_content: 'id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0', +}); describe('yieldlabBidAdapter', () => { describe('instantiation from spec', () => { it('is working properly', () => { - const yieldlabBidAdapter = newBidder(spec) - expect(yieldlabBidAdapter.callBids).to.exist.and.to.be.a('function') - }) - }) + const yieldlabBidAdapter = newBidder(spec); + expect(yieldlabBidAdapter.callBids).to.exist.and.to.be.a('function'); + }); + }); describe('isBidRequestValid', () => { it('should return true when all required parameters are found', () => { const request = { params: { adslotId: '1111', - supplyId: '2222' - } - } - expect(spec.isBidRequestValid(request)).to.equal(true) - }) + supplyId: '2222', + }, + }; + expect(spec.isBidRequestValid(request)).to.equal(true); + }); it('should return false when required parameters are missing', () => { - expect(spec.isBidRequestValid({})).to.equal(false) - }) - }) + expect(spec.isBidRequestValid({})).to.equal(false); + }); + }); describe('buildRequests', () => { - const bidRequests = [DEFAULT_REQUEST()] + const bidRequests = [DEFAULT_REQUEST()]; describe('default functionality', () => { - let request + let request; before(() => { - request = spec.buildRequests(bidRequests) - }) + request = spec.buildRequests(bidRequests); + }); it('sends bid request to ENDPOINT via GET', () => { - expect(request.method).to.equal('GET') - }) + expect(request.method).to.equal('GET'); + }); it('returns a list of valid requests', () => { - expect(request.validBidRequests).to.eql(bidRequests) - }) + expect(request.validBidRequests).to.eql(bidRequests); + }); it('passes single-encoded targeting to bid request', () => { - expect(request.url).to.include('t=key1%3Dvalue1%26key2%3Dvalue2%26notDoubleEncoded%3Dvalue3%2Cvalue4') - }) + expect(request.url).to.include('t=key1%3Dvalue1%26key2%3Dvalue2%26notDoubleEncoded%3Dvalue3%2Cvalue4'); + }); it('passes userids to bid request', () => { - expect(request.url).to.include('ids=netid.de%3AfH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg%2Cdigitrust.de%3Ad8aa10fa-d86c-451d-aad8-5f16162a9e64') - }) + expect(request.url).to.include('ids=netid.de%3AfH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg%2Cdigitrust.de%3Ad8aa10fa-d86c-451d-aad8-5f16162a9e64'); + }); it('passes atype to bid request', () => { - expect(request.url).to.include('atypes=netid.de%3A1%2Cdigitrust.de%3A2') - }) + expect(request.url).to.include('atypes=netid.de%3A1%2Cdigitrust.de%3A2'); + }); it('passes extra params to bid request', () => { - expect(request.url).to.include('extraParam=true&foo=bar') - }) + expect(request.url).to.include('extraParam=true&foo=bar'); + }); it('passes unencoded schain string to bid request', () => { - expect(request.url).to.include('schain=1.0,1!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,') - }) + expect(request.url).to.include('schain=1.0,1!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,'); + }); it('passes iab_content string to bid request', () => { - expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0') - }) + expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0'); + }); it('passes correct size to bid request', () => { - expect(request.url).to.include('728x90') - }) + expect(request.url).to.include('728x90'); + }); it('passes external id to bid request', () => { - expect(request.url).to.include('id=abc') - }) - }) + expect(request.url).to.include('id=abc'); + }); + }); describe('iab_content handling', () => { const siteConfig = { ortb2: { site: { content: { - id: 'id_from_config' - } - } - } - } + id: 'id_from_config', + }, + }, + }, + }; beforeEach(() => { - config.setConfig(siteConfig) - }) + config.setConfig(siteConfig); + }); afterEach(() => { - config.resetConfig() - }) + config.resetConfig(); + }); it('generates iab_content string from bidder params', () => { - const request = spec.buildRequests(bidRequests) - expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0') - }) + const request = spec.buildRequests(bidRequests); + expect(request.url).to.include('iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0'); + }); it('generates iab_content string from first party data if not provided in bidder params', () => { - const requestWithoutIabContent = DEFAULT_REQUEST() - delete requestWithoutIabContent.params.iabContent + const requestWithoutIabContent = DEFAULT_REQUEST(); + delete requestWithoutIabContent.params.iabContent; - const request = spec.buildRequests([{...requestWithoutIabContent, ...siteConfig}]) - expect(request.url).to.include('iab_content=id%3Aid_from_config') - }) + const request = spec.buildRequests([{...requestWithoutIabContent, ...siteConfig}]); + expect(request.url).to.include('iab_content=id%3Aid_from_config'); + }); it('flattens the iabContent, encodes the values, joins the keywords into one value, and than encodes the iab_content request param ', () => { const expectedIabContentValue = encodeURIComponent( @@ -382,18 +382,18 @@ describe('yieldlabBidAdapter', () => { 'channel.id:bar,' + 'channel.name:foo,' + 'channel.domain:channel.test' - ) - const request = spec.buildRequests([IAB_REQUEST()], REQPARAMS) - expect(request.url).to.include('iab_content=' + expectedIabContentValue) - }) - }) + ); + const request = spec.buildRequests([IAB_REQUEST()], REQPARAMS); + expect(request.url).to.include('iab_content=' + expectedIabContentValue); + }); + }); it('passes unencoded schain string to bid request when complete == 0', () => { - const schainRequest = DEFAULT_REQUEST() + const schainRequest = DEFAULT_REQUEST(); schainRequest.schain.complete = 0; // - const request = spec.buildRequests([schainRequest]) - expect(request.url).to.include('schain=1.0,0!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,') - }) + const request = spec.buildRequests([schainRequest]); + expect(request.url).to.include('schain=1.0,0!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,'); + }); it('passes encoded referer to bid request', () => { const refererRequest = spec.buildRequests(bidRequests, { @@ -402,123 +402,123 @@ describe('yieldlabBidAdapter', () => { numIframes: 0, reachedTop: true, page: 'https://www.yieldlab.de/test?with=querystring', - stack: ['https://www.yieldlab.de/test?with=querystring'] - } - }) + stack: ['https://www.yieldlab.de/test?with=querystring'], + }, + }); - expect(refererRequest.url).to.include('pubref=https%3A%2F%2Fwww.yieldlab.de%2Ftest%3Fwith%3Dquerystring') - }) + expect(refererRequest.url).to.include('pubref=https%3A%2F%2Fwww.yieldlab.de%2Ftest%3Fwith%3Dquerystring'); + }); it('passes gdpr flag and consent if present', () => { const gdprRequest = spec.buildRequests(bidRequests, { gdprConsent: { consentString: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA', - gdprApplies: true - } - }) + gdprApplies: true, + }, + }); - expect(gdprRequest.url).to.include('consent=BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA') - expect(gdprRequest.url).to.include('gdpr=true') - }) + expect(gdprRequest.url).to.include('consent=BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA'); + expect(gdprRequest.url).to.include('gdpr=true'); + }); describe('sizes handling', () => { it('passes correct size to bid request for mediaType banner', () => { const bannerRequest = DEFAULT_REQUEST(); bannerRequest.mediaTypes = { banner: { - sizes: [[123, 456]] - } - } + sizes: [[123, 456]], + }, + }; // when mediaTypes is present it has precedence over the sizes field (728, 90) - let request = spec.buildRequests([bannerRequest], REQPARAMS) - expect(request.url).to.include('sizes') - expect(request.url).to.include('123x456') - - bannerRequest.mediaTypes.banner.sizes = [123, 456] - request = spec.buildRequests([bannerRequest], REQPARAMS) - expect(request.url).to.include('123x456') - - bannerRequest.mediaTypes.banner.sizes = [[123, 456], [320, 240]] - request = spec.buildRequests([bannerRequest], REQPARAMS) - expect(request.url).to.include('123x456') - expect(request.url).to.include('320x240') - }) + let request = spec.buildRequests([bannerRequest], REQPARAMS); + expect(request.url).to.include('sizes'); + expect(request.url).to.include('123x456'); + + bannerRequest.mediaTypes.banner.sizes = [123, 456]; + request = spec.buildRequests([bannerRequest], REQPARAMS); + expect(request.url).to.include('123x456'); + + bannerRequest.mediaTypes.banner.sizes = [[123, 456], [320, 240]]; + request = spec.buildRequests([bannerRequest], REQPARAMS); + expect(request.url).to.include('123x456'); + expect(request.url).to.include('320x240'); + }); it('passes correct sizes to bid request when mediaType is not present', () => { // information is taken from the top level sizes field const sizesRequest = DEFAULT_REQUEST(); - let request = spec.buildRequests([sizesRequest], REQPARAMS) - expect(request.url).to.include('sizes') - expect(request.url).to.include('728x90') + let request = spec.buildRequests([sizesRequest], REQPARAMS); + expect(request.url).to.include('sizes'); + expect(request.url).to.include('728x90'); - sizesRequest.sizes = [[728, 90]] - request = spec.buildRequests([sizesRequest], REQPARAMS) - expect(request.url).to.include('728x90') + sizesRequest.sizes = [[728, 90]]; + request = spec.buildRequests([sizesRequest], REQPARAMS); + expect(request.url).to.include('728x90'); - sizesRequest.sizes = [[728, 90], [320, 240]] - request = spec.buildRequests([sizesRequest], REQPARAMS) - expect(request.url).to.include('728x90') - }) + sizesRequest.sizes = [[728, 90], [320, 240]]; + request = spec.buildRequests([sizesRequest], REQPARAMS); + expect(request.url).to.include('728x90'); + }); it('does not pass the sizes parameter for mediaType video', () => { const videoRequest = VIDEO_REQUEST(); - let request = spec.buildRequests([videoRequest], REQPARAMS) - expect(request.url).to.not.include('sizes') - }) + let request = spec.buildRequests([videoRequest], REQPARAMS); + expect(request.url).to.not.include('sizes'); + }); it('does not pass the sizes parameter for mediaType native', () => { const nativeRequest = NATIVE_REQUEST(); - let request = spec.buildRequests([nativeRequest], REQPARAMS) - expect(request.url).to.not.include('sizes') - }) - }) - }) + let request = spec.buildRequests([nativeRequest], REQPARAMS); + expect(request.url).to.not.include('sizes'); + }); + }); + }); describe('interpretResponse', () => { - let bidRequest + let bidRequest; before(() => { - bidRequest = DEFAULT_REQUEST() - }) + bidRequest = DEFAULT_REQUEST(); + }); it('handles nobid responses', () => { - expect(spec.interpretResponse({body: {}}, {validBidRequests: []}).length).to.equal(0) - expect(spec.interpretResponse({body: []}, {validBidRequests: []}).length).to.equal(0) - }) + expect(spec.interpretResponse({body: {}}, {validBidRequests: []}).length).to.equal(0); + expect(spec.interpretResponse({body: []}, {validBidRequests: []}).length).to.equal(0); + }); it('should get correct bid response', () => { - const result = spec.interpretResponse({body: [RESPONSE]}, {validBidRequests: [bidRequest], queryParams: REQPARAMS}) - - expect(result[0].requestId).to.equal('2d925f27f5079f') - expect(result[0].cpm).to.equal(0.01) - expect(result[0].width).to.equal(728) - expect(result[0].height).to.equal(90) - expect(result[0].creativeId).to.equal('1111') - expect(result[0].dealId).to.equal(2222) - expect(result[0].currency).to.equal('EUR') - expect(result[0].netRevenue).to.equal(false) - expect(result[0].ttl).to.equal(300) - expect(result[0].referrer).to.equal('') - expect(result[0].meta.advertiserDomains).to.equal('yieldlab') - expect(result[0].ad).to.include('') From 36834f40c300fb862e84fd975b42656761708a9b Mon Sep 17 00:00:00 2001 From: Robert Ray Martinez III Date: Tue, 17 Jan 2023 11:58:27 -0800 Subject: [PATCH 263/367] PBjs Core (Price Floors) : Support inverseBidAdjustment function (#9395) * support inverseBidAdjustment function * pass in bidRequest object to adjustments * dont do fake bids bobby duh --- modules/priceFloors.js | 16 ++- test/spec/modules/priceFloors_spec.js | 155 ++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 5 deletions(-) diff --git a/modules/priceFloors.js b/modules/priceFloors.js index 8b5976149d0..32b3cbaa607 100644 --- a/modules/priceFloors.js +++ b/modules/priceFloors.js @@ -179,10 +179,10 @@ function generatePossibleEnumerations(arrayOfFields, delimiter) { /** * @summary If a the input bidder has a registered cpmadjustment it returns the input CPM after being adjusted */ -export function getBiddersCpmAdjustment(bidderName, inputCpm, bid = {}) { +export function getBiddersCpmAdjustment(bidderName, inputCpm, bid, bidRequest) { const adjustmentFunction = bidderSettings.get(bidderName, 'bidCpmAdjustment'); if (adjustmentFunction) { - return parseFloat(adjustmentFunction(inputCpm, {...bid, cpm: inputCpm})); + return parseFloat(adjustmentFunction(inputCpm, { ...bid, cpm: inputCpm }, bidRequest)); } return parseFloat(inputCpm); } @@ -249,8 +249,14 @@ export function getFloor(requestParams = {currency: 'USD', mediaType: '*', size: // if cpmAdjustment flag is true and we have a valid floor then run the adjustment on it if (floorData.enforcement.bidAdjustment && floorInfo.matchingFloor) { - let cpmAdjustment = getBiddersCpmAdjustment(bidRequest.bidder, floorInfo.matchingFloor); - floorInfo.matchingFloor = cpmAdjustment ? calculateAdjustedFloor(floorInfo.matchingFloor, cpmAdjustment) : floorInfo.matchingFloor; + // pub provided inverse function takes precedence, otherwise do old adjustment stuff + const inverseFunction = bidderSettings.get(bidRequest.bidder, 'inverseBidAdjustment'); + if (inverseFunction) { + floorInfo.matchingFloor = inverseFunction(floorInfo.matchingFloor, bidRequest); + } else { + let cpmAdjustment = getBiddersCpmAdjustment(bidRequest.bidder, floorInfo.matchingFloor, {}, bidRequest); + floorInfo.matchingFloor = cpmAdjustment ? calculateAdjustedFloor(floorInfo.matchingFloor, cpmAdjustment) : floorInfo.matchingFloor; + } } if (floorInfo.matchingFloor) { @@ -731,7 +737,7 @@ export const addBidResponseHook = timedBidResponseHook('priceFloors', function a } // ok we got the bid response cpm in our desired currency. Now we need to run the bidders CPMAdjustment function if it exists - adjustedCpm = getBiddersCpmAdjustment(bid.bidderCode, adjustedCpm, bid); + adjustedCpm = getBiddersCpmAdjustment(bid.bidderCode, adjustedCpm, bid, matchingBidRequest); // add necessary data information for analytics adapters / floor providers would possibly need addFloorDataToBid(floorData, floorInfo, bid, adjustedCpm); diff --git a/test/spec/modules/priceFloors_spec.js b/test/spec/modules/priceFloors_spec.js index b7d771814d0..f232631d73d 100644 --- a/test/spec/modules/priceFloors_spec.js +++ b/test/spec/modules/priceFloors_spec.js @@ -1495,6 +1495,161 @@ describe('the price floors module', function () { }); }); + it('should use inverseFloorAdjustment function before bidder cpm adjustment', function () { + let functionUsed; + getGlobal().bidderSettings = { + rubicon: { + bidCpmAdjustment: function (bidCpm, bidResponse) { + functionUsed = 'Rubicon Adjustment'; + bidCpm *= 0.5; + if (bidResponse.mediaType === 'video') bidCpm -= 0.18; + return bidCpm; + }, + inverseBidAdjustment: function (bidCpm, bidRequest) { + functionUsed = 'Rubicon Inverse'; + // if video is the only mediaType on Bid Request => add 0.18 + if (bidRequest.mediaTypes.video && Object.keys(bidRequest.mediaTypes).length === 1) bidCpm += 0.18; + return bidCpm / 0.5; + }, + }, + appnexus: { + bidCpmAdjustment: function (bidCpm, bidResponse) { + functionUsed = 'Appnexus Adjustment'; + bidCpm *= 0.75; + if (bidResponse.mediaType === 'video') bidCpm -= 0.18; + return bidCpm; + }, + inverseBidAdjustment: function (bidCpm, bidRequest) { + functionUsed = 'Appnexus Inverse'; + // if video is the only mediaType on Bid Request => add 0.18 + if (bidRequest.mediaTypes.video && Object.keys(bidRequest.mediaTypes).length === 1) bidCpm += 0.18; + return bidCpm / 0.75; + }, + } + }; + + _floorDataForAuction[bidRequest.auctionId] = utils.deepClone(basicFloorConfig); + + _floorDataForAuction[bidRequest.auctionId].data.values = { '*': 1.0 }; + + // start with banner as only mediaType + bidRequest.mediaTypes = { banner: { sizes: [[300, 250]] } }; + let appnexusBid = { + ...bidRequest, + bidder: 'appnexus', + }; + + // should be same as the adjusted calculated inverses above test (banner) + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 2.0 + }); + + // should use rubicon inverse + expect(functionUsed).to.equal('Rubicon Inverse'); + + // appnexus just using banner should be same + expect(appnexusBid.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.3334 + }); + + expect(functionUsed).to.equal('Appnexus Inverse'); + + // now since asking for 'video' only mediaType inverse function should include the .18 + bidRequest.mediaTypes = { video: { context: 'instream' } }; + expect(bidRequest.getFloor({ mediaType: 'video' })).to.deep.equal({ + currency: 'USD', + floor: 2.36 + }); + + expect(functionUsed).to.equal('Rubicon Inverse'); + + // now since asking for 'video' inverse function should include the .18 + appnexusBid.mediaTypes = { video: { context: 'instream' } }; + expect(appnexusBid.getFloor({ mediaType: 'video' })).to.deep.equal({ + currency: 'USD', + floor: 1.5734 + }); + + expect(functionUsed).to.equal('Appnexus Inverse'); + }); + + it('should pass inverseFloorAdjustment the bidRequest object so it can be used', function () { + // Adjustment factors based on Bid Media Type + const mediaTypeFactors = { + banner: 0.5, + native: 0.7, + video: 0.9 + } + getGlobal().bidderSettings = { + rubicon: { + bidCpmAdjustment: function (bidCpm, bidResponse) { + return bidCpm * mediaTypeFactors[bidResponse.mediaType]; + }, + inverseBidAdjustment: function (bidCpm, bidRequest) { + // For the inverse we add up each mediaType in the request and divide by number of Mt's to get the inverse number + let factor = Object.keys(bidRequest.mediaTypes).reduce((sum, mediaType) => sum += mediaTypeFactors[mediaType], 0); + factor = factor / Object.keys(bidRequest.mediaTypes).length; + return bidCpm / factor; + }, + } + }; + + _floorDataForAuction[bidRequest.auctionId] = utils.deepClone(basicFloorConfig); + + _floorDataForAuction[bidRequest.auctionId].data.values = { '*': 1.0 }; + + // banner only should be 2 + bidRequest.mediaTypes = { banner: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 2.0 + }); + + // native only should be 1.4286 + bidRequest.mediaTypes = { native: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.4286 + }); + + // video only should be 1.1112 + bidRequest.mediaTypes = { video: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.1112 + }); + + // video and banner should even out to 0.7 factor so 1.4286 + bidRequest.mediaTypes = { video: {}, banner: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.4286 + }); + + // video and native should even out to 0.8 factor so -- 1.25 + bidRequest.mediaTypes = { video: {}, native: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.25 + }); + + // banner and native should even out to 0.6 factor so -- 1.6667 + bidRequest.mediaTypes = { banner: {}, native: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.6667 + }); + + // all 3 banner video and native should even out to 0.7 factor so -- 1.4286 + bidRequest.mediaTypes = { banner: {}, native: {}, video: {} }; + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.4286 + }); + }); + it('should use standard cpmAdjustment if no bidder cpmAdjustment', function () { getGlobal().bidderSettings = { rubicon: { From 31b662cef4819dabc196fbf631f440b792025e72 Mon Sep 17 00:00:00 2001 From: Tachfine Date: Tue, 17 Jan 2023 22:43:46 +0100 Subject: [PATCH 264/367] Criteo Bid Adapter : Bump Publisher Tag version (#9429) Update reference to version 133 (latest) --- modules/criteoBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 5567103db69..a056454564c 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -27,7 +27,7 @@ const LOG_PREFIX = 'Criteo: '; Unminified source code can be found in the privately shared repo: https://github.com/Prebid-org/prebid-js-external-js-criteo/blob/master/dist/prod.js */ const FAST_BID_VERSION_PLACEHOLDER = '%FAST_BID_VERSION%'; -export const FAST_BID_VERSION_CURRENT = 132; +export const FAST_BID_VERSION_CURRENT = 133; const FAST_BID_VERSION_LATEST = 'latest'; const FAST_BID_VERSION_NONE = 'none'; const PUBLISHER_TAG_URL_TEMPLATE = 'https://static.criteo.net/js/ld/publishertag.prebid' + FAST_BID_VERSION_PLACEHOLDER + '.js'; From 2c12cd27481cc0c248f6afe52f704faa0cbeba13 Mon Sep 17 00:00:00 2001 From: ccorbo Date: Wed, 18 Jan 2023 15:09:08 -0500 Subject: [PATCH 265/367] IX Bid Adapter: retrieve user/agent hints and fix tmax issue (#9394) * feat: passthrough gpp information when it is provided [PB-1395] * chore: passthrough using module [PB-1395] * IX Bid Adapter Changes: change mtype logic, useragent client hints, change tmax logic * remove fallback for tmax timeout Co-authored-by: Chris Corbo --- modules/ixBidAdapter.js | 31 +++++-- package-lock.json | 2 +- test/spec/modules/ixBidAdapter_spec.js | 123 +++++++++++++++++++++++-- 3 files changed, 143 insertions(+), 13 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 27e6d0aee02..bd598cf2d04 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -380,8 +380,8 @@ function parseBid(rawBid, currency, bidRequest) { bid.netRevenue = NET_REVENUE; bid.currency = currency; bid.creativeId = rawBid.hasOwnProperty('crid') ? rawBid.crid : '-'; - - if (rawBid.mtype == MEDIA_TYPES.Video) { + // If mtype = video is passed and vastURl is not set, set vastxml + if (rawBid.mtype == MEDIA_TYPES.Video && ((rawBid.ext && !rawBid.ext.vasturl) || !rawBid.ext)) { bid.vastXml = rawBid.adm; } else if (rawBid.ext && rawBid.ext.vasturl) { bid.vastUrl = rawBid.ext.vasturl; @@ -425,7 +425,6 @@ function parseBid(rawBid, currency, bidRequest) { if (rawBid.adomain && rawBid.adomain.length > 0) { bid.meta.advertiserDomains = rawBid.adomain; } - return bid; } @@ -629,8 +628,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { } const r = {}; - const tmax = config.getConfig('bidderTimeout'); - + const tmax = deepAccess(bidderRequest, 'timeout'); // Since bidderRequestId are the same for different bid request, just use the first one. r.id = validBidRequests[0].bidderRequestId.toString(); r.site = {}; @@ -720,6 +718,11 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { if (pageUrl) { r.site.page = pageUrl; } + + if (bidderRequest.gppConsent) { + deepSetValue(r, 'regs.gpp', bidderRequest.gppConsent.gppString); + deepSetValue(r, 'regs.gpp_sid', bidderRequest.gppConsent.applicableSections); + } } if (config.getConfig('coppa')) { @@ -856,7 +859,6 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { currentRequestSize += currentImpressionSize; const fpd = deepAccess(bidderRequest, 'ortb2') || {}; - if (!isEmpty(fpd) && !isFpdAdded) { r.ext.ixdiag.fpd = true; @@ -876,6 +878,23 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { } }); + if (fpd.device) { + const sua = {...fpd.device.sua}; + if (!isEmpty(sua)) { + deepSetValue(r, 'device.sua', sua); + } + } + + if (fpd.hasOwnProperty('regs') && !bidderRequest.gppConsent) { + if (fpd.regs.hasOwnProperty('gpp') && typeof fpd.regs.gpp == 'string') { + deepSetValue(r, 'regs.gpp', fpd.regs.gpp) + } + + if (fpd.regs.hasOwnProperty('gpp_sid') && Array.isArray(fpd.regs.gpp_sid)) { + deepSetValue(r, 'regs.gpp_sid', fpd.regs.gpp_sid) + } + } + const clonedRObject = deepClone(r); clonedRObject.site = mergeDeep({}, clonedRObject.site, site); diff --git a/package-lock.json b/package-lock.json index 9701ff8c91c..54d48311d36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.31.0-pre", + "version": "7.32.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 0de300e4a32..2327376d9ac 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -658,7 +658,7 @@ describe('IndexexchangeAdapter', function () { } }; - const DEFAULT_VIDEO_BID_RESPONSE_WITH_MTYPE_SET = { + const DEFAULT_VIDEO_BID_RESPONSE_WITH_XML_ADM = { cur: 'USD', id: '1aa2bb3cc4de', seatbid: [ @@ -675,7 +675,6 @@ describe('IndexexchangeAdapter', function () { mtype: 2, adm: ' Test In-Stream Video Date: Wed, 18 Jan 2023 21:39:08 +0100 Subject: [PATCH 266/367] PBjs Core (Promises): fix static method GreedyPromise.resolve not working with Angular + Zone.js (#9426) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Webpack v5 complain about named export from JSON modules * Index Exchange Adapter: fix "Should not import the named export 'EVENTS'.'AUCTION_DEBUG' (imported as 'EVENTS') from default-exporting module (only default export is available soon)"" * fix: Uncaught TypeError: Cannot read properties of undefined (reading 'getSlotElementId') * fix: Uncaught TypeError: Cannot read properties of undefined (reading 'getSlotElementId') * fix #9422 * refactor: fix linting error Co-authored-by: Javier Marín --- src/utils/promise.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/utils/promise.js b/src/utils/promise.js index 97c64a96f8b..69e40791ab1 100644 --- a/src/utils/promise.js +++ b/src/utils/promise.js @@ -90,6 +90,14 @@ export class GreedyPromise extends (getGlobal().Promise || Promise) { res.#parent = this; return res; } + + static resolve(value) { + return new this(resolve => resolve(value)) + } + + static reject(error) { + return new this((resolve, reject) => reject(error)) + } } /** From 27884fc39175960ee54c4a5735ec9d4a594c68a1 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 19 Jan 2023 03:30:27 -0700 Subject: [PATCH 267/367] USP consent management: handle errors from CMPs that cannot deal with `registerDeletion` (#9434) --- modules/consentManagementUsp.js | 20 +++++++++---------- .../spec/modules/consentManagementUsp_spec.js | 17 ++++++++++++++-- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/modules/consentManagementUsp.js b/modules/consentManagementUsp.js index 0a99ec4a913..fcc13152aa9 100644 --- a/modules/consentManagementUsp.js +++ b/modules/consentManagementUsp.js @@ -100,6 +100,14 @@ function lookupUspConsent({onSuccess, onError}) { return onError('USP CMP not found.'); } + function registerDataDelHandler(invoker, arg2) { + try { + invoker('registerDeletion', arg2, adapterManager.callDataDeletionRequest); + } catch (e) { + logError('Error invoking CMP `registerDeletion`:', e); + } + } + // to collect the consent information from the user, we perform a call to USPAPI // to collect the user's consent choices represented as a string (via getUSPData) @@ -115,11 +123,7 @@ function lookupUspConsent({onSuccess, onError}) { USPAPI_VERSION, callbackHandler.consentDataCallback ); - uspapiFunction( - 'registerDeletion', - USPAPI_VERSION, - adapterManager.callDataDeletionRequest - ) + registerDataDelHandler(uspapiFunction, USPAPI_VERSION); } else { logInfo( 'Detected USP CMP is outside the current iframe where Prebid.js is located, calling it now...' @@ -129,11 +133,7 @@ function lookupUspConsent({onSuccess, onError}) { uspapiFrame, callbackHandler.consentDataCallback ); - callUspApiWhileInIframe( - 'registerDeletion', - uspapiFrame, - adapterManager.callDataDeletionRequest - ); + registerDataDelHandler(callUspApiWhileInIframe, uspapiFrame); } let listening = false; diff --git a/test/spec/modules/consentManagementUsp_spec.js b/test/spec/modules/consentManagementUsp_spec.js index f9c3cd5890e..e98486754ab 100644 --- a/test/spec/modules/consentManagementUsp_spec.js +++ b/test/spec/modules/consentManagementUsp_spec.js @@ -8,7 +8,7 @@ import { } from 'modules/consentManagementUsp.js'; import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; -import adapterManager, {uspDataHandler} from 'src/adapterManager.js'; +import adapterManager, {gdprDataHandler, uspDataHandler} from 'src/adapterManager.js'; import 'src/prebid.js'; import {defer} from '../../../src/utils/promise.js'; @@ -508,7 +508,20 @@ describe('consentManagement', function () { sinon.assert.notCalled(adapterManager.callDataDeletionRequest); listener(); sinon.assert.calledOnce(adapterManager.callDataDeletionRequest); - }) + }); + + it('does not fail if CMP does not support registerDeletion', () => { + sandbox.stub(window, '__uspapi').callsFake((cmd, _, cb) => { + if (cmd === 'registerDeletion') { + throw new Error('CMP not compliant'); + } else if (cmd === 'getUSPData') { + // eslint-disable-next-line standard/no-callback-literal + cb({uspString: 'string'}, true); + } + }); + setConsentConfig(goodConfig); + expect(uspDataHandler.getConsentData()).to.eql('string'); + }); }); }); }); From 352fcb3d4a27b6f1948b0616db945f0ed976c8b4 Mon Sep 17 00:00:00 2001 From: Gabriel Chicoye Date: Thu, 19 Jan 2023 15:08:48 +0100 Subject: [PATCH 268/367] nexx360 Bid Adapter: aliases list update (#9439) * ssp added to meta.demandSource * aliases update --- modules/nexx360BidAdapter.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/nexx360BidAdapter.js b/modules/nexx360BidAdapter.js index 96738f586c1..b04bb47543f 100644 --- a/modules/nexx360BidAdapter.js +++ b/modules/nexx360BidAdapter.js @@ -21,7 +21,8 @@ export const spec = { gvlid: GVLID, aliases: [ { code: 'revenuemaker' }, - { code: 'firstid-ssp' }, + { code: 'first-id', gvlid: 1178 }, + { code: 'adwebone' }, ], supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid, From 452fbabe9144d869f1b898e35f3328b333f8f007 Mon Sep 17 00:00:00 2001 From: Wiem Zine El Abidine Date: Thu, 19 Jan 2023 15:26:21 +0100 Subject: [PATCH 269/367] Update live-connect-js version (#9438) * update live-connect-js * fix * fix package-lock.json --- package-lock.json | 16 ++++++++-------- package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 54d48311d36..fcdd783bb75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.32.0-pre", + "version": "7.33.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -22,7 +22,7 @@ "express": "^4.15.4", "fun-hooks": "^0.9.9", "just-clone": "^1.0.2", - "live-connect-js": "3.0.1" + "live-connect-js": "3.0.5" }, "devDependencies": { "@babel/eslint-parser": "^7.16.5", @@ -16229,9 +16229,9 @@ "dev": true }, "node_modules/live-connect-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-3.0.1.tgz", - "integrity": "sha512-rwB0IQfuKPJM+I96nLyq8Utr3LkQ7Z/iuq/xKlWDckQRJLYyWkk7F7yaavf/VsjazzLK2dpJeXGijoDkK4Vz8g==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-3.0.5.tgz", + "integrity": "sha512-KqxE+V/050nK2tUx8PnAtQBOK4E29WVasQTrLkkCwSebmV5uqMu+VMcwhJSbnyh/g+GhDAE/LL9RB6X9vcmLrg==", "dependencies": { "tiny-hashes": "1.0.1" }, @@ -37865,9 +37865,9 @@ "dev": true }, "live-connect-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-3.0.1.tgz", - "integrity": "sha512-rwB0IQfuKPJM+I96nLyq8Utr3LkQ7Z/iuq/xKlWDckQRJLYyWkk7F7yaavf/VsjazzLK2dpJeXGijoDkK4Vz8g==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-3.0.5.tgz", + "integrity": "sha512-KqxE+V/050nK2tUx8PnAtQBOK4E29WVasQTrLkkCwSebmV5uqMu+VMcwhJSbnyh/g+GhDAE/LL9RB6X9vcmLrg==", "requires": { "tiny-hashes": "1.0.1" } diff --git a/package.json b/package.json index 58c50ee882e..6101967c552 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "express": "^4.15.4", "fun-hooks": "^0.9.9", "just-clone": "^1.0.2", - "live-connect-js": "3.0.1" + "live-connect-js": "3.0.5" }, "optionalDependencies": { "fsevents": "^2.3.2" From 1e318fde36659a6b072bfbc46463efb038f75422 Mon Sep 17 00:00:00 2001 From: Yohan Boutin Date: Thu, 19 Jan 2023 18:44:03 +0100 Subject: [PATCH 270/367] enable video/banner mediatypes for inImage/inBanner/inArticle/inScreen (#9417) --- modules/seedtagBidAdapter.js | 26 +++++-- test/spec/modules/seedtagBidAdapter_spec.js | 75 ++++++++++++++++----- 2 files changed, 78 insertions(+), 23 deletions(-) diff --git a/modules/seedtagBidAdapter.js b/modules/seedtagBidAdapter.js index d5abb89437b..f54245a41ab 100644 --- a/modules/seedtagBidAdapter.js +++ b/modules/seedtagBidAdapter.js @@ -60,6 +60,10 @@ function hasVideoMediaType(bid) { return !!bid.mediaTypes && !!bid.mediaTypes.video; } +function hasBannerMediaType(bid) { + return !!bid.mediaTypes && !!bid.mediaTypes.banner; +} + function hasMandatoryDisplayParams(bid) { const p = bid.params; return ( @@ -72,17 +76,27 @@ function hasMandatoryDisplayParams(bid) { function hasMandatoryVideoParams(bid) { const videoParams = getVideoParams(bid); - return ( + let isValid = !!bid.params.publisherId && !!bid.params.adUnitId && hasVideoMediaType(bid) && !!videoParams.playerSize && isArray(videoParams.playerSize) && - videoParams.playerSize.length > 0 && - // only instream is supported for video - videoParams.context === 'instream' && - bid.params.placement === 'inStream' - ); + videoParams.playerSize.length > 0; + + switch (bid.params.placement) { + // instream accept only video format + case 'inStream': + return isValid && videoParams.context === 'instream'; + // outstream accept banner/native/video format + default: + return ( + isValid && + videoParams.context === 'outstream' && + hasBannerMediaType(bid) && + hasMandatoryDisplayParams(bid) + ); + } } function buildBidRequest(validBidRequest) { diff --git a/test/spec/modules/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js index cfdd3365269..3627296975b 100644 --- a/test/spec/modules/seedtagBidAdapter_spec.js +++ b/test/spec/modules/seedtagBidAdapter_spec.js @@ -33,30 +33,60 @@ function createInStreamSlotConfig(mediaType) { }); } +const createBannerSlotConfig = (placement, mediatypes) => { + return getSlotConfigs(mediatypes || { banner: {} }, { + publisherId: PUBLISHER_ID, + adUnitId: ADUNIT_ID, + placement, + }); +}; + describe('Seedtag Adapter', function () { 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 createBannerSlotConfig = (placement) => { - return getSlotConfigs( - { banner: {} }, - { - publisherId: PUBLISHER_ID, - adUnitId: ADUNIT_ID, - placement, - } + const placements = ['inBanner', 'inImage', 'inScreen', 'inArticle']; + placements.forEach((placement) => { + it(placement + 'should be valid', function () { + const isBidRequestValid = spec.isBidRequestValid( + createBannerSlotConfig(placement) ); - }; - const placements = ['inBanner', 'inImage', 'inScreen', 'inArticle']; - placements.forEach((placement) => { - it('should be ' + placement, function () { + expect(isBidRequestValid).to.equal(true); + }); + + it( + placement + + ' should be valid when has display and video mediatypes, and video context is outstream', + function () { const isBidRequestValid = spec.isBidRequestValid( - createBannerSlotConfig(placement) + createBannerSlotConfig(placement, { + banner: {}, + video: { + context: 'outstream', + playerSize: [[600, 200]], + }, + }) ); expect(isBidRequestValid).to.equal(true); - }); - }); + } + ); + + it( + placement + + " shouldn't be valid when has display and video mediatypes, and video context is instream", + function () { + const isBidRequestValid = spec.isBidRequestValid( + createBannerSlotConfig(placement, { + banner: {}, + video: { + context: 'instream', + playerSize: [[600, 200]], + }, + }) + ); + expect(isBidRequestValid).to.equal(false); + } + ); }); }); describe('when video slot has all mandatory params', function () { @@ -70,7 +100,18 @@ describe('Seedtag Adapter', function () { const isBidRequestValid = spec.isBidRequestValid(slotConfig); expect(isBidRequestValid).to.equal(true); }); - it('should return true, when video context is instream, but placement is not inStream', function () { + it('should return true, when video context is instream and mediatype is video and banner', function () { + const slotConfig = createInStreamSlotConfig({ + video: { + context: 'instream', + playerSize: [[600, 200]], + }, + banner: {}, + }); + const isBidRequestValid = spec.isBidRequestValid(slotConfig); + expect(isBidRequestValid).to.equal(true); + }); + it('should return false, when video context is instream, but placement is not inStream', function () { const slotConfig = getSlotConfigs( { video: { From 26e53fe98fafa9f058605e1cb729edde310eb503 Mon Sep 17 00:00:00 2001 From: pkwisniowski-id5 <121963897+pkwisniowski-id5@users.noreply.github.com> Date: Fri, 20 Jan 2023 11:15:21 +0100 Subject: [PATCH 271/367] The payload extended with document.referer and canonicalUrl (#9416) --- modules/id5IdSystem.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/id5IdSystem.js b/modules/id5IdSystem.js index c2c4a97c62e..a0745df37c8 100644 --- a/modules/id5IdSystem.js +++ b/modules/id5IdSystem.js @@ -247,7 +247,9 @@ class IdFetchFlow { 'gdpr': hasGdpr, 'nbPage': nbPage, 'o': 'pbjs', - 'rf': referer.topmostLocation, + 'tml': referer.topmostLocation, + 'ref': referer.ref, + 'cu': referer.canonicalUrl, 'top': referer.reachedTop ? 1 : 0, 'u': referer.stack[0] || window.location.href, 'v': '$prebid.version$', From 4096bec171ba5736988cdeb4fdf77aef79f98204 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 20 Jan 2023 16:49:38 +0000 Subject: [PATCH 272/367] Prebid 7.33.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index fcdd783bb75..ed18633033b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.33.0-pre", + "version": "7.33.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 6101967c552..07d848a5592 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.33.0-pre", + "version": "7.33.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 165233b99cd87326eb0b3b96f796aa6767dc6d7c Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 20 Jan 2023 16:49:38 +0000 Subject: [PATCH 273/367] Increment version to 7.34.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ed18633033b..3d5072df524 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.33.0", + "version": "7.34.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 07d848a5592..4b52267af26 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.33.0", + "version": "7.34.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 678d13653f381c6c56395f12150c12d3bda1da4c Mon Sep 17 00:00:00 2001 From: Daria Boyko Date: Mon, 23 Jan 2023 10:54:57 +0200 Subject: [PATCH 274/367] Admixer Bid Adapter : adding floor module support and new alias (#9427) * add floor module support * bidFloor update * Update admixerBidAdapter.md * Update admixerBidAdapter.js * remove tests * tests * floor test * Update admixerBidAdapter_spec.js * Update admixerBidAdapter_spec.js * Update admixerBidAdapter.js * https endpoint * lint bugs fix --- modules/admixerBidAdapter.js | 30 ++- test/spec/modules/admixerBidAdapter_spec.js | 200 ++++++++++++++------ 2 files changed, 166 insertions(+), 64 deletions(-) diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js index 90031ed7f5d..8dbcfdafd32 100644 --- a/modules/admixerBidAdapter.js +++ b/modules/admixerBidAdapter.js @@ -1,12 +1,14 @@ -import { logError } from '../src/utils.js'; +import {logError} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js'; -import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; const BIDDER_CODE = 'admixer'; -const ALIASES = ['go2net', 'adblender', 'adsyield', 'futureads', 'smn']; +const BIDDER_CODE_ADX = 'admixeradx'; +const ALIASES = ['go2net', 'adblender', 'adsyield', 'futureads', 'admixeradx']; const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.2.aspx'; +const ADX_ENDPOINT_URL = 'https://inv-nets.admixer.net/adxprebid.1.2.aspx'; export const spec = { code: BIDDER_CODE, aliases: ALIASES, @@ -57,6 +59,10 @@ export const spec = { if (bidderRequest.uspConsent) { payload.uspConsent = bidderRequest.uspConsent; } + let bidFloor = getBidFloor(bidderRequest); + if (bidFloor) { + payload.bidFloor = bidFloor; + } } validRequest.forEach((bid) => { let imp = {}; @@ -65,7 +71,11 @@ export const spec = { }); return { method: 'POST', - url: endpointUrl || ENDPOINT_URL, + url: + endpointUrl || + (bidderRequest.bidderCode === BIDDER_CODE_ADX + ? ADX_ENDPOINT_URL + : ENDPOINT_URL), data: payload, }; }, @@ -96,4 +106,16 @@ export const spec = { return pixels; } }; +function getBidFloor(bid) { + try { + const bidFloor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (_) { + return 0; + } +} registerBidder(spec); diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js index 228b87ae4d5..26caaf5b70f 100644 --- a/test/spec/modules/admixerBidAdapter_spec.js +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -4,8 +4,10 @@ import {newBidder} from 'src/adapters/bidderFactory.js'; import {config} from '../../../src/config.js'; const BIDDER_CODE = 'admixer'; +const BIDDER_CODE_ADX = 'admixeradx'; const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.2.aspx'; const ENDPOINT_URL_CUSTOM = 'https://custom.admixer.net/prebid.aspx'; +const ENDPOINT_URL_ADX = 'https://inv-nets.admixer.net/adxprebid.1.2.aspx'; const ZONE_ID = '2eb6bd58-865c-47ce-af7f-a918108c3fd2'; describe('AdmixerAdapter', function () { @@ -16,18 +18,22 @@ describe('AdmixerAdapter', function () { expect(adapter.callBids).to.be.exist.and.to.be.a('function'); }); }); + // inv-nets.admixer.net/adxprebid.1.2.aspx describe('isBidRequestValid', function () { let bid = { - 'bidder': BIDDER_CODE, - 'params': { - 'zone': ZONE_ID + bidder: BIDDER_CODE, + params: { + zone: ZONE_ID, }, - 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250], [300, 600]], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', + adUnitCode: 'adunit-code', + sizes: [ + [300, 250], + [300, 600], + ], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', }; it('should return true when required params found', function () { @@ -38,7 +44,7 @@ describe('AdmixerAdapter', function () { let bid = Object.assign({}, bid); delete bid.params; bid.params = { - 'placementId': 0 + placementId: 0, }; expect(spec.isBidRequestValid(bid)).to.equal(false); }); @@ -47,22 +53,25 @@ describe('AdmixerAdapter', function () { describe('buildRequests', function () { let validRequest = [ { - 'bidder': BIDDER_CODE, - 'params': { - 'zone': ZONE_ID + bidder: BIDDER_CODE, + params: { + zone: ZONE_ID, }, - 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250], [300, 600]], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - } + adUnitCode: 'adunit-code', + sizes: [ + [300, 250], + [300, 600], + ], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + }, ]; let bidderRequest = { bidderCode: BIDDER_CODE, refererInfo: { - page: 'https://example.com' - } + page: 'https://example.com', + }, }; it('should add referrer and imp to be equal bidRequest', function () { @@ -81,49 +90,122 @@ describe('AdmixerAdapter', function () { it('sends bid request to CUSTOM_ENDPOINT via GET', function () { config.setBidderConfig({ bidders: [BIDDER_CODE], // one or more bidders - config: {[BIDDER_CODE]: {endpoint_url: ENDPOINT_URL_CUSTOM}} + config: { [BIDDER_CODE]: { endpoint_url: ENDPOINT_URL_CUSTOM } }, }); - const request = config.runWithBidder(BIDDER_CODE, () => spec.buildRequests(validRequest, bidderRequest)); + const request = config.runWithBidder(BIDDER_CODE, () => + spec.buildRequests(validRequest, bidderRequest) + ); expect(request.url).to.equal(ENDPOINT_URL_CUSTOM); expect(request.method).to.equal('POST'); }); }); + describe('buildRequestsAdmixerADX', function () { + let validRequest = [ + { + bidder: BIDDER_CODE_ADX, + params: { + zone: ZONE_ID, + }, + adUnitCode: 'adunit-code', + sizes: [ + [300, 250], + [300, 600], + ], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + }, + ]; + let bidderRequest = { + bidderCode: BIDDER_CODE_ADX, + refererInfo: { + page: 'https://example.com', + }, + }; + + it('sends bid request to ADX ENDPOINT', function () { + const request = spec.buildRequests(validRequest, bidderRequest); + expect(request.url).to.equal(ENDPOINT_URL_ADX); + expect(request.method).to.equal('POST'); + }); + }); + + describe('checkFloorGetting', function () { + let validRequest = [ + { + bidder: BIDDER_CODE, + params: { + zone: ZONE_ID, + }, + adUnitCode: 'adunit-code', + sizes: [[300, 250]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + }, + ]; + let bidderRequest = { + bidderCode: BIDDER_CODE, + refererInfo: { + page: 'https://example.com', + }, + }; + it('gets floor', function () { + bidderRequest.getFloor = () => { + return { floor: 0.6 }; + }; + const request = spec.buildRequests(validRequest, bidderRequest); + const payload = request.data; + expect(payload.bidFloor).to.deep.equal(0.6); + }); + }); + describe('interpretResponse', function () { let response = { body: { - ads: [{ - 'currency': 'USD', - 'cpm': 6.210000, - 'ad': '
ad
', - 'width': 300, - 'height': 600, - 'creativeId': 'ccca3e5e-0c54-4761-9667-771322fbdffc', - 'ttl': 360, - 'netRevenue': false, - 'requestId': '5e4e763b6bc60b', - 'dealId': 'asd123', - 'meta': {'advertiserId': 123, 'networkId': 123, 'advertiserDomains': ['test.com']} - }] - } + ads: [ + { + currency: 'USD', + cpm: 6.21, + ad: '
ad
', + width: 300, + height: 600, + creativeId: 'ccca3e5e-0c54-4761-9667-771322fbdffc', + ttl: 360, + netRevenue: false, + requestId: '5e4e763b6bc60b', + dealId: 'asd123', + meta: { + advertiserId: 123, + networkId: 123, + advertiserDomains: ['test.com'], + }, + }, + ], + }, }; it('should get correct bid response', function () { const ads = response.body.ads; let expectedResponse = [ { - 'requestId': ads[0].requestId, - 'cpm': ads[0].cpm, - 'creativeId': ads[0].creativeId, - 'width': ads[0].width, - 'height': ads[0].height, - 'ad': ads[0].ad, - 'currency': ads[0].currency, - 'netRevenue': ads[0].netRevenue, - 'ttl': ads[0].ttl, - 'dealId': ads[0].dealId, - 'meta': {'advertiserId': 123, 'networkId': 123, 'advertiserDomains': ['test.com']} - } + requestId: ads[0].requestId, + cpm: ads[0].cpm, + creativeId: ads[0].creativeId, + width: ads[0].width, + height: ads[0].height, + ad: ads[0].ad, + currency: ads[0].currency, + netRevenue: ads[0].netRevenue, + ttl: ads[0].ttl, + dealId: ads[0].dealId, + meta: { + advertiserId: 123, + networkId: 123, + advertiserDomains: ['test.com'], + }, + }, ]; let result = spec.interpretResponse(response); @@ -141,18 +223,16 @@ describe('AdmixerAdapter', function () { describe('getUserSyncs', function () { let imgUrl = 'https://example.com/img1'; let frmUrl = 'https://example.com/frm2'; - let responses = [{ - body: { - cm: { - pixels: [ - imgUrl - ], - iframes: [ - frmUrl - ], - } - } - }]; + let responses = [ + { + body: { + cm: { + pixels: [imgUrl], + iframes: [frmUrl], + }, + }, + }, + ]; it('Returns valid values', function () { let userSyncAll = spec.getUserSyncs({pixelEnabled: true, iframeEnabled: true}, responses); From 35be6c81a4a60cfbe442893bbe020e00f88d7546 Mon Sep 17 00:00:00 2001 From: Fatih Kaya Date: Mon, 23 Jan 2023 16:09:39 +0300 Subject: [PATCH 275/367] Admatic Bid Adapter : bugfix with AdserverCurrency param (#9451) * Admatic Bidder Adaptor * Update admaticBidAdapter.md * Update admaticBidAdapter.md * remove floor parameter * Update admaticBidAdapter.js * Admatic Bid Adapter: alias and bid floor features activated * Admatic adapter: host param control changed * Alias name changed. * Revert "Admatic adapter: host param control changed" This reverts commit de7ac85981b1ba3ad8c5d1dc95c5dadbdf5b9895. * added alias feature and host param * Revert "added alias feature and host param" This reverts commit 6ec8f4539ea6be403a0d7e08dad5c7a5228f28a1. * Revert "Alias name changed." This reverts commit 661c54f9b2397e8f25c257144d73161e13466281. * Revert "Admatic Bid Adapter: alias and bid floor features activated" This reverts commit 7a2e0e29c49e2f876b68aafe886b336fe2fe6fcb. * Revert "Update admaticBidAdapter.js" This reverts commit 7a845b7151bbb08addfb58ea9bd5b44167cc8a4e. * Revert "remove floor parameter" This reverts commit 7a23b055ccd4ea23d23e73248e82b21bc6f69d90. * Admatic adapter: host param control && Add new Bidder * Revert "Admatic adapter: host param control && Add new Bidder" This reverts commit 3c797b120c8e0fe2b851381300ac5c4b1f92c6e2. * commit new features * Update admaticBidAdapter.js * updated for coverage * sync updated * Update adloader.js * AdMatic Bidder: development of user sync url * Update admaticBidAdapter.js * Set currency for AdserverCurrency: bug fix --- modules/admaticBidAdapter.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/admaticBidAdapter.js b/modules/admaticBidAdapter.js index 148424c0a98..808c788fcb9 100644 --- a/modules/admaticBidAdapter.js +++ b/modules/admaticBidAdapter.js @@ -1,5 +1,6 @@ import { getValue, logError, deepAccess, getBidIdParameter, isArray } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; let SYNC_URL = ''; const BIDDER_CODE = 'admatic'; @@ -35,7 +36,7 @@ export const spec = { const bids = validBidRequests.map(buildRequestObject); const networkId = getValue(validBidRequests[0].params, 'networkId'); const host = getValue(validBidRequests[0].params, 'host'); - const currency = getValue(validBidRequests[0].params, 'currency') || 'TRY'; + const currency = config.getConfig('currency.adServerCurrency') || 'TRY'; const bidderName = validBidRequests[0].bidder; const payload = { From 2741fe9b2bacebedacd7ed7edf7db304fc5dafd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaros=C5=82aw=20Stropa?= <51368253+jaropenx@users.noreply.github.com> Date: Mon, 23 Jan 2023 14:43:15 +0100 Subject: [PATCH 276/367] added support for user agent client hints (#9445) --- modules/openxBidAdapter.js | 5 +++ test/spec/modules/openxBidAdapter_spec.js | 41 +++++++++++++++++++ test/spec/modules/openxOrtbBidAdapter_spec.js | 41 +++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/modules/openxBidAdapter.js b/modules/openxBidAdapter.js index 14525cd0cfc..b6f4523bb50 100644 --- a/modules/openxBidAdapter.js +++ b/modules/openxBidAdapter.js @@ -268,6 +268,11 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) { nocache: new Date().getTime() }; + const userAgentClientHints = deepAccess(bidderRequest, 'ortb2.device.sua'); + if (userAgentClientHints) { + defaultParams.sua = JSON.stringify(userAgentClientHints); + } + const userDataSegments = buildFpdQueryParams('user.data', bidderRequest.ortb2); if (userDataSegments.length > 0) { defaultParams.sm = userDataSegments; diff --git a/test/spec/modules/openxBidAdapter_spec.js b/test/spec/modules/openxBidAdapter_spec.js index cc1c2d1e607..8fe220aa202 100644 --- a/test/spec/modules/openxBidAdapter_spec.js +++ b/test/spec/modules/openxBidAdapter_spec.js @@ -1729,6 +1729,47 @@ describe('OpenxAdapter', function () { }); }); }); + describe('with user agent client hints', function () { + it('should add json query param sua with BidRequest.device.sua if available', function () { + const bidderRequestWithUserAgentClientHints = { refererInfo: {}, + ortb2: { + device: { + sua: { + source: 2, + platform: { + brand: 'macOS', + version: [ '12', '4', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + }], + mobile: 0, + model: 'Pro', + bitness: '64', + architecture: 'x86' + } + } + }}; + + let request = spec.buildRequests([bidRequest], bidderRequestWithUserAgentClientHints); + expect(request[0].data.sua).to.exist; + const payload = JSON.parse(request[0].data.sua); + expect(payload).to.deep.equal(bidderRequestWithUserAgentClientHints.ortb2.device.sua); + const bidderRequestWithoutUserAgentClientHints = {refererInfo: {}, ortb2: {}}; + request = spec.buildRequests([bidRequest], bidderRequestWithoutUserAgentClientHints); + expect(request[0].data.sua).to.not.exist; + }); + }); }); }) diff --git a/test/spec/modules/openxOrtbBidAdapter_spec.js b/test/spec/modules/openxOrtbBidAdapter_spec.js index be6427f607b..4295cb36df2 100644 --- a/test/spec/modules/openxOrtbBidAdapter_spec.js +++ b/test/spec/modules/openxOrtbBidAdapter_spec.js @@ -579,6 +579,47 @@ describe('OpenxRtbAdapter', function () { }); }); }); + + describe('with user agent client hints', function () { + it('should add device.sua if available', function () { + const bidderRequestWithUserAgentClientHints = { refererInfo: {}, + ortb2: { + device: { + sua: { + source: 2, + platform: { + brand: 'macOS', + version: [ '12', '4', '0' ] + }, + browsers: [ + { + brand: 'Chromium', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Google Chrome', + version: [ '106', '0', '5249', '119' ] + }, + { + brand: 'Not;A=Brand', + version: [ '99', '0', '0', '0' ] + }], + mobile: 0, + model: 'Pro', + bitness: '64', + architecture: 'x86' + } + } + }}; + + let request = spec.buildRequests(bidRequests, bidderRequestWithUserAgentClientHints); + expect(request[0].data.device.sua).to.exist; + expect(request[0].data.device.sua).to.deep.equal(bidderRequestWithUserAgentClientHints.ortb2.device.sua); + const bidderRequestWithoutUserAgentClientHints = {refererInfo: {}, ortb2: {}}; + request = spec.buildRequests(bidRequests, bidderRequestWithoutUserAgentClientHints); + expect(request[0].data.device.sua).to.not.exist; + }); + }); }); context('when there is a consent management framework', function () { From 9808b3f352764268a46f50b43416c999a93c0f59 Mon Sep 17 00:00:00 2001 From: Mikhail Ivanchenko Date: Mon, 23 Jan 2023 21:59:43 +0300 Subject: [PATCH 277/367] nextMillenniumBidAdapter: fix replaceGetUserMacro function (#9442) * add video support * fix replaceUserMacro func * Add tests Co-authored-by: Mikhail Ivanchenko --- modules/nextMillenniumBidAdapter.js | 28 +++++++++++++------ .../modules/nextMillenniumBidAdapter_spec.js | 16 +++++++++-- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/modules/nextMillenniumBidAdapter.js b/modules/nextMillenniumBidAdapter.js index b5d0e15d078..655f5fc3a35 100644 --- a/modules/nextMillenniumBidAdapter.js +++ b/modules/nextMillenniumBidAdapter.js @@ -271,15 +271,25 @@ export const spec = { }; function replaceUsersyncMacros(url, gdprConsent, uspConsent) { - const { consentString, gdprApplies } = gdprConsent; - - return url.replace( - '{{.GDPR}}', Number(gdprApplies) - ).replace( - '{{.GDPRConsent}}', consentString - ).replace( - '{{.USPrivacy}}', uspConsent - ); + const { consentString, gdprApplies } = gdprConsent || {}; + + if (gdprApplies) { + const gdpr = Number(gdprApplies); + url = url.replace('{{.GDPR}}', gdpr); + + if (gdpr == 1 && consentString && consentString.length > 0) { + url = url.replace('{{.GDPRConsent}}', consentString); + } + } else { + url = url.replace('{{.GDPR}}', 0); + url = url.replace('{{.GDPRConsent}}', ''); + } + + if (uspConsent) { + url = url.replace('{{.USPrivacy}}', uspConsent); + } + + return url; }; function getAdEl(bid) { diff --git a/test/spec/modules/nextMillenniumBidAdapter_spec.js b/test/spec/modules/nextMillenniumBidAdapter_spec.js index 90f0d8ae15c..571bb5fc584 100644 --- a/test/spec/modules/nextMillenniumBidAdapter_spec.js +++ b/test/spec/modules/nextMillenniumBidAdapter_spec.js @@ -49,7 +49,7 @@ describe('nextMillenniumBidAdapterTests', function() { cur: 'USD', ext: { sync: { - image: ['urlA'], + image: ['urlA?gdpr={{.GDPR}}'], iframe: ['urlB'], } } @@ -132,7 +132,7 @@ describe('nextMillenniumBidAdapterTests', function() { let userSync = spec.getUserSyncs(syncOptions, [serverResponse], bidRequestData[0].gdprConsent, bidRequestData[0].uspConsent); expect(userSync).to.be.an('array').with.lengthOf(1); expect(userSync[0].type).to.equal('image'); - expect(userSync[0].url).to.equal('urlA'); + expect(userSync[0].url).to.equal('urlA?gdpr=1'); syncOptions.iframeEnabled = true; syncOptions.pixelEnabled = false; @@ -142,6 +142,18 @@ describe('nextMillenniumBidAdapterTests', function() { expect(userSync[0].url).to.equal('urlB'); }); + it('Test getUserSyncs function if GDPR is undefined', function () { + const syncOptions = { + 'iframeEnabled': false, + 'pixelEnabled': true + } + + let userSync = spec.getUserSyncs(syncOptions, [serverResponse], undefined, bidRequestData[0].uspConsent); + expect(userSync).to.be.an('array').with.lengthOf(1); + expect(userSync[0].type).to.equal('image'); + expect(userSync[0].url).to.equal('urlA?gdpr=0'); + }); + it('Request params check without GDPR Consent', function () { delete bidRequestData[0].gdprConsent const request = spec.buildRequests(bidRequestData, bidRequestData[0]); From eafc9887bddc467596496e2d2c3d9f1259d912a8 Mon Sep 17 00:00:00 2001 From: Andy Rusiecki Date: Mon, 23 Jan 2023 14:05:38 -0500 Subject: [PATCH 278/367] kargo - adding support for vast url in bid response (#9447) --- modules/kargoBidAdapter.js | 6 ++++- test/spec/modules/kargoBidAdapter_spec.js | 32 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index 2c33c3f61d1..6a1c1cf94b0 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -116,7 +116,11 @@ export const spec = { }; if (meta.mediaType == VIDEO) { - bidResponse.vastXml = adUnit.adm; + if (adUnit.admUrl) { + bidResponse.vastUrl = adUnit.admUrl; + } else { + bidResponse.vastXml = adUnit.adm; + } } bidResponses.push(bidResponse); diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index 565b83704fa..525c00d655c 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -556,6 +556,17 @@ describe('kargo adapter tests', function () { mediaType: 'video', metadata: {}, currency: 'EUR' + }, + 6: { + id: 'bar', + cpm: 2.5, + adm: '', + admUrl: 'https://foobar.com/vast_adm', + width: 300, + height: 250, + mediaType: 'video', + metadata: {}, + currency: 'EUR' } }}, { currency: 'USD', @@ -584,6 +595,11 @@ describe('kargo adapter tests', function () { params: { placementId: 'bar' } + }, { + bidId: 6, + params: { + placementId: 'bar' + } }] }); var expectation = [{ @@ -664,6 +680,22 @@ describe('kargo adapter tests', function () { meta: { mediaType: 'video' } + }, { + requestId: '6', + cpm: 2.5, + width: 300, + height: 250, + ad: '', + vastUrl: 'https://foobar.com/vast_adm', + ttl: 300, + creativeId: 'bar', + dealId: undefined, + netRevenue: true, + currency: 'EUR', + mediaType: 'video', + meta: { + mediaType: 'video' + } }]; expect(resp).to.deep.equal(expectation); }); From 6d9887a672b28a4d7018a491839b06fbdd90f0b1 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Mon, 23 Jan 2023 12:36:13 -0700 Subject: [PATCH 279/367] openxOrtbBidAdapter: fix device.sua test (#9452) --- test/spec/modules/openxOrtbBidAdapter_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/modules/openxOrtbBidAdapter_spec.js b/test/spec/modules/openxOrtbBidAdapter_spec.js index 4295cb36df2..3bb1958c5fe 100644 --- a/test/spec/modules/openxOrtbBidAdapter_spec.js +++ b/test/spec/modules/openxOrtbBidAdapter_spec.js @@ -617,7 +617,7 @@ describe('OpenxRtbAdapter', function () { expect(request[0].data.device.sua).to.deep.equal(bidderRequestWithUserAgentClientHints.ortb2.device.sua); const bidderRequestWithoutUserAgentClientHints = {refererInfo: {}, ortb2: {}}; request = spec.buildRequests(bidRequests, bidderRequestWithoutUserAgentClientHints); - expect(request[0].data.device.sua).to.not.exist; + expect(request[0].data.device?.sua).to.not.exist; }); }); }); From b77951dd732a60863fb7c45ce05eb301836007f1 Mon Sep 17 00:00:00 2001 From: Vincent Date: Mon, 23 Jan 2023 21:01:10 +0100 Subject: [PATCH 280/367] Criteo Bid Adapter : Bump Publisher Tag version (#9450) Co-authored-by: v.raybaud --- modules/criteoBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index a056454564c..fb42066a008 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -27,7 +27,7 @@ const LOG_PREFIX = 'Criteo: '; Unminified source code can be found in the privately shared repo: https://github.com/Prebid-org/prebid-js-external-js-criteo/blob/master/dist/prod.js */ const FAST_BID_VERSION_PLACEHOLDER = '%FAST_BID_VERSION%'; -export const FAST_BID_VERSION_CURRENT = 133; +export const FAST_BID_VERSION_CURRENT = 134; const FAST_BID_VERSION_LATEST = 'latest'; const FAST_BID_VERSION_NONE = 'none'; const PUBLISHER_TAG_URL_TEMPLATE = 'https://static.criteo.net/js/ld/publishertag.prebid' + FAST_BID_VERSION_PLACEHOLDER + '.js'; From 11b4c97f0867e383575e7eab275e2941b7d9791a Mon Sep 17 00:00:00 2001 From: samous Date: Tue, 24 Jan 2023 05:01:05 +0100 Subject: [PATCH 281/367] BLIINK Bid Adapter: fix ttl (#9443) * fix(bliink): bid ttl * fix(bliink): ttl unit tests Co-authored-by: Samous --- modules/bliinkBidAdapter.js | 2 +- test/spec/modules/bliinkBidAdapter_spec.js | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/bliinkBidAdapter.js b/modules/bliinkBidAdapter.js index 127b534c989..ee814807331 100644 --- a/modules/bliinkBidAdapter.js +++ b/modules/bliinkBidAdapter.js @@ -125,7 +125,7 @@ export const buildBid = (bidResponse) => { requestId: deepAccess(bidResponse, 'extras.transaction_id'), width: deepAccess(bidResponse, `creative.${bid.mediaType}.width`) || 1, height: deepAccess(bidResponse, `creative.${bid.mediaType}.height`) || 1, - ttl: 3600, + ttl: 300, netRevenue: true, }); }; diff --git a/test/spec/modules/bliinkBidAdapter_spec.js b/test/spec/modules/bliinkBidAdapter_spec.js index b8994b86847..8e96bd76940 100644 --- a/test/spec/modules/bliinkBidAdapter_spec.js +++ b/test/spec/modules/bliinkBidAdapter_spec.js @@ -130,7 +130,7 @@ const getConfigCreative = () => { creativeId: '34567erty', width: 300, height: 250, - ttl: 3600, + ttl: 300, netRevenue: true, } } @@ -145,7 +145,7 @@ const getConfigCreativeVideo = (isNoVast) => { requestId: '6a204ce130280d', width: 300, height: 250, - ttl: 3600, + ttl: 300, netRevenue: true, } } @@ -395,7 +395,7 @@ const testsInterpretResponse = [ mediaType: 'video', netRevenue: true, requestId: '2def0c5b2a7f6e', - ttl: 3600, + ttl: 300, vastXml, vastUrl: 'data:text/xml;charset=utf-8;base64,' + btoa(vastXml.replace(/\\"/g, '"')) }] @@ -421,7 +421,7 @@ const testsInterpretResponse = [ mediaType: 'banner', netRevenue: true, requestId: '2def0c5b2a7f6e', - ttl: 3600, + ttl: 300, width: 300 }] }, @@ -505,7 +505,7 @@ const testsBuildBid = [ netRevenue: true, vastXml: getConfigCreativeVideo().vastXml, vastUrl: 'data:text/xml;charset=utf-8;base64,' + btoa(getConfigCreativeVideo().vastXml.replace(/\\"/g, '"')), - ttl: 3600, + ttl: 300, } }, { @@ -535,7 +535,7 @@ const testsBuildBid = [ netRevenue: true, vastXml: getConfigCreativeVideo().vastXml, vastUrl: 'data:text/xml;charset=utf-8;base64,' + btoa(getConfigCreativeVideo().vastXml.replace(/\\"/g, '"')), - ttl: 3600, + ttl: 300, } }, { @@ -552,7 +552,7 @@ const testsBuildBid = [ height: 250, creativeId: getConfigCreative().creativeId, ad: getConfigBannerBid().creative.banner.adm, - ttl: 3600, + ttl: 300, netRevenue: true, } } From 57f6109c79fc6cbdffe6dfaf66ee1d96331ff49e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jan 2023 13:23:05 -0500 Subject: [PATCH 282/367] Bump ua-parser-js from 0.7.32 to 0.7.33 (#9456) Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.32 to 0.7.33. - [Release notes](https://github.com/faisalman/ua-parser-js/releases) - [Changelog](https://github.com/faisalman/ua-parser-js/blob/master/changelog.md) - [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.32...0.7.33) --- updated-dependencies: - dependency-name: ua-parser-js dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d5072df524..6298a19479c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.33.0-pre", + "version": "7.34.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -2797,9 +2797,9 @@ } }, "node_modules/@wdio/browserstack-service/node_modules/ua-parser-js": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", - "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz", + "integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==", "dev": true, "funding": [ { @@ -8453,9 +8453,9 @@ } }, "node_modules/devtools/node_modules/ua-parser-js": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", - "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz", + "integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==", "dev": true, "funding": [ { @@ -22962,9 +22962,9 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.32", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", - "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", + "version": "0.7.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", + "integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==", "dev": true, "funding": [ { @@ -27305,9 +27305,9 @@ } }, "ua-parser-js": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", - "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz", + "integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==", "dev": true }, "uuid": { @@ -31718,9 +31718,9 @@ } }, "ua-parser-js": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", - "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz", + "integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==", "dev": true }, "uuid": { @@ -43058,9 +43058,9 @@ } }, "ua-parser-js": { - "version": "0.7.32", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", - "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", + "version": "0.7.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", + "integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==", "dev": true }, "uglify-js": { From a009ced31f55c5402bf92b773561468abb8508a6 Mon Sep 17 00:00:00 2001 From: Patrick Loughrey Date: Tue, 24 Jan 2023 13:26:22 -0500 Subject: [PATCH 283/367] Triplelift Bid Adapter: Support for GPP in bid requests (#9455) * prioritize topmostlocation * adds test for topmostlocation / referrer * cleanup * delete param after test * TL-32803: Update referrer logic * TL-32803: Update referrer logic * TL-34204: Add support for GPP Co-authored-by: Nick Llerandi Co-authored-by: nllerandi3lift <75995508+nllerandi3lift@users.noreply.github.com> --- modules/tripleliftBidAdapter.js | 4 ++++ test/spec/modules/tripleliftBidAdapter_spec.js | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/modules/tripleliftBidAdapter.js b/modules/tripleliftBidAdapter.js index 7f6ec90c7b9..3ce44d067bf 100644 --- a/modules/tripleliftBidAdapter.js +++ b/modules/tripleliftBidAdapter.js @@ -154,6 +154,10 @@ function _buildPostBody(bidRequests, bidderRequest) { if (!isEmpty(ext)) { data.ext = ext; } + + if (bidderRequest?.ortb2?.regs?.gpp) { + data.regs = Object.assign({}, bidderRequest.ortb2.regs); + } return data; } diff --git a/test/spec/modules/tripleliftBidAdapter_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js index 5cfa64184f9..0447cb4d5d6 100644 --- a/test/spec/modules/tripleliftBidAdapter_spec.js +++ b/test/spec/modules/tripleliftBidAdapter_spec.js @@ -1168,6 +1168,19 @@ describe('triplelift adapter', function () { } }) }); + it('should add gpp consent data to bid request object if gpp data exists', function() { + bidderRequest.ortb2 = { + regs: { + 'gpp': 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + 'gpp_sid': [7] + } + } + const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); + expect(request.data.regs).to.deep.equal({ + 'gpp': 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + 'gpp_sid': [7] + }) + }); }); describe('interpretResponse', function () { From 97c149daf215f5f0b178c9fb88f29a3fd9b5b32c Mon Sep 17 00:00:00 2001 From: Mike Marcus Date: Tue, 24 Jan 2023 17:05:59 -0500 Subject: [PATCH 284/367] Lotame Panorama ID Module : add safari handling (#9418) * GRUE-176 work in progress, trying to make the id URL dynamic. * GRUE-176 After some attempts with leveraging environment variables, decided to look for an environment variable passed on configuration. * GRUE-177 WIP added a fix for handling timestamps, plus there's some temporary debugging that I was using to understand flow. * GRUE-177 Fixed bug with localStorage checking for empty, included null as a possible return value. * GRUE-177 updated the environment handling for dev, qa, and prod. I'm still on the fence on whether we need this, but it's allowing the tests to pass currently, so leaving it in for now. * GRUE-178 removed the dynamic URL handling for the ID endpoint. We will manage that change with the build process for testing. * GRUE-339 changes to check for browser, and accomodate Safari with a different URL. * GRUE-339 changes to check for browser, and accomodate Safari with a different URL. * GRUE-339 Removed the obfuscation from the Safari URL, as it was deemed unnecessary. * GRUE-339 corrected the safari id endpoint - I had forgotten that it was different than the usual one. * GRUE-339 Updated test to cover Safari handling. * GRUE-340 Updated the variable name for the cookieless domain, to remove the emphasis on Safari and better illustrate that this is a general approach. Co-authored-by: Mark Conrad Co-authored-by: Mark --- modules/lotamePanoramaIdSystem.js | 10 ++++++- .../modules/lotamePanoramaIdSystem_spec.js | 26 ++++++++++++------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/modules/lotamePanoramaIdSystem.js b/modules/lotamePanoramaIdSystem.js index 832d98e4f83..883c931824b 100644 --- a/modules/lotamePanoramaIdSystem.js +++ b/modules/lotamePanoramaIdSystem.js @@ -29,6 +29,7 @@ const DAY_MS = 60 * 60 * 24 * 1000; const MISSING_CORE_CONSENT = 111; const GVLID = 95; const ID_HOST = 'id.crwdcntrl.net'; +const ID_HOST_COOKIELESS = 'c.ltmsphrcl.net'; export const storage = getStorageManager({gvlid: GVLID, moduleName: MODULE_NAME}); let cookieDomain; @@ -252,6 +253,13 @@ export const lotamePanoramaIdSubmodule = { usPrivacy = getFromStorage('us_privacy'); } + const getRequestHost = function() { + if (navigator.userAgent && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { + return ID_HOST_COOKIELESS; + } + return ID_HOST; + } + const resolveIdFunction = function (callback) { let queryParams = {}; if (storedUserId) { @@ -288,7 +296,7 @@ export const lotamePanoramaIdSubmodule = { const url = buildUrl({ protocol: 'https', - host: ID_HOST, + host: getRequestHost(), pathname: '/id', search: isEmpty(queryParams) ? undefined : queryParams, }); diff --git a/test/spec/modules/lotamePanoramaIdSystem_spec.js b/test/spec/modules/lotamePanoramaIdSystem_spec.js index 5dc055ac080..ea538db08e1 100644 --- a/test/spec/modules/lotamePanoramaIdSystem_spec.js +++ b/test/spec/modules/lotamePanoramaIdSystem_spec.js @@ -18,6 +18,7 @@ describe('LotameId', function() { let removeFromLocalStorageStub; let timeStampStub; let uspConsentDataStub; + let requestHost; const nowTimestamp = new Date().getTime(); @@ -33,6 +34,11 @@ describe('LotameId', function() { ); timeStampStub = sinon.stub(utils, 'timestamp').returns(nowTimestamp); uspConsentDataStub = sinon.stub(uspDataHandler, 'getConsentData'); + if (navigator.userAgent && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { + requestHost = 'https://c.ltmsphrcl.net/id'; + } else { + requestHost = 'https://id.crwdcntrl.net/id'; + } }); afterEach(function () { @@ -69,7 +75,7 @@ describe('LotameId', function() { }); it('should call the remote server when getId is called', function () { - expect(request.url).to.be.eq('https://id.crwdcntrl.net/id'); + expect(request.url).to.be.eq(`${requestHost}`); expect(callBackSpy.calledOnce).to.be.true; }); @@ -439,7 +445,7 @@ describe('LotameId', function() { it('should pass the gdpr consent string back', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=true&gdpr_consent=consentGiven' + `${requestHost}?gdpr_applies=true&gdpr_consent=consentGiven` ); }); }); @@ -471,7 +477,7 @@ describe('LotameId', function() { it('should pass the gdpr consent string back', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=true&gdpr_consent=consentGiven' + `${requestHost}?gdpr_applies=true&gdpr_consent=consentGiven` ); }); }); @@ -503,7 +509,7 @@ describe('LotameId', function() { it('should pass the gdpr consent string back', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=true&gdpr_consent=consentGiven' + `${requestHost}?gdpr_applies=true&gdpr_consent=consentGiven` ); }); }); @@ -531,7 +537,7 @@ describe('LotameId', function() { it('should not include the gdpr consent string on the url', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=true' + `${requestHost}?gdpr_applies=true` ); }); }); @@ -560,7 +566,7 @@ describe('LotameId', function() { it('should pass the gdpr consent string back', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_consent=consentGiven' + `${requestHost}?gdpr_consent=consentGiven` ); }); }); @@ -589,7 +595,7 @@ describe('LotameId', function() { it('should pass the gdpr consent string back', function() { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_consent=consentGiven' + `${requestHost}?gdpr_consent=consentGiven` ); }); }); @@ -613,7 +619,7 @@ describe('LotameId', function() { }); it('should pass the gdpr consent string back', function() { - expect(request.url).to.be.eq('https://id.crwdcntrl.net/id'); + expect(request.url).to.be.eq(`${requestHost}`); }); }); @@ -835,7 +841,7 @@ describe('LotameId', function() { it('should pass the usp consent string and client id back', function () { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=false&us_privacy=1NNN&c=1234' + `${requestHost}?gdpr_applies=false&us_privacy=1NNN&c=1234` ); }); @@ -923,7 +929,7 @@ describe('LotameId', function() { it('should pass client id back', function () { expect(request.url).to.be.eq( - 'https://id.crwdcntrl.net/id?gdpr_applies=false&c=1234' + `${requestHost}?gdpr_applies=false&c=1234` ); }); From a10a0fa431d3ce1ad160169457cad82818bcadf9 Mon Sep 17 00:00:00 2001 From: Mikael Lundin Date: Wed, 25 Jan 2023 16:08:35 +0100 Subject: [PATCH 285/367] Adnuntius Bid Adapter: Bug fix for multiple mime types. (#9458) --- modules/adnuntiusBidAdapter.js | 74 +++--- test/spec/modules/adnuntiusBidAdapter_spec.js | 240 +++++++++--------- 2 files changed, 156 insertions(+), 158 deletions(-) diff --git a/modules/adnuntiusBidAdapter.js b/modules/adnuntiusBidAdapter.js index 5ad5436e732..ea3b723b316 100644 --- a/modules/adnuntiusBidAdapter.js +++ b/modules/adnuntiusBidAdapter.js @@ -1,6 +1,6 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; -import { isStr, deepAccess, logInfo } from '../src/utils.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { isStr, deepAccess } from '../src/utils.js'; import { config } from '../src/config.js'; import { getStorageManager } from '../src/storageManager.js'; @@ -8,7 +8,7 @@ const BIDDER_CODE = 'adnuntius'; const ENDPOINT_URL = 'https://ads.adnuntius.delivery/i'; const GVLID = 855; const DEFAULT_VAST_VERSION = 'vast4' -const DEFAULT_NATIVE = 'native' +// const DEFAULT_NATIVE = 'native' const checkSegment = function (segment) { if (isStr(segment)) return segment; @@ -28,31 +28,31 @@ const getSegmentsFromOrtb = function (ortb2) { return segments } -function createNative(ad) { - const native = {}; - const assets = ad.assets - native.title = ad.text.title.content; - native.image = { - url: assets.image.cdnId, - height: assets.image.height, - width: assets.image.width, - }; - if (assets.icon) { - native.icon = { - url: assets.icon.cdnId, - height: assets.icon.height, - width: assets.icon.width, - }; - } - - native.sponsoredBy = ad.text.sponsoredBy?.content || ''; - native.body = ad.text.body?.content || ''; - native.cta = ad.text.cta?.content || ''; - native.clickUrl = ad.destinationUrls.destination || ''; - native.impressionTrackers = ad.impressionTrackingUrls || [ad.renderedPixel]; - - return native; -} +// function createNative(ad) { +// const native = {}; +// const assets = ad.assets +// native.title = ad.text.title.content; +// native.image = { +// url: assets.image.cdnId, +// height: assets.image.height, +// width: assets.image.width, +// }; +// if (assets.icon) { +// native.icon = { +// url: assets.icon.cdnId, +// height: assets.icon.height, +// width: assets.icon.width, +// }; +// } + +// native.sponsoredBy = ad.text.sponsoredBy?.content || ''; +// native.body = ad.text.body?.content || ''; +// native.cta = ad.text.cta?.content || ''; +// native.clickUrl = ad.destinationUrls.destination || ''; +// native.impressionTrackers = ad.impressionTrackingUrls || [ad.renderedPixel]; + +// return native; +// } const handleMeta = function () { const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }) @@ -73,7 +73,7 @@ const getUsi = function (meta, ortb2, bidderRequest) { export const spec = { code: BIDDER_CODE, gvlid: GVLID, - supportedMediaTypes: [BANNER, VIDEO, NATIVE], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: function (bid) { return !!(bid.bidId || (bid.params.member && bid.params.invCode)); }, @@ -109,9 +109,9 @@ export const spec = { network += '_video' } - if (bid.mediaTypes && bid.mediaTypes.native) { - network += '_native' - } + // if (bid.mediaTypes && bid.mediaTypes.native) { + // network += '_native' + // } bidRequests[network] = bidRequests[network] || []; bidRequests[network].push(bid); @@ -130,7 +130,7 @@ export const spec = { const network = networkKeys[j]; const networkRequest = [...request] if (network.indexOf('_video') > -1) { networkRequest.push('tt=' + DEFAULT_VAST_VERSION) } - if (network.indexOf('_native') > -1) { networkRequest.push('tt=' + DEFAULT_NATIVE) } + // if (network.indexOf('_native') > -1) { networkRequest.push('tt=' + DEFAULT_NATIVE) } requests.push({ method: 'POST', url: ENDPOINT_URL + '?' + networkRequest.join('&'), @@ -170,15 +170,13 @@ export const spec = { if (adUnit.vastXml) { adResponse[adUnit.targetId].vastXml = adUnit.vastXml adResponse[adUnit.targetId].mediaType = VIDEO - } else if (ad.assets && ad.assets.image && ad.text && ad.text.title && ad.text.body && ad.destinationUrls && ad.destinationUrls.destination) { - adResponse[adUnit.targetId].native = createNative(ad); - adResponse[adUnit.targetId].mediaType = NATIVE; + // } else if (ad.assets && ad.assets.image && ad.text && ad.text.title && ad.text.body && ad.destinationUrls && ad.destinationUrls.destination) { + // adResponse[adUnit.targetId].native = createNative(ad); + // adResponse[adUnit.targetId].mediaType = NATIVE; } else { adResponse[adUnit.targetId].ad = adUnit.html } - logInfo('BID', adResponse) - return adResponse } else return response }, {}); diff --git a/test/spec/modules/adnuntiusBidAdapter_spec.js b/test/spec/modules/adnuntiusBidAdapter_spec.js index ee585862800..b787a52d6f2 100644 --- a/test/spec/modules/adnuntiusBidAdapter_spec.js +++ b/test/spec/modules/adnuntiusBidAdapter_spec.js @@ -71,29 +71,29 @@ describe('adnuntiusBidAdapter', function () { } ] - const nativeBidderRequest = [ - { - bidId: '123', - bidder: 'adnuntius', - params: { - auId: '8b6bc', - network: 'adnuntius', - }, - mediaTypes: { - native: { - title: { - required: true - }, - image: { - required: true - }, - body: { - required: true - } - } - }, - } - ] + // const nativeBidderRequest = [ + // { + // bidId: '123', + // bidder: 'adnuntius', + // params: { + // auId: '8b6bc', + // network: 'adnuntius', + // }, + // mediaTypes: { + // native: { + // title: { + // required: true + // }, + // image: { + // required: true + // }, + // body: { + // required: true + // } + // } + // }, + // } + // ] const singleBidRequest = { bid: [ @@ -107,9 +107,9 @@ describe('adnuntiusBidAdapter', function () { bid: videoBidderRequest } - const nativeBidRequest = { - bid: nativeBidderRequest - } + // const nativeBidRequest = { + // bid: nativeBidderRequest + // } const serverResponse = { body: { @@ -237,83 +237,83 @@ describe('adnuntiusBidAdapter', function () { ] } } - const serverNativeResponse = { - body: { - 'adUnits': [ - { - 'auId': '000000000008b6bc', - 'targetId': '123', - '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/K9rfXC6wJvgVuy4Fbt5P8oEEGXme9ZaP8BNDzz3OMGQ.jpg', - 'width': '300', - 'height': '250' - } - }, - 'text': { - 'body': { - 'content': 'Testing Native ad from Adnuntius', - 'length': '32', - 'minLength': '0', - 'maxLength': '100' - }, - 'title': { - 'content': 'Native Ad', - 'length': '9', - 'minLength': '5', - 'maxLength': '100' - } - }, - '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' - }, - - ] - }, - { - 'auId': '000000000008b6bc', - 'targetId': '456', - 'matchedAdCount': 0, - 'responseId': 'adn-rsp-1460129238', - } - ] - } - } + // const serverNativeResponse = { + // body: { + // 'adUnits': [ + // { + // 'auId': '000000000008b6bc', + // 'targetId': '123', + // '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/K9rfXC6wJvgVuy4Fbt5P8oEEGXme9ZaP8BNDzz3OMGQ.jpg', + // 'width': '300', + // 'height': '250' + // } + // }, + // 'text': { + // 'body': { + // 'content': 'Testing Native ad from Adnuntius', + // 'length': '32', + // 'minLength': '0', + // 'maxLength': '100' + // }, + // 'title': { + // 'content': 'Native Ad', + // 'length': '9', + // 'minLength': '5', + // 'maxLength': '100' + // } + // }, + // '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' + // }, + + // ] + // }, + // { + // 'auId': '000000000008b6bc', + // 'targetId': '456', + // 'matchedAdCount': 0, + // 'responseId': 'adn-rsp-1460129238', + // } + // ] + // } + // } describe('inherited functions', function () { it('exists and is a function', function () { @@ -531,21 +531,21 @@ describe('adnuntiusBidAdapter', function () { expect(interpretedResponse[0].vastXml).to.equal(serverVideoResponse.body.adUnits[0].vastXml); }); }); - describe('interpretNativeResponse', function () { - it('should return valid response when passed valid server response', function () { - const interpretedResponse = spec.interpretResponse(serverNativeResponse, nativeBidRequest); - const ad = serverNativeResponse.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.bid.currency); - expect(interpretedResponse[0].netRevenue).to.equal(false); - expect(interpretedResponse[0].meta).to.have.property('advertiserDomains'); - expect(interpretedResponse[0].meta.advertiserDomains).to.have.lengthOf(1); - expect(interpretedResponse[0].meta.advertiserDomains[0]).to.equal('google.com'); - expect(interpretedResponse[0].native.body).to.equal(serverNativeResponse.body.adUnits[0].ads[0].text.body.content); - }); - }); + // describe('interpretNativeResponse', function () { + // it('should return valid response when passed valid server response', function () { + // const interpretedResponse = spec.interpretResponse(serverNativeResponse, nativeBidRequest); + // const ad = serverNativeResponse.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.bid.currency); + // expect(interpretedResponse[0].netRevenue).to.equal(false); + // expect(interpretedResponse[0].meta).to.have.property('advertiserDomains'); + // expect(interpretedResponse[0].meta.advertiserDomains).to.have.lengthOf(1); + // expect(interpretedResponse[0].meta.advertiserDomains[0]).to.equal('google.com'); + // expect(interpretedResponse[0].native.body).to.equal(serverNativeResponse.body.adUnits[0].ads[0].text.body.content); + // }); + // }); }); From 3c536e181ed104bcfdc9766bea8034afe123482a Mon Sep 17 00:00:00 2001 From: Krzysztof Desput Date: Wed, 25 Jan 2023 16:18:39 +0100 Subject: [PATCH 286/367] Holid bid adapter: skip user syncs when no bidders in bid response (#9462) --- modules/holidBidAdapter.js | 13 ++++++---- test/spec/modules/holidBidAdapter_spec.js | 29 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/modules/holidBidAdapter.js b/modules/holidBidAdapter.js index be5a7a044c3..92b0a1c18db 100644 --- a/modules/holidBidAdapter.js +++ b/modules/holidBidAdapter.js @@ -85,11 +85,12 @@ export const spec = { } const syncs = [] + const bidders = getBidders(serverResponse) - if (optionsType.iframeEnabled) { + if (optionsType.iframeEnabled && bidders) { const queryParams = [] - queryParams.push('bidders=' + getBidders(serverResponse)) + queryParams.push('bidders=' + bidders) queryParams.push('gdpr=' + +gdprConsent.gdprApplies) queryParams.push('gdpr_consent=' + gdprConsent.consentString) queryParams.push('usp_consent=' + (uspConsent || '')) @@ -107,6 +108,8 @@ export const spec = { return syncs } + + return [] }, } @@ -136,10 +139,12 @@ function getImp(bid) { function getBidders(serverResponse) { const bidders = serverResponse - .map((res) => Object.keys(res.body.ext.responsetimemillis)) + .map((res) => Object.keys(res.body.ext.responsetimemillis || [])) .flat(1) - return encodeURIComponent(JSON.stringify([...new Set(bidders)])) + if (bidders.length) { + return encodeURIComponent(JSON.stringify([...new Set(bidders)])) + } } function addWurl(auctionId, adId, wurl) { diff --git a/test/spec/modules/holidBidAdapter_spec.js b/test/spec/modules/holidBidAdapter_spec.js index e18a5ac58f4..e55befd213a 100644 --- a/test/spec/modules/holidBidAdapter_spec.js +++ b/test/spec/modules/holidBidAdapter_spec.js @@ -161,5 +161,34 @@ describe('holidBidAdapterTests', () => { expect(userSyncs).to.deep.equal(expectedUserSyncs) }) + + it('should return empty user syncs when responsetimemillis is not defined', () => { + const optionsType = { + iframeEnabled: true, + pixelEnabled: true, + } + const serverResponse = [ + { + body: { + ext: {}, + }, + }, + ] + const gdprConsent = { + gdprApplies: 1, + consentString: 'dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig', + } + const uspConsent = 'mkjvbiniwot4827obfoy8sdg8203gb' + const expectedUserSyncs = [] + + const userSyncs = spec.getUserSyncs( + optionsType, + serverResponse, + gdprConsent, + uspConsent + ) + + expect(userSyncs).to.deep.equal(expectedUserSyncs) + }) }) }) From da42b1b607d4d463551e3eaf8ef5bfd02f94370e Mon Sep 17 00:00:00 2001 From: sag-jonhil <78849369+sag-jonhil@users.noreply.github.com> Date: Wed, 25 Jan 2023 17:29:10 +0100 Subject: [PATCH 287/367] Seeding Alliance Bid Adapter: add banner support and get endpoint-url from config (#9404) * add seedingAlliance Adapter * add two native default params * ... * ... * seedingAlliance Adapter: add two more default native params * updating seedingAlliance Adapter * seedingAlliance Adapter * quickfix no bids + net revenue * bugfix replace auction price * change URL and add versioning * add vendorId to seedingAllianceAdapter * optimize code + banner support * add newline at the end of file * fix ci/circleci error * add new specs Co-authored-by: SeedingAllianceTech <55976067+SeedingAllianceTech@users.noreply.github.com> Co-authored-by: Hendrick Musche <107099114+sag-henmus@users.noreply.github.com> Co-authored-by: Hendrick Musche --- modules/seedingAllianceBidAdapter.js | 245 +++++++++--------- .../modules/seedingAllianceAdapter_spec.js | 89 +++++-- 2 files changed, 195 insertions(+), 139 deletions(-) diff --git a/modules/seedingAllianceBidAdapter.js b/modules/seedingAllianceBidAdapter.js index 64b9cd5d4aa..29953da7ffa 100755 --- a/modules/seedingAllianceBidAdapter.js +++ b/modules/seedingAllianceBidAdapter.js @@ -2,120 +2,111 @@ 'use strict'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { NATIVE } from '../src/mediaTypes.js'; -import { _map, deepSetValue, isEmpty, deepAccess } from '../src/utils.js'; +import { NATIVE, BANNER } from '../src/mediaTypes.js'; +import { _map, isArray, isEmpty, deepSetValue, replaceAuctionPrice } from '../src/utils.js'; import { config } from '../src/config.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; -const BIDDER_CODE = 'seedingAlliance'; const GVL_ID = 371; +const BIDDER_CODE = 'seedingAlliance'; const DEFAULT_CUR = 'EUR'; const ENDPOINT_URL = 'https://b.nativendo.de/cds/rtb/bid?format=openrtb2.5&ssp=pb'; -const NATIVE_ASSET_IDS = {0: 'title', 1: 'body', 2: 'sponsoredBy', 3: 'image', 4: 'cta', 5: 'icon'}; +const NATIVE_ASSET_IDS = { 0: 'title', 1: 'body', 2: 'sponsoredBy', 3: 'image', 4: 'cta', 5: 'icon' }; const NATIVE_PARAMS = { - title: { - id: 0, - name: 'title' - }, - - body: { - id: 1, - name: 'data', - type: 2 - }, - - sponsoredBy: { - id: 2, - name: 'data', - type: 1 - }, - - image: { - id: 3, - type: 3, - name: 'img' - }, - - cta: { - id: 4, - type: 12, - name: 'data' - }, - - icon: { - id: 5, - type: 1, - name: 'img' - } + title: { id: 0, name: 'title' }, + body: { id: 1, name: 'data', type: 2 }, + sponsoredBy: { id: 2, name: 'data', type: 1 }, + image: { id: 3, type: 3, name: 'img' }, + cta: { id: 4, type: 12, name: 'data' }, + icon: { id: 5, type: 1, name: 'img' } }; export const spec = { code: BIDDER_CODE, - gvlid: GVL_ID, + supportedMediaTypes: [NATIVE, BANNER], - supportedMediaTypes: [NATIVE], - - isBidRequestValid: function(bid) { + isBidRequestValid: function (bid) { return !!bid.params.adUnitId; }, - buildRequests: (validBidRequests, bidderRequest) => { + buildRequests: (validBidRequests = [], bidderRequest) => { // convert Native ORTB definition to old-style prebid native definition validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); - const pt = setOnAny(validBidRequests, 'params.pt') || setOnAny(validBidRequests, 'params.priceType') || 'net'; - const tid = bidderRequest.auctionId; - const cur = [config.getConfig('currency.adServerCurrency') || DEFAULT_CUR]; let url = bidderRequest.refererInfo.page; - const imp = validBidRequests.map((bid, id) => { - const assets = _map(bid.nativeParams, (bidParams, key) => { - const props = NATIVE_PARAMS[key]; - - const asset = { - required: bidParams.required & 1 - }; + const imps = validBidRequests.map((bidRequest, id) => { + const imp = { + id: String(id + 1), + tagid: bidRequest.params.adUnitId + }; - if (props) { - asset.id = props.id; + /** + * Native Ad + */ + if (bidRequest.nativeParams) { + const assets = _map(bidRequest.nativeParams, (nativeAsset, key) => { + const props = NATIVE_PARAMS[key]; + + if (props) { + let wmin, hmin, w, h; + let aRatios = nativeAsset.aspect_ratios; + + if (aRatios && aRatios[0]) { + aRatios = aRatios[0]; + wmin = aRatios.min_width || 0; + hmin = aRatios.ratio_height * wmin / aRatios.ratio_width | 0; + } - let w, h; + if (nativeAsset.sizes) { + const sizes = flatten(nativeAsset.sizes); + w = parseInt(sizes[0], 10); + h = parseInt(sizes[1], 10); + } - if (bidParams.sizes) { - w = bidParams.sizes[0]; - h = bidParams.sizes[1]; + const asset = { + id: props.id, + required: nativeAsset.required & 1 + }; + + asset[props.name] = { + len: nativeAsset.len, + type: props.type, + wmin, + hmin, + w, + h + }; + + return asset; + } else { + // TODO Filter impressions with required assets we don't support } + }).filter(Boolean); - asset[props.name] = { - len: bidParams.len, - type: props.type, - w, - h - }; + imp.native = { + request: { + assets + } + }; + } else { + let sizes = transformSizes(bidRequest.sizes); - return asset; + imp.banner = { + format: sizes, + w: sizes[0] ? sizes[0].w : 0, + h: sizes[0] ? sizes[0].h : 0 } - }) - .filter(Boolean); + } - if (bid.params.url) { - url = bid.params.url; + if (bidRequest.params.url) { + url = bidRequest.params.url; } - return { - id: String(id + 1), - tagid: bid.params.adUnitId, - tid: tid, - pt: pt, - native: { - request: { - assets - } - } - }; + return imp; }); const request = { @@ -123,12 +114,9 @@ export const spec = { site: { page: url }, - device: { - ua: navigator.userAgent - }, - cur, - imp, - user: {}, + cur: [config.getConfig('currency.adServerCurrency') || DEFAULT_CUR], + imp: imps, + tmax: bidderRequest.timeout, regs: { ext: { gdpr: 0, @@ -137,23 +125,22 @@ export const spec = { } }; - if (bidderRequest && bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent) { + request.user = {}; + deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString); deepSetValue(request, 'regs.ext.gdpr', (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean' && bidderRequest.gdprConsent.gdprApplies) ? 1 : 0); } return { method: 'POST', - url: ENDPOINT_URL, + url: config.getConfig('seedingAlliance.endpoint') || ENDPOINT_URL, data: JSON.stringify(request), - options: { - contentType: 'application/json' - }, - bids: validBidRequests + bidRequests: validBidRequests }; }, - interpretResponse: function(serverResponse, { bids }) { + interpretResponse: function (serverResponse, { bidRequests }) { if (isEmpty(serverResponse.body)) { return []; } @@ -165,35 +152,72 @@ export const spec = { return result; }, []) : []; - return bids - .map((bid, id) => { + return bidRequests + .map((bidRequest, id) => { const bidResponse = bidResponses[id]; + const type = bidRequest.nativeParams ? NATIVE : BANNER; + if (bidResponse) { - return { - requestId: bid.bidId, + const bidObject = { + requestId: bidRequest.bidId, // TODO get this value from response? cpm: bidResponse.price, creativeId: bidResponse.crid, - ttl: 1000, - netRevenue: (!bid.netRevenue || bid.netRevenue === 'net'), + ttl: 600, + netRevenue: true, currency: cur, - mediaType: NATIVE, + mediaType: type, bidderCode: BIDDER_CODE, - native: parseNative(bidResponse), meta: { advertiserDomains: bidResponse.adomain && bidResponse.adomain.length > 0 ? bidResponse.adomain : [] } }; + + if (type === NATIVE) { + bidObject.native = parseNative(bidResponse); + bidObject.mediaType = NATIVE; + } + + if (type === BANNER) { + bidObject.ad = replaceAuctionPrice(bidResponse.adm, bidResponse.price); + bidObject.width = bidResponse.w; + bidObject.height = bidResponse.h; + bidObject.mediaType = BANNER; + } + + return bidObject; } }) .filter(Boolean); } }; -registerBidder(spec); +function transformSizes(requestSizes) { + if (!isArray(requestSizes)) { + return []; + } + + if (requestSizes.length === 2 && !isArray(requestSizes[0])) { + return [{ + w: parseInt(requestSizes[0], 10), + h: parseInt(requestSizes[1], 10) + }]; + } else if (isArray(requestSizes[0])) { + return requestSizes.map(item => ({ + w: parseInt(item[0], 10), + h: parseInt(item[1], 10) + })); + } + + return []; +} + +function flatten(arr) { + return [].concat(...arr); +} function parseNative(bid) { - const {assets, link, imptrackers} = bid.adm.native; + const { assets, link, imptrackers } = bid.adm.native; let clickUrl = link.url.replace(/\$\{AUCTION_PRICE\}/g, bid.price); @@ -228,15 +252,4 @@ function parseNative(bid) { return result; } -function setOnAny(collection, key) { - for (let i = 0, result; i < collection.length; i++) { - result = deepAccess(collection[i], key); - if (result) { - return result; - } - } -} - -function flatten(arr) { - return [].concat(...arr); -} +registerBidder(spec); diff --git a/test/spec/modules/seedingAllianceAdapter_spec.js b/test/spec/modules/seedingAllianceAdapter_spec.js index 81af9546ff0..6086db01de4 100755 --- a/test/spec/modules/seedingAllianceAdapter_spec.js +++ b/test/spec/modules/seedingAllianceAdapter_spec.js @@ -38,7 +38,7 @@ describe('SeedingAlliance adapter', function () { }); it('should have default request structure', function () { - let keys = 'site,device,cur,imp,user,regs'.split(','); + let keys = 'site,cur,imp,regs'.split(','); let validBidRequests = [{ bidId: 'bidId', params: {} @@ -60,14 +60,17 @@ describe('SeedingAlliance adapter', function () { assert.equal(request.id, validBidRequests[0].auctionId); }); - it('Verify the device', function () { + it('Verify the site url', function () { + let siteUrl = 'https://www.yourdomain.tld/your-directory/'; let validBidRequests = [{ bidId: 'bidId', - params: {} + params: { + url: siteUrl + } }]; let request = JSON.parse(spec.buildRequests(validBidRequests, { refererInfo: { referer: 'page' } }).data); - assert.equal(request.device.ua, navigator.userAgent); + assert.equal(request.site.page, siteUrl); }); it('Verify native asset ids', function () { @@ -109,7 +112,7 @@ describe('SeedingAlliance adapter', function () { }); describe('interpretResponse', function () { - const goodResponse = { + const goodNativeResponse = { body: { cur: 'EUR', id: '4b516b80-886e-4ec0-82ae-9209e6d625fb', @@ -136,51 +139,91 @@ describe('SeedingAlliance adapter', function () { ] } }; + + const goodBannerResponse = { + body: { + cur: 'EUR', + id: 'b4516b80-886e-4ec0-82ae-9209e6d625fb', + seatbid: [ + { + seat: 'seedingAlliance', + bid: [{ + adm: '', + impid: 1, + price: 0.90, + h: 250, + w: 300 + }] + } + ] + } + }; + const badResponse = { body: { cur: 'EUR', id: '4b516b80-886e-4ec0-82ae-9209e6d625fb', seatbid: [] }}; - const bidRequest = { + const bidNativeRequest = { data: {}, - bids: [{ bidId: 'bidId1' }] + bidRequests: [{bidId: 'bidId1', nativeParams: {title: {required: true, len: 800}}}] + }; + + const bidBannerRequest = { + data: {}, + bidRequests: [{bidId: 'bidId1', sizes: [300, 250]}] }; it('should return null if body is missing or empty', function () { - const result = spec.interpretResponse(badResponse, bidRequest); + const result = spec.interpretResponse(badResponse, bidNativeRequest); assert.equal(result.length, 0); delete badResponse.body - const result1 = spec.interpretResponse(badResponse, bidRequest); + const result1 = spec.interpretResponse(badResponse, bidNativeRequest); assert.equal(result.length, 0); }); it('should return the correct params', function () { - const result = spec.interpretResponse(goodResponse, bidRequest); - const bid = goodResponse.body.seatbid[0].bid[0]; - - assert.deepEqual(result[0].currency, goodResponse.body.cur); - assert.deepEqual(result[0].requestId, bidRequest.bids[0].bidId); - assert.deepEqual(result[0].cpm, bid.price); - assert.deepEqual(result[0].creativeId, bid.crid); - assert.deepEqual(result[0].mediaType, 'native'); - assert.deepEqual(result[0].bidderCode, 'seedingAlliance'); + const resultNative = spec.interpretResponse(goodNativeResponse, bidNativeRequest); + const bidNative = goodNativeResponse.body.seatbid[0].bid[0]; + + assert.deepEqual(resultNative[0].bidderCode, 'seedingAlliance'); + assert.deepEqual(resultNative[0].currency, goodNativeResponse.body.cur); + assert.deepEqual(resultNative[0].requestId, bidNativeRequest.bidRequests[0].bidId); + assert.deepEqual(resultNative[0].cpm, bidNative.price); + assert.deepEqual(resultNative[0].creativeId, bidNative.crid); + assert.deepEqual(resultNative[0].mediaType, 'native'); + + const resultBanner = spec.interpretResponse(goodBannerResponse, bidBannerRequest); + + assert.deepEqual(resultBanner[0].bidderCode, 'seedingAlliance'); + assert.deepEqual(resultBanner[0].mediaType, 'banner'); + assert.deepEqual(resultBanner[0].width, bidBannerRequest.bidRequests[0].sizes[0]); + assert.deepEqual(resultBanner[0].height, bidBannerRequest.bidRequests[0].sizes[1]); }); - it('should return the correct tracking links', function () { - const result = spec.interpretResponse(goodResponse, bidRequest); - const bid = goodResponse.body.seatbid[0].bid[0]; + it('should return the correct native tracking links', function () { + const result = spec.interpretResponse(goodNativeResponse, bidNativeRequest); + const bid = goodNativeResponse.body.seatbid[0].bid[0]; const regExpPrice = new RegExp('price=' + bid.price); result[0].native.clickTrackers.forEach(function (clickTracker) { - assert.ok(clickTracker.search(regExpPrice) > -1); + assert.ok(clickTracker.search(regExpPrice) > -1); }); result[0].native.impressionTrackers.forEach(function (impTracker) { - assert.ok(impTracker.search(regExpPrice) > -1); + assert.ok(impTracker.search(regExpPrice) > -1); }); }); + + it('should return the correct banner content', function () { + const result = spec.interpretResponse(goodBannerResponse, bidBannerRequest); + const bid = goodBannerResponse.body.seatbid[0].bid[0]; + const regExpContent = new RegExp(''); + + assert.ok(result[0].ad.search(regExpContent) > -1); + }); }); }); From 628c22931d9d49c11a014b1a7fb6197fb4b04b69 Mon Sep 17 00:00:00 2001 From: EMX Digital <43830380+EMXDigital@users.noreply.github.com> Date: Wed, 25 Jan 2023 09:16:16 -0800 Subject: [PATCH 288/367] Emx Digital Bid Adapter : adding US Privacy string support (#9461) * adding ccpa support for emx_digital adapter * emx_digital ccpa compliance: lint fix * emx 3.0 compliance update * fix outstream renderer issue, update test spec * refactor formatVideoResponse function to use core-js/find * Add support for schain forwarding * Resolved issue with Schain object location * prebid 5.0 floor module and advertiserDomain support * liveramp idl and uid2.0 support for prebid * gpid support * remove utils ext * remove empty line * remove trailing spaces * move gpid test module * move gpid test module * removing trailing spaces from unit test * remove comments from unit test * Include us_privacy string in redirects (#8) * include us_privacy string in redirects * added test cases for us_privacy and gdpr * added test cases for gdpr without usp * updated test case when no privacy strings and fixed package-lock.json * revert package-lock.json Co-authored-by: EMXDigital * kick off ci tests Co-authored-by: Nick Colletti Co-authored-by: Nick Colletti Co-authored-by: Kiyoshi Hara Co-authored-by: Dan Bogdan Co-authored-by: Jherez Taylor Co-authored-by: EMXDigital Co-authored-by: Rakesh Balakrishnan Co-authored-by: Kevin Co-authored-by: Chris Huie --- modules/emx_digitalBidAdapter.js | 11 +++++-- .../modules/emx_digitalBidAdapter_spec.js | 31 ++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/modules/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js index eb69e76a837..99f313b9484 100644 --- a/modules/emx_digitalBidAdapter.js +++ b/modules/emx_digitalBidAdapter.js @@ -354,16 +354,23 @@ export const spec = { }, getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { const syncs = []; + const consentParams = []; if (syncOptions.iframeEnabled) { let url = 'https://biddr.brealtime.com/check.html'; if (gdprConsent && typeof gdprConsent.consentString === 'string') { // add 'gdpr' only if 'gdprApplies' is defined if (typeof gdprConsent.gdprApplies === 'boolean') { - url += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + consentParams.push(`gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`); } else { - url += `?gdpr_consent=${gdprConsent.consentString}`; + consentParams.push(`?gdpr_consent=${gdprConsent.consentString}`); } } + if (uspConsent && typeof uspConsent.consentString === 'string') { + consentParams.push(`usp=${uspConsent.consentString}`); + } + if (consentParams.length > 0) { + url = url + '?' + consentParams.join('&'); + } syncs.push({ type: 'iframe', url: url diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js index d99318b5ddc..d80d0f3e875 100644 --- a/test/spec/modules/emx_digitalBidAdapter_spec.js +++ b/test/spec/modules/emx_digitalBidAdapter_spec.js @@ -707,7 +707,7 @@ describe('emx_digital Adapter', function () { })); }); - it('returns valid advertiser domain', function () { + it('returns valid advertiser domains', function () { const bidResponse = utils.deepClone(serverResponse); let result = spec.interpretResponse({body: bidResponse}); expect(result[0].meta.advertiserDomains).to.deep.equal(expectedResponse[0].meta.advertiserDomains); @@ -724,6 +724,7 @@ describe('emx_digital Adapter', function () { 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.equal('https://biddr.brealtime.com/check.html') }); it('should pass gdpr params', function () { @@ -734,6 +735,34 @@ describe('emx_digital Adapter', function () { expect(syncs).to.have.lengthOf(1); expect(syncs[0].type).to.equal('iframe'); expect(syncs[0].url).to.contains('gdpr=0'); + expect(syncs[0].url).to.equal('https://biddr.brealtime.com/check.html?gdpr=0&gdpr_consent=test') + }); + + it('should pass us_privacy string', function () { + let syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, { + 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('usp=test'); + }); + + it('should pass us_privacy and gdpr strings', function () { + let syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, + { + gdprApplies: true, + consentString: 'test' + }, + { + 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=1'); + expect(syncs[0].url).to.contains('usp=test'); + expect(syncs[0].url).to.equal('https://biddr.brealtime.com/check.html?gdpr=1&gdpr_consent=test&usp=test') }); }); }); From fd952368c8bd3ca070645d28aedf9fcdca592da8 Mon Sep 17 00:00:00 2001 From: Jason Piros Date: Wed, 25 Jan 2023 09:17:40 -0800 Subject: [PATCH 289/367] consumableBidAdapter: add gdpr and usp sync params (#9463) --- modules/consumableBidAdapter.js | 22 ++++++++- .../spec/modules/consumableBidAdapter_spec.js | 46 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/modules/consumableBidAdapter.js b/modules/consumableBidAdapter.js index c91f1a7f906..4e2a92fb594 100644 --- a/modules/consumableBidAdapter.js +++ b/modules/consumableBidAdapter.js @@ -180,12 +180,26 @@ export const spec = { return bidResponses; }, - getUserSyncs: function(syncOptions, serverResponses) { + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { + let syncUrl = 'https://sync.serverbid.com/ss/' + siteId + '.html'; + if (syncOptions.iframeEnabled) { + if (gdprConsent && gdprConsent.consentString) { + if (typeof gdprConsent.gdprApplies === 'boolean') { + syncUrl = appendUrlParam(syncUrl, `gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`); + } else { + syncUrl = appendUrlParam(syncUrl, `gdpr=0&gdpr_consent=${gdprConsent.consentString}`); + } + } + + if (uspConsent && uspConsent.consentString) { + syncUrl = appendUrlParam(syncUrl, `us_privacy=${uspConsent.consentString}`); + } + if (!serverResponses || serverResponses.length === 0 || !serverResponses[0].body.bdr || serverResponses[0].body.bdr !== 'cx') { return [{ type: 'iframe', - url: 'https://sync.serverbid.com/ss/' + siteId + '.html' + url: syncUrl }]; } } @@ -294,4 +308,8 @@ function getBidFloor(bid, sizes) { return floor; } +function appendUrlParam(url, queryString) { + return `${url}${url.indexOf('?') > -1 ? '&' : '?'}${queryString}`; +} + registerBidder(spec); diff --git a/test/spec/modules/consumableBidAdapter_spec.js b/test/spec/modules/consumableBidAdapter_spec.js index d1b310624a6..556dce447b9 100644 --- a/test/spec/modules/consumableBidAdapter_spec.js +++ b/test/spec/modules/consumableBidAdapter_spec.js @@ -625,6 +625,52 @@ describe('Consumable BidAdapter', function () { expect(opts.length).to.equal(1); }); + it('should return a sync url if iframe syncs are enabled and GDPR applies', function () { + let gdprConsent = { + consentString: 'GDPR_CONSENT_STRING', + gdprApplies: true, + } + let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], gdprConsent); + + expect(opts.length).to.equal(1); + expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?gdpr=1&gdpr_consent=GDPR_CONSENT_STRING'); + }) + + it('should return a sync url if iframe syncs are enabled and GDPR is undefined', function () { + let gdprConsent = { + consentString: 'GDPR_CONSENT_STRING', + gdprApplies: undefined, + } + let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], gdprConsent); + + expect(opts.length).to.equal(1); + expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?gdpr=0&gdpr_consent=GDPR_CONSENT_STRING'); + }) + + it('should return a sync url if iframe syncs are enabled and USP applies', function () { + let uspConsent = { + consentString: 'USP_CONSENT_STRING', + } + let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], {}, uspConsent); + + expect(opts.length).to.equal(1); + expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?us_privacy=USP_CONSENT_STRING'); + }) + + it('should return a sync url if iframe syncs are enabled, GDPR and USP applies', function () { + let gdprConsent = { + consentString: 'GDPR_CONSENT_STRING', + gdprApplies: true, + } + let uspConsent = { + consentString: 'USP_CONSENT_STRING', + } + let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], gdprConsent, uspConsent); + + expect(opts.length).to.equal(1); + expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?gdpr=1&gdpr_consent=GDPR_CONSENT_STRING&us_privacy=USP_CONSENT_STRING'); + }) + it('should return a sync url if pixel syncs are enabled and some are returned from the server', function () { let syncOptions = {'pixelEnabled': true}; let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE]); From ff84384903473b6fdf57fdedba659645ff04041b Mon Sep 17 00:00:00 2001 From: Chris Huie Date: Wed, 25 Jan 2023 11:48:41 -0700 Subject: [PATCH 290/367] PBS Bid Adapter : site should not exist when app is present (#9258) * Update prebidServerBidAdapter_spec.js * Update prebidServerBidAdapter_spec.js * fix test * remove app from site test * add site/app/dooh function * fix config * remove deepSetValue * add to ortb converter * add check * add back publisher.id * fix linting * ortb conversion lib: leave only one of dooh, app, or site in the request Co-authored-by: Demetrio Girardi --- libraries/ortbConverter/processors/default.js | 20 +++++++++++++++- .../prebidServerBidAdapter/ortbConverter.js | 2 +- .../modules/prebidServerBidAdapter_spec.js | 22 ++++++++++++++++++ .../ortbConverter/default_processors_spec.js | 23 +++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 test/spec/ortbConverter/default_processors_spec.js diff --git a/libraries/ortbConverter/processors/default.js b/libraries/ortbConverter/processors/default.js index 8d44de00fa2..1d6bfb8424e 100644 --- a/libraries/ortbConverter/processors/default.js +++ b/libraries/ortbConverter/processors/default.js @@ -1,4 +1,4 @@ -import {deepSetValue, mergeDeep} from '../../../src/utils.js'; +import {deepSetValue, logWarn, mergeDeep} from '../../../src/utils.js'; import {bannerResponseProcessor, fillBannerImp} from './banner.js'; import {fillVideoImp, fillVideoResponse} from './video.js'; import {setResponseMediaType} from './mediaType.js'; @@ -20,6 +20,10 @@ export const DEFAULT_PROCESSORS = { appFpd: fpdFromTopLevelConfig('app'), siteFpd: fpdFromTopLevelConfig('site'), deviceFpd: fpdFromTopLevelConfig('device'), + onlyOneClient: { + priority: -99, + fn: onlyOneClientSection + }, props: { // sets request properties id, tmax, test, source.tid fn(ortbRequest, bidderRequest) { @@ -133,3 +137,17 @@ function fpdFromTopLevelConfig(prop) { } } } + +export function onlyOneClientSection(ortbRequest) { + ['dooh', 'app', 'site'].reduce((found, section) => { + if (ortbRequest[section] != null && Object.keys(ortbRequest[section]).length > 0) { + if (found != null) { + logWarn(`ORTB request specifies both '${found}' and '${section}'; dropping the latter.`) + delete ortbRequest[section]; + } else { + found = section; + } + } + return found; + }, null); +} diff --git a/modules/prebidServerBidAdapter/ortbConverter.js b/modules/prebidServerBidAdapter/ortbConverter.js index 83335f81bc2..e35a3825826 100644 --- a/modules/prebidServerBidAdapter/ortbConverter.js +++ b/modules/prebidServerBidAdapter/ortbConverter.js @@ -47,7 +47,7 @@ const PBS_CONVERTER = ortbConverter({ request.tmax = s2sBidRequest.s2sConfig.timeout; deepSetValue(request, 'source.tid', proxyBidderRequest.auctionId); - [request.app, request.site].forEach(section => { + [request.app, request.dooh, request.site].forEach(section => { if (section && !section.publisher?.id) { deepSetValue(section, 'publisher.id', s2sBidRequest.s2sConfig.accountId); } diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 9da242381be..999a4477d19 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1505,6 +1505,28 @@ describe('S2S Adapter', function () { }); }); + it('site should not be present when app is present', function () { + const _config = { + s2sConfig: CONFIG, + app: { bundle: 'com.test.app' }, + site: { + publisher: { + id: '1234', + domain: 'test.com' + }, + content: { + language: 'en' + } + } + }; + + config.setConfig(_config); + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + const requestBid = JSON.parse(server.requests[0].requestBody); + expect(requestBid.site).to.not.exist; + expect(requestBid.app).to.exist.and.to.be.a('object'); + }); + it('adds appnexus aliases to request', function () { config.setConfig({ s2sConfig: CONFIG }); diff --git a/test/spec/ortbConverter/default_processors_spec.js b/test/spec/ortbConverter/default_processors_spec.js new file mode 100644 index 00000000000..48204b2c861 --- /dev/null +++ b/test/spec/ortbConverter/default_processors_spec.js @@ -0,0 +1,23 @@ +import {onlyOneClientSection} from '../../../libraries/ortbConverter/processors/default.js'; + +describe('onlyOneClientSection', () => { + [ + [['app'], 'app'], + [['site'], 'site'], + [['dooh'], 'dooh'], + [['app', 'site'], 'app'], + [['dooh', 'app', 'site'], 'dooh'], + [['dooh', 'site'], 'dooh'] + ].forEach(([sections, winner]) => { + it(`should leave only ${winner} in request when it contains ${sections.join(', ')}`, () => { + const req = Object.fromEntries(sections.map(s => [s, {foo: 'bar'}])); + onlyOneClientSection(req); + expect(Object.keys(req)).to.eql([winner]); + }) + }); + it('should not choke if none of the sections are in the request', () => { + const req = {}; + onlyOneClientSection(req); + expect(req).to.eql({}); + }); +}); From ed385ba9a5dd1d795fd7830267832eb8d61bb4d4 Mon Sep 17 00:00:00 2001 From: Jason Quaccia Date: Wed, 25 Jan 2023 12:48:49 -0800 Subject: [PATCH 291/367] updated pbs filterSettings to sync with pbjs config filterSettings (#9423) --- modules/prebidServerBidAdapter/index.js | 15 ++- .../modules/prebidServerBidAdapter_spec.js | 116 ++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index b609d1a54ec..924748ce197 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -222,10 +222,23 @@ function queueSync(bidderCodes, gdprConsent, uspConsent, gppConsent, s2sConfig) } _syncCount++; + let filterSettings = {}; + const userSyncFilterSettings = getConfig('userSync.filterSettings'); + + if (userSyncFilterSettings) { + const { all, iframe, image } = userSyncFilterSettings; + const ifrm = iframe || all; + const img = image || all; + + if (ifrm) filterSettings = Object.assign({ iframe: ifrm }, filterSettings); + if (img) filterSettings = Object.assign({ image: img }, filterSettings); + } + const payload = { uuid: generateUUID(), bidders: bidderCodes, - account: s2sConfig.accountId + account: s2sConfig.accountId, + filterSettings }; let userSyncLimit = s2sConfig.userSyncLimit; diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 999a4477d19..cffc75f6949 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1,3 +1,4 @@ +/* eslint-disable no-trailing-spaces */ import {expect} from 'chai'; import { PrebidServer as Adapter, @@ -1725,6 +1726,121 @@ describe('S2S Adapter', function () { }]); }); + describe('filterSettings', function () { + const getRequestBid = userSync => { + let cookieSyncConfig = utils.deepClone(CONFIG); + const s2sBidRequest = utils.deepClone(REQUEST); + cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; + s2sBidRequest.s2sConfig = cookieSyncConfig; + + config.setConfig({ userSync, s2sConfig: cookieSyncConfig }); + + let bidRequest = utils.deepClone(BID_REQUESTS); + adapter.callBids(s2sBidRequest, bidRequest, addBidResponse, done, ajax); + return JSON.parse(server.requests[0].requestBody); + } + + it('correctly adds filterSettings to the cookie_sync request if userSync.filterSettings is present in the config and only the all key is present in userSync.filterSettings', function () { + const userSync = { + filterSettings: { + all: { + bidders: ['appnexus', 'rubicon', 'pubmatic'], + filter: 'exclude' + } + } + }; + const requestBid = getRequestBid(userSync); + + expect(requestBid.filterSettings).to.deep.equal({ + 'image': { + 'bidders': ['appnexus', 'rubicon', 'pubmatic'], + 'filter': 'exclude' + }, + 'iframe': { + 'bidders': ['appnexus', 'rubicon', 'pubmatic'], + 'filter': 'exclude' + } + }); + }); + + it('correctly adds filterSettings to the cookie_sync request if userSync.filterSettings is present in the config and only the iframe key is present in userSync.filterSettings', function () { + const userSync = { + filterSettings: { + iframe: { + bidders: ['rubicon', 'pubmatic'], + filter: 'include' + } + } + }; + const requestBid = getRequestBid(userSync); + + expect(requestBid.filterSettings).to.deep.equal({ + 'image': { + 'bidders': '*', + 'filter': 'include' + }, + 'iframe': { + 'bidders': ['rubicon', 'pubmatic'], + 'filter': 'include' + } + }); + }); + + it('correctly adds filterSettings to the cookie_sync request if userSync.filterSettings is present in the config and the image and iframe keys are both present in userSync.filterSettings', function () { + const userSync = { + filterSettings: { + image: { + bidders: ['triplelift', 'appnexus'], + filter: 'include' + }, + iframe: { + bidders: ['pulsepoint', 'triplelift', 'appnexus', 'rubicon'], + filter: 'exclude' + } + } + }; + const requestBid = getRequestBid(userSync); + + expect(requestBid.filterSettings).to.deep.equal({ + 'image': { + 'bidders': ['triplelift', 'appnexus'], + 'filter': 'include' + }, + 'iframe': { + 'bidders': ['pulsepoint', 'triplelift', 'appnexus', 'rubicon'], + 'filter': 'exclude' + } + }); + }); + + it('correctly adds filterSettings to the cookie_sync request if userSync.filterSettings is present in the config and the all and iframe keys are both present in userSync.filterSettings', function () { + const userSync = { + filterSettings: { + all: { + bidders: ['triplelift', 'appnexus'], + filter: 'include' + }, + iframe: { + bidders: ['pulsepoint', 'triplelift', 'appnexus', 'rubicon'], + filter: 'exclude' + } + } + }; + const requestBid = getRequestBid(userSync); + + expect(requestBid.filterSettings).to.deep.equal({ + 'image': { + 'bidders': ['triplelift', 'appnexus'], + 'filter': 'include' + }, + 'iframe': { + 'bidders': ['pulsepoint', 'triplelift', 'appnexus', 'rubicon'], + 'filter': 'exclude' + } + }); + }); + }); + it('adds limit to the cookie_sync request if userSyncLimit is greater than 0', function () { let cookieSyncConfig = utils.deepClone(CONFIG); cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; From bd57c8dffe2effe149d3f0e71ab07605c578dc8b Mon Sep 17 00:00:00 2001 From: Jose Cabal-Ugaz <6942011+josecu@users.noreply.github.com> Date: Wed, 25 Jan 2023 17:59:49 -0500 Subject: [PATCH 292/367] ArcSpan RTD Module: Initial Release (#9459) * Create arcspanRtdProvider.md * Added ArcSpan RTD Provider * Implemented alter bid request function in ArcSpan RTD Provider * Added unit tests for ArcSpan RTD Provider * Added more unit tests for ArcSpan RTD Provider * Load ArcSpan scripts using Prebid script loader * Fixed ArcSpan RTD module unit tests * Adding ArcSpan to submodules.json * Load ArcSpan script only if not already on the page * Load ArcSpan script only if not already on the page --- modules/.submodules.json | 1 + modules/arcspanRtdProvider.js | 73 ++++++++ modules/arcspanRtdProvider.md | 11 ++ src/adloader.js | 3 +- test/spec/modules/arcspanRtdProvider_spec.js | 187 +++++++++++++++++++ 5 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 modules/arcspanRtdProvider.js create mode 100644 modules/arcspanRtdProvider.md create mode 100644 test/spec/modules/arcspanRtdProvider_spec.js diff --git a/modules/.submodules.json b/modules/.submodules.json index deeee91e247..a535fd4988d 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -55,6 +55,7 @@ "aaxBlockmeterRtdProvider", "airgridRtdProvider", "akamaiDapRtdProvider", + "arcspanRtdProvider", "blueconicRtdProvider", "browsiRtdProvider", "captifyRtdProvider", diff --git a/modules/arcspanRtdProvider.js b/modules/arcspanRtdProvider.js new file mode 100644 index 00000000000..a7ffa059279 --- /dev/null +++ b/modules/arcspanRtdProvider.js @@ -0,0 +1,73 @@ +import { submodule } from '../src/hook.js'; +import { mergeDeep } from '../src/utils.js'; +import {loadExternalScript} from '../src/adloader.js'; + +/** @type {string} */ +const MODULE_NAME = 'realTimeData'; +const SUBMODULE_NAME = 'arcspan'; + +/** @type {RtdSubmodule} */ +export const arcspanSubmodule = { + name: SUBMODULE_NAME, + init: init, + getBidRequestData: alterBidRequests, +}; + +function init(config, userConsent) { + if (typeof config.params.silo === 'undefined') { + return false; + } + if (typeof window.arcobj2 === 'undefined') { + var scriptUrl; + if (config.params.silo === 'test') { + scriptUrl = 'https://localhost:8080/as.js'; + } else { + scriptUrl = 'https://silo' + config.params.silo + '.p7cloud.net/as.js'; + } + loadExternalScript(scriptUrl, SUBMODULE_NAME); + } + return true; +} + +function alterBidRequests(reqBidsConfigObj, callback, config, userConsent) { + var _v1 = []; + var _v1s = []; + var _v2 = []; + var arcobj1 = window.arcobj1; + if (typeof arcobj1 != 'undefined') { + if (typeof arcobj1.page_iab_codes.text != 'undefined') { _v1 = _v1.concat(arcobj1.page_iab_codes.text); } + if (typeof arcobj1.page_iab_codes.images != 'undefined') { _v1 = _v1.concat(arcobj1.page_iab_codes.images); } + if (typeof arcobj1.page_iab.text != 'undefined') { _v1s = _v1s.concat(arcobj1.page_iab.text); } + if (typeof arcobj1.page_iab.images != 'undefined') { _v1s = _v1s.concat(arcobj1.page_iab.images); } + if (typeof arcobj1.page_iab_newcodes.text != 'undefined') { _v2 = [...new Set([..._v2, ...arcobj1.page_iab_newcodes.text])]; } + if (typeof arcobj1.page_iab_newcodes.images != 'undefined') { _v2 = [...new Set([..._v2, ...arcobj1.page_iab_newcodes.images])]; } + + var _content = {}; + _content.data = []; + var p = {}; + p.name = 'arcspan'; + p.segment = []; + p.ext = { segtax: 6 }; + _v2.forEach(function (e) { + p.segment = p.segment.concat({ id: e }); + }); + _content.data = _content.data.concat(p); + var _ortb2 = { + site: { + name: 'arcspan', + domain: new URL(location.href).hostname, + cat: _v1, + sectioncat: _v1, + pagecat: _v1, + page: location.href, + ref: document.referrer, + keywords: _v1s.toString(), + content: _content, + }, + }; + mergeDeep(reqBidsConfigObj.ortb2Fragments.global, _ortb2); + } + callback(); +} + +submodule(MODULE_NAME, arcspanSubmodule); diff --git a/modules/arcspanRtdProvider.md b/modules/arcspanRtdProvider.md new file mode 100644 index 00000000000..4aa1de02acf --- /dev/null +++ b/modules/arcspanRtdProvider.md @@ -0,0 +1,11 @@ +# Overview + +Module Name: ArcSpan Rtd Provider + +Module Type: Rtd Provider + +Maintainer: engineering@arcspan.com + +# Description + +RTD provider for ArcSpan Technologies. Contact jcabalugaz@arcspan.com for more information. diff --git a/src/adloader.js b/src/adloader.js index 01a77971b93..f0b7f7f3e8c 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -21,7 +21,8 @@ const _approvedLoadExternalJSList = [ 'medianet', 'improvedigital', 'aaxBlockmeter', - 'confiant' + 'confiant', + 'arcspan' ] /** diff --git a/test/spec/modules/arcspanRtdProvider_spec.js b/test/spec/modules/arcspanRtdProvider_spec.js new file mode 100644 index 00000000000..c75075d8e05 --- /dev/null +++ b/test/spec/modules/arcspanRtdProvider_spec.js @@ -0,0 +1,187 @@ +import { arcspanSubmodule } from 'modules/arcspanRtdProvider.js'; +import { expect } from 'chai'; +import { loadExternalScript } from 'src/adloader.js'; + +describe('arcspanRtdProvider', function () { + describe('init', function () { + afterEach(function () { + window.arcobj1 = undefined; + window.arcobj2 = undefined; + }); + + it('successfully initializes with a valid silo ID', function () { + expect(arcspanSubmodule.init(getGoodConfig())).to.equal(true); + expect(loadExternalScript.called).to.be.ok; + expect(loadExternalScript.args[0][0]).to.deep.equal('https://silo13.p7cloud.net/as.js'); + loadExternalScript.resetHistory(); + }); + + it('fails to initialize with a missing silo ID', function () { + expect(arcspanSubmodule.init(getBadConfig())).to.equal(false); + expect(loadExternalScript.called).to.be.not.ok; + loadExternalScript.resetHistory(); + }); + + it('drops localhost script for test silo', function () { + expect(arcspanSubmodule.init(getTestConfig())).to.equal(true); + expect(loadExternalScript.called).to.be.ok; + expect(loadExternalScript.args[0][0]).to.deep.equal('https://localhost:8080/as.js'); + loadExternalScript.resetHistory(); + }); + }); + + describe('alterBidRequests', function () { + afterEach(function () { + window.arcobj1 = undefined; + window.arcobj2 = undefined; + }); + + it('alters the bid request 1', function () { + setIAB({ + raw: { + images: [ + 'Religion & Spirituality', + 'Medical Health>Substance Abuse', + 'Religion & Spirituality>Astrology', + 'Medical Health', + 'Events & Attractions', + ], + }, + codes: { + images: ['IAB23-10', 'IAB7', 'IAB7-42', 'IAB15-1'], + }, + newcodes: { + images: ['150', '453', '311', '456', '286'], + }, + }); + + var reqBidsConfigObj = {}; + reqBidsConfigObj.ortb2Fragments = {}; + reqBidsConfigObj.ortb2Fragments.global = {}; + arcspanSubmodule.getBidRequestData(reqBidsConfigObj, function () { + expect(reqBidsConfigObj.ortb2Fragments.global.site.name).to.equal( + 'arcspan' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.site.keywords).to.equal( + 'Religion & Spirituality,Medical Health>Substance Abuse,Religion & Spirituality>Astrology,Medical Health,Events & Attractions' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].ext.segtax).to.equal(6); + expect(reqBidsConfigObj.ortb2Fragments.global.site.cat).to.eql([ + 'IAB23_10', + 'IAB7', + 'IAB7_42', + 'IAB15_1', + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.sectioncat).to.eql([ + 'IAB23_10', + 'IAB7', + 'IAB7_42', + 'IAB15_1' + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.pagecat).to.eql([ + 'IAB23_10', + 'IAB7', + 'IAB7_42', + 'IAB15_1', + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].segment).to.eql([ + { id: '150' }, + { id: '453' }, + { id: '311' }, + { id: '456' }, + { id: '286' } + ]); + }); + }); + + it('alters the bid request 2', function () { + setIAB({ + raw: { text: ['Sports', 'Sports>Soccer'] }, + codes: { text: ['IAB17', 'IAB17-44'] }, + newcodes: { text: ['483', '533'] }, + }); + + var reqBidsConfigObj = {}; + reqBidsConfigObj.ortb2Fragments = {}; + reqBidsConfigObj.ortb2Fragments.global = {}; + arcspanSubmodule.getBidRequestData(reqBidsConfigObj, function () { + expect(reqBidsConfigObj.ortb2Fragments.global.site.name).to.equal( + 'arcspan' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.site.keywords).to.equal( + 'Sports,Sports>Soccer' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].ext.segtax).to.equal(6); + expect(reqBidsConfigObj.ortb2Fragments.global.site.cat).to.eql([ + 'IAB17', + 'IAB17_44', + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.sectioncat).to.eql([ + 'IAB17', + 'IAB17_44' + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.pagecat).to.eql([ + 'IAB17', + 'IAB17_44', + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].segment).to.eql([ + { id: '483' }, + { id: '533' } + ]); + }); + }); + }); +}); + +function getGoodConfig() { + return { + name: 'arcspan', + waitForIt: true, + params: { + silo: 13, + }, + }; +} + +function getBadConfig() { + return { + name: 'arcspan', + waitForIt: true, + params: { + notasilo: 1, + }, + }; +} + +function getTestConfig() { + return { + name: 'arcspan', + waitForIt: true, + params: { + silo: 'test', + }, + }; +} + +function setIAB(vjson) { + window.arcobj2 = {}; + window.arcobj2.cat = 0; + if (typeof vjson.codes != 'undefined') { + window.arcobj2.cat = 1; + if (typeof vjson.codes.images != 'undefined') { + vjson.codes.images.forEach(function f(e, i) { + vjson.codes.images[i] = e.replace('-', '_'); + }); + } + if (typeof vjson.codes.text != 'undefined') { + vjson.codes.text.forEach(function f(e, i) { + vjson.codes.text[i] = e.replace('-', '_'); + }); + } + window.arcobj2.sampled = 1; + window.arcobj1 = {}; + window.arcobj1.page_iab_codes = vjson.codes; + window.arcobj1.page_iab = vjson.raw; + window.arcobj1.page_iab_newcodes = vjson.newcodes; + } +} From 39c2f87a2b791363e1c4066176b41a0572aa803f Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 26 Jan 2023 06:46:58 -0700 Subject: [PATCH 293/367] Update issue tracker action to use new gh api (#9466) --- .github/workflows/issue_tracker.yml | 41 ++++++++++++++++++----------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/.github/workflows/issue_tracker.yml b/.github/workflows/issue_tracker.yml index 4a9502e38c1..29082a4990a 100644 --- a/.github/workflows/issue_tracker.yml +++ b/.github/workflows/issue_tracker.yml @@ -29,21 +29,30 @@ jobs: gh api graphql -f query=' query($org: String!, $number: Int!) { organization(login: $org){ - projectNext(number: $number) { + projectV2(number: $number) { id fields(first:100) { nodes { - id - name - settings + ... on ProjectV2Field { + id + name + } + ... on ProjectV2SingleSelectField { + id + name + options { + id + name + } + } } } } } }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json - echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV - echo 'DATE_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "'"$DATE_FIELD"'") | .id' project_data.json) >> $GITHUB_ENV + echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV + echo 'DATE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name=="'"$DATE_FIELD"'") | .id' project_data.json) >> $GITHUB_ENV - name: Add issue to project env: @@ -52,9 +61,9 @@ jobs: run: | gh api graphql -f query=' mutation($project:ID!, $issue:ID!) { - addProjectNextItem(input: {projectId: $project, contentId: $issue}) { - projectNextItem { - id, + addProjectV2ItemById(input: {projectId: $project, contentId: $issue}) { + item { + id content { ... on Issue { createdAt @@ -67,8 +76,8 @@ jobs: } }' -f project=$PROJECT_ID -f issue=$ISSUE_ID > issue_data.json - echo 'ITEM_ID='$(jq '.data.addProjectNextItem.projectNextItem.id' issue_data.json) >> $GITHUB_ENV - echo 'ITEM_CREATION_DATE='$(jq '.data.addProjectNextItem.projectNextItem.content.createdAt' issue_data.json) >> $GITHUB_ENV + echo 'ITEM_ID='$(jq '.data.addProjectV2ItemById.item.id' issue_data.json) >> $GITHUB_ENV + echo 'ITEM_CREATION_DATE='$(jq '.data.addProjectV2ItemById.item.content.createdAt' issue_data.json | cut -c 2-11) >> $GITHUB_ENV - name: Set fields env: @@ -79,15 +88,17 @@ jobs: $project: ID! $item: ID! $date_field: ID! - $date_value: String! + $date_value: Date! ) { - set_creation_date: updateProjectNextItemField(input: { + set_creation_date: updateProjectV2ItemFieldValue(input: { projectId: $project itemId: $item fieldId: $date_field - value: $date_value + value: { + date: $date_value + } }) { - projectNextItem { + projectV2Item { id } } From 199349c30733e2aff1a43ababb613fa41caffec7 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 26 Jan 2023 15:20:39 +0000 Subject: [PATCH 294/367] Prebid 7.34.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6298a19479c..925a29338b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.34.0-pre", + "version": "7.34.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 4b52267af26..c5d5f83eb2c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.34.0-pre", + "version": "7.34.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 9a5f08ce3a9a86a337c9718bc159bdb5c814251d Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 26 Jan 2023 15:20:40 +0000 Subject: [PATCH 295/367] Increment version to 7.35.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 925a29338b4..6249ef52c04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.34.0", + "version": "7.35.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index c5d5f83eb2c..6467045121b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.34.0", + "version": "7.35.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 60f96abe1f0068820f25b99d9084165d050c25a8 Mon Sep 17 00:00:00 2001 From: Eugene Rachitskiy Date: Thu, 26 Jan 2023 10:54:52 -0500 Subject: [PATCH 296/367] PulsePoint Bid Adapter: support timeout/tmax (#9465) * ET-1691: Pulsepoint Analytics adapter for Prebid. (#1) * ET-1691: Adding pulsepoint analytics and tests for pulsepoint adapter * ET-1691: Adding pulsepoint analytics and tests for pulsepoint adapter * ET-1691: cleanup * ET-1691: minor * ET-1691: revert package.json change * Adding bidRequest to bidFactory.createBid method as per https://github.com/prebid/Prebid.js/issues/509 * ET-1765: Adding support for additional params in PulsePoint adapter (#2) * ET-1850: Fixing https://github.com/prebid/Prebid.js/issues/866 * Minor fix * Adding mandatory parameters to Bid * ET-12672 - passing tmax value to PulsePoint bidder * ET-12672 - using 500ms as a default and adding formatting Co-authored-by: anand-venkatraman --- modules/pulsepointBidAdapter.js | 2 ++ test/spec/modules/pulsepointBidAdapter_spec.js | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/pulsepointBidAdapter.js b/modules/pulsepointBidAdapter.js index 25f82fb60d9..015e80d5692 100644 --- a/modules/pulsepointBidAdapter.js +++ b/modules/pulsepointBidAdapter.js @@ -16,6 +16,7 @@ const DEFAULT_BID_TTL = 20; const DEFAULT_CURRENCY = 'USD'; const DEFAULT_NET_REVENUE = true; const KNOWN_PARAMS = ['cp', 'ct', 'cf', 'video', 'battr', 'bcat', 'badv', 'bidfloor']; +const DEFAULT_TMAX = 500; /** * PulsePoint Bid Adapter. @@ -54,6 +55,7 @@ export const spec = { user: user(bidRequests[0], bidderRequest), regs: regs(bidderRequest), source: source(bidRequests[0].schain), + tmax: bidderRequest.timeout || DEFAULT_TMAX, }; return { method: 'POST', diff --git a/test/spec/modules/pulsepointBidAdapter_spec.js b/test/spec/modules/pulsepointBidAdapter_spec.js index 825b3abf432..60dca9e6da0 100644 --- a/test/spec/modules/pulsepointBidAdapter_spec.js +++ b/test/spec/modules/pulsepointBidAdapter_spec.js @@ -2,7 +2,6 @@ import {expect} from 'chai'; import {spec} from 'modules/pulsepointBidAdapter.js'; import {deepClone} from 'src/utils.js'; -import { config } from 'src/config.js'; describe('PulsePoint Adapter Tests', function () { const slotConfigs = [{ @@ -225,6 +224,8 @@ describe('PulsePoint Adapter Tests', function () { 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); + // tmax + expect(ortbRequest.tmax).to.equal(500); }); it('Verify parse response', function () { @@ -918,4 +919,13 @@ describe('PulsePoint Adapter Tests', function () { } }); }); + + it('Verify bid request timeouts', function () { + const mkRequest = (bidderRequest) => spec.buildRequests(slotConfigs, bidderRequest).data; + // assert default is used when no bidderRequest.timeout value is available + expect(mkRequest(bidderRequest).tmax).to.equal(500) + + // assert bidderRequest value is used when available + expect(mkRequest(Object.assign({}, { timeout: 6000 }, bidderRequest)).tmax).to.equal(6000) + }); }); From ba7d0d0026484396d3098da5dfc96586ca68568b Mon Sep 17 00:00:00 2001 From: joseluis laso Date: Thu, 26 Jan 2023 19:44:41 +0100 Subject: [PATCH 297/367] hadronId user id submodule: force localStorage (#9432) * Storing hadronId in localStorage after getting it from server * reverting hadronId documentation --- modules/hadronIdSystem.js | 69 +++++++++++++----------- test/spec/modules/hadronIdSystem_spec.js | 10 ++-- test/spec/modules/userId_spec.js | 33 +++++++----- 3 files changed, 60 insertions(+), 52 deletions(-) diff --git a/modules/hadronIdSystem.js b/modules/hadronIdSystem.js index 2f10245cd59..a75c03ee1c4 100644 --- a/modules/hadronIdSystem.js +++ b/modules/hadronIdSystem.js @@ -8,8 +8,9 @@ import {ajax} from '../src/ajax.js'; import {getStorageManager} from '../src/storageManager.js'; import {submodule} from '../src/hook.js'; -import { isFn, isStr, isPlainObject, logError } from '../src/utils.js'; +import {isFn, isStr, isPlainObject, logError, logInfo} from '../src/utils.js'; +const HADRONID_LOCAL_NAME = 'auHadronId'; const MODULE_NAME = 'hadronId'; const AU_GVLID = 561; const DEFAULT_HADRON_URL_ENDPOINT = 'https://id.hadron.ad.gt/api/v1/pbhid'; @@ -18,8 +19,9 @@ export const storage = getStorageManager({gvlid: AU_GVLID, moduleName: 'hadron'} /** * Param or default. - * @param {String} param + * @param {String|function} param * @param {String} defaultVal + * @param arg */ function paramOrDefault(param, defaultVal, arg) { if (isFn(param)) { @@ -53,11 +55,11 @@ export const hadronIdSubmodule = { * @returns {Object} */ decode(value) { - let hadronId = storage.getDataFromLocalStorage('auHadronId'); + const hadronId = storage.getDataFromLocalStorage(HADRONID_LOCAL_NAME); if (isStr(hadronId)) { return {hadronId: hadronId}; } - return (value && typeof value['hadronId'] === 'string') ? { 'hadronId': value['hadronId'] } : undefined; + return (value && typeof value['hadronId'] === 'string') ? {'hadronId': value['hadronId']} : undefined; }, /** * performs action to obtain id and return a value in the callback's response argument @@ -70,37 +72,40 @@ export const hadronIdSubmodule = { config.params = {}; } const partnerId = config.params.partnerId | 0; - - const url = urlAddParams( - paramOrDefault(config.params.url, DEFAULT_HADRON_URL_ENDPOINT, config.params.urlArg), - `partner_id=${partnerId}&_it=prebid` - ); - + let hadronId = storage.getDataFromLocalStorage(HADRONID_LOCAL_NAME); + if (isStr(hadronId)) { + return {id: {hadronId}}; + } const resp = function (callback) { - let hadronId = storage.getDataFromLocalStorage('auHadronId'); - if (isStr(hadronId)) { - const responseObj = {hadronId: hadronId}; - callback(responseObj); - } else { - const callbacks = { - success: response => { - let responseObj; - if (response) { - try { - responseObj = JSON.parse(response); - } catch (error) { - logError(error); - } + let responseObj = {}; + const callbacks = { + success: response => { + if (response) { + try { + responseObj = JSON.parse(response); + } catch (error) { + logError(error); } - callback(responseObj); - }, - error: error => { - logError(`${MODULE_NAME}: ID fetch encountered an error`, error); - callback(); + logInfo(`Response from backend is ${responseObj}`); + hadronId = responseObj['hadronId']; + storage.setDataInLocalStorage(HADRONID_LOCAL_NAME, hadronId); + responseObj = {id: {hadronId}}; } - }; - ajax(url, callbacks, undefined, {method: 'GET'}); - } + callback(responseObj); + }, + error: error => { + logError(`${MODULE_NAME}: ID fetch encountered an error`, error); + callback(); + } + }; + logInfo('HadronId not found in storage, calling backend...'); + const url = urlAddParams( + // config.params.url and config.params.urlArg are not documented + // since their use is for debugging purposes only + paramOrDefault(config.params.url, DEFAULT_HADRON_URL_ENDPOINT, config.params.urlArg), + `partner_id=${partnerId}&_it=prebid` + ); + ajax(url, callbacks, undefined, {method: 'GET'}); }; return {callback: resp}; } diff --git a/test/spec/modules/hadronIdSystem_spec.js b/test/spec/modules/hadronIdSystem_spec.js index ca9eadc7fd4..c998ef2cf14 100644 --- a/test/spec/modules/hadronIdSystem_spec.js +++ b/test/spec/modules/hadronIdSystem_spec.js @@ -24,7 +24,7 @@ describe('HadronIdSystem', function () { const request = server.requests[0]; expect(request.url).to.eq(`https://id.hadron.ad.gt/api/v1/pbhid?partner_id=0&_it=prebid`); request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ hadronId: 'testHadronId1' })); - expect(callbackSpy.lastCall.lastArg).to.deep.equal({hadronId: 'testHadronId1'}); + expect(callbackSpy.lastCall.lastArg).to.deep.equal({ id: { hadronId: 'testHadronId1' } }); }); it('gets a cached hadronid', function() { @@ -33,10 +33,8 @@ describe('HadronIdSystem', function () { }; getDataFromLocalStorageStub.withArgs('auHadronId').returns('tstCachedHadronId1'); - const callbackSpy = sinon.spy(); - const callback = hadronIdSubmodule.getId(config).callback; - callback(callbackSpy); - expect(callbackSpy.lastCall.lastArg).to.deep.equal({hadronId: 'tstCachedHadronId1'}); + const result = hadronIdSubmodule.getId(config); + expect(result).to.deep.equal({ id: { hadronId: 'tstCachedHadronId1' } }); }); it('allows configurable id url', function() { @@ -51,7 +49,7 @@ describe('HadronIdSystem', function () { const request = server.requests[0]; expect(request.url).to.eq('https://hadronid.publync.com?partner_id=0&_it=prebid'); request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ hadronId: 'testHadronId1' })); - expect(callbackSpy.lastCall.lastArg).to.deep.equal({hadronId: 'testHadronId1'}); + expect(callbackSpy.lastCall.lastArg).to.deep.equal({ id: { hadronId: 'testHadronId1' } }); }); }); }); diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index 99e0681e547..5403d842e02 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -897,7 +897,7 @@ describe('User ID', function () { storage: {name: 'intentIqId', type: 'cookie'} }, { name: 'hadronId', - storage: {name: 'hadronId', type: 'cookie'} + storage: {name: 'hadronId', type: 'html5'} }, { name: 'zeotapIdPlus' }, { @@ -1872,8 +1872,8 @@ describe('User ID', function () { it('test hook from hadronId html5', function (done) { // simulate existing browser local storage values - localStorage.setItem('hadronId', JSON.stringify({'hadronId': 'random-ls-identifier'})); - localStorage.setItem('hadronId_exp', ''); + localStorage.setItem('hadronId', JSON.stringify({'hadronId': 'testHadronId1'})); + localStorage.setItem('hadronId_exp', (new Date(Date.now() + 5000)).toUTCString()); init(config); setSubmoduleRegistry([hadronIdSubmodule]); @@ -1883,15 +1883,15 @@ describe('User ID', function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.hadronId'); - expect(bid.userId.hadronId).to.equal('random-ls-identifier'); + expect(bid.userId.hadronId).to.equal('testHadronId1'); expect(bid.userIdAsEids[0]).to.deep.equal({ source: 'audigent.com', - uids: [{id: 'random-ls-identifier', atype: 1}] + uids: [{id: 'testHadronId1', atype: 1}] }); }); }); localStorage.removeItem('hadronId'); - localStorage.removeItem('hadronId_exp', ''); + localStorage.removeItem('hadronId_exp'); done(); }, {adUnits}); }); @@ -2125,7 +2125,9 @@ describe('User ID', function () { coreStorage.setCookie('netId', JSON.stringify({'netId': 'testnetId'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('intentIqId', 'testintentIqId', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('IDP', btoa(JSON.stringify('zeotapId')), (new Date(Date.now() + 5000).toUTCString())); - coreStorage.setCookie('hadronId', JSON.stringify({'hadronId': 'testHadronId'}), (new Date(Date.now() + 5000).toUTCString())); + // hadronId only supports localStorage + localStorage.setItem('hadronId', JSON.stringify({'hadronId': 'testHadronId1'})); + localStorage.setItem('hadronId_exp', (new Date(Date.now() + 5000)).toUTCString()); coreStorage.setCookie('storage_criteo', JSON.stringify({'criteoId': 'test_bidid'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('mwol', JSON.stringify({eid: 'XX-YY-ZZ-123'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('uid2id', 'Sample_AD_Token', (new Date(Date.now() + 5000).toUTCString())); @@ -2149,7 +2151,7 @@ describe('User ID', function () { ['netId', 'netId', 'cookie'], ['intentIqId', 'intentIqId', 'cookie'], ['zeotapIdPlus', 'IDP', 'cookie'], - ['hadronId', 'hadronId', 'cookie'], + ['hadronId', 'hadronId', 'html5'], ['criteo', 'storage_criteo', 'cookie'], ['mwOpenLinkId', 'mwol', 'cookie'], ['tapadId', 'tapad_id', 'cookie'], @@ -2192,7 +2194,7 @@ describe('User ID', function () { expect(bid.userId.IDP).to.equal('zeotapId'); // also check that hadronId id was copied to bid expect(bid).to.have.deep.nested.property('userId.hadronId'); - expect(bid.userId.hadronId).to.equal('testHadronId'); + expect(bid.userId.hadronId).to.equal('testHadronId1'); // also check that criteo id was copied to bid expect(bid).to.have.deep.nested.property('userId.criteoId'); expect(bid.userId.criteoId).to.equal('test_bidid'); @@ -2231,7 +2233,8 @@ describe('User ID', function () { coreStorage.setCookie('netId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('intentIqId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); - coreStorage.setCookie('hadronId', '', EXPIRED_COOKIE_DATE); + localStorage.removeItem('hadronId'); + localStorage.removeItem('hadronId_exp'); coreStorage.setCookie('storage_criteo', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('mwol', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('uid2id', '', EXPIRED_COOKIE_DATE); @@ -2284,7 +2287,8 @@ describe('User ID', function () { coreStorage.setCookie('netId', JSON.stringify({'netId': 'testnetId'}), new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('intentIqId', 'testintentIqId', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('IDP', btoa(JSON.stringify('zeotapId')), (new Date(Date.now() + 5000).toUTCString())); - coreStorage.setCookie('hadronId', JSON.stringify({'hadronId': 'testHadronId'}), (new Date(Date.now() + 5000).toUTCString())); + localStorage.setItem('hadronId', JSON.stringify({'hadronId': 'testHadronId1'})); + localStorage.setItem('hadronId_exp', (new Date(Date.now() + 5000)).toUTCString()); coreStorage.setCookie('admixerId', 'testadmixerId', new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('deepintentId', 'testdeepintentId', new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('MOCKID', JSON.stringify({'MOCKID': '123456778'}), new Date(Date.now() + 5000).toUTCString()); @@ -2320,7 +2324,7 @@ describe('User ID', function () { }, { name: 'zeotapIdPlus' }, { - name: 'hadronId', storage: {name: 'hadronId', type: 'cookie'} + name: 'hadronId', storage: {name: 'hadronId', type: 'html5'} }, { name: 'admixerId', storage: {name: 'admixerId', type: 'cookie'} }, { @@ -2388,7 +2392,7 @@ describe('User ID', function () { expect(bid.userId.IDP).to.equal('zeotapId'); // also check that hadronId id data was copied to bid expect(bid).to.have.deep.nested.property('userId.hadronId'); - expect(bid.userId.hadronId).to.equal('testHadronId'); + expect(bid.userId.hadronId).to.equal('testHadronId1'); expect(bid.userId.uid2).to.deep.equal({ id: 'Sample_AD_Token' }); @@ -2420,7 +2424,8 @@ describe('User ID', function () { coreStorage.setCookie('netId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('intentIqId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); - coreStorage.setCookie('hadronId', '', EXPIRED_COOKIE_DATE); + localStorage.removeItem('hadronId'); + localStorage.removeItem('hadronId_exp'); coreStorage.setCookie('dmdId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('admixerId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('deepintentId', '', EXPIRED_COOKIE_DATE); From 5787552f19a06c3f777da0f0531e4032c501d3ed Mon Sep 17 00:00:00 2001 From: Mark Kuhar Date: Thu, 26 Jan 2023 20:40:58 +0100 Subject: [PATCH 298/367] Outbrain Bid Adapter: added video support (#9405) * add video support * add more video props --- modules/outbrainBidAdapter.js | 109 +++++++++- test/spec/modules/outbrainBidAdapter_spec.js | 200 +++++++++++++++++-- 2 files changed, 285 insertions(+), 24 deletions(-) diff --git a/modules/outbrainBidAdapter.js b/modules/outbrainBidAdapter.js index 3db1da0d689..6bcbc6a1cba 100644 --- a/modules/outbrainBidAdapter.js +++ b/modules/outbrainBidAdapter.js @@ -4,11 +4,13 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { NATIVE, BANNER } from '../src/mediaTypes.js'; -import { deepAccess, deepSetValue, replaceAuctionPrice, _map, isArray } from '../src/utils.js'; +import { NATIVE, BANNER, VIDEO } from '../src/mediaTypes.js'; +import { OUTSTREAM } from '../src/video.js'; +import { deepAccess, deepSetValue, replaceAuctionPrice, _map, isArray, logWarn } from '../src/utils.js'; import { ajax } from '../src/ajax.js'; import { config } from '../src/config.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import { Renderer } from '../src/Renderer.js'; const BIDDER_CODE = 'outbrain'; const GVLID = 164; @@ -22,11 +24,12 @@ const NATIVE_PARAMS = { body: { id: 4, name: 'data', type: 2 }, cta: { id: 1, type: 12, name: 'data' } }; +const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; export const spec = { code: BIDDER_CODE, gvlid: GVLID, - supportedMediaTypes: [ NATIVE, BANNER ], + supportedMediaTypes: [ NATIVE, BANNER, VIDEO ], isBidRequestValid: (bid) => { if (typeof bid.params !== 'object') { return false; @@ -50,7 +53,7 @@ export const spec = { return ( !!config.getConfig('outbrain.bidderUrl') && - !!(bid.nativeParams || bid.sizes) + (!!(bid.nativeParams || bid.sizes) || isValidVideoRequest(bid)) ); }, buildRequests: (validBidRequests, bidderRequest) => { @@ -85,6 +88,8 @@ export const spec = { assets: getNativeAssets(bid) }) } + } else if (isVideoRequest(bid)) { + imp.video = getVideoAsset(bid); } else { imp.banner = { format: transformSizes(bid.sizes) @@ -163,7 +168,12 @@ export const spec = { return bids.map((bid, id) => { const bidResponse = bidResponses[id]; if (bidResponse) { - const type = bid.nativeParams ? NATIVE : BANNER; + let type = BANNER; + if (bid.nativeParams) { + type = NATIVE; + } else if (isVideoRequest(bid)) { + type = VIDEO; + } const bidObject = { requestId: bid.bidId, cpm: bidResponse.price, @@ -176,10 +186,16 @@ export const spec = { }; if (type === NATIVE) { bidObject.native = parseNative(bidResponse); - } else { + } else if (type === BANNER) { bidObject.ad = bidResponse.adm; bidObject.width = bidResponse.w; bidObject.height = bidResponse.h; + } else if (type === VIDEO) { + bidObject.vastXml = bidResponse.adm; + const videoContext = deepAccess(bid, 'mediaTypes.video.context'); + if (videoContext === OUTSTREAM) { + bidObject.renderer = createRenderer(bid); + } } bidObject.meta = {}; if (bidResponse.adomain && bidResponse.adomain.length > 0) { @@ -304,6 +320,27 @@ function getNativeAssets(bid) { }).filter(Boolean); } +function getVideoAsset(bid) { + const sizes = flatten(bid.mediaTypes.video.playerSize); + return { + w: parseInt(sizes[0], 10), + h: parseInt(sizes[1], 10), + protocols: bid.mediaTypes.video.protocols, + playbackmethod: bid.mediaTypes.video.playbackmethod, + mimes: bid.mediaTypes.video.mimes, + skip: bid.mediaTypes.video.skip, + delivery: bid.mediaTypes.video.delivery, + api: bid.mediaTypes.video.api, + minbitrate: bid.mediaTypes.video.minbitrate, + maxbitrate: bid.mediaTypes.video.maxbitrate, + minduration: bid.mediaTypes.video.minduration, + maxduration: bid.mediaTypes.video.maxduration, + startdelay: bid.mediaTypes.video.startdelay, + placement: bid.mediaTypes.video.placement, + linearity: bid.mediaTypes.video.linearity + }; +} + /* Turn bid request sizes into ut-compatible format */ function transformSizes(requestSizes) { if (!isArray(requestSizes)) { @@ -338,3 +375,63 @@ function _getFloor(bid, type) { } return null; } + +function isVideoRequest(bid) { + return bid.mediaType === 'video' || !!deepAccess(bid, 'mediaTypes.video'); +} + +function createRenderer(bid) { + let config = {}; + let playerUrl = OUTSTREAM_RENDERER_URL; + let render = function (bid) { + bid.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + sizes: bid.sizes, + targetId: bid.adUnitCode, + adResponse: { content: bid.vastXml } + }); + }); + }; + + let externalRenderer = deepAccess(bid, 'mediaTypes.video.renderer'); + if (!externalRenderer) { + externalRenderer = deepAccess(bid, 'renderer'); + } + + if (externalRenderer) { + config = externalRenderer.options; + playerUrl = externalRenderer.url; + render = externalRenderer.render; + } + + const renderer = Renderer.install({ + id: bid.adUnitCode, + url: playerUrl, + config: config, + adUnitCode: bid.adUnitCode, + loaded: false + }); + try { + renderer.setRender(render); + } catch (err) { + logWarn('Prebid Error calling setRender on renderer', err); + } + return renderer; +} + +function isValidVideoRequest(bid) { + const videoAdUnit = deepAccess(bid, 'mediaTypes.video') + if (!videoAdUnit) { + return false; + } + + if (!Array.isArray(videoAdUnit.playerSize)) { + return false; + } + + if (videoAdUnit.context == '') { + return false; + } + + return true; +} diff --git a/test/spec/modules/outbrainBidAdapter_spec.js b/test/spec/modules/outbrainBidAdapter_spec.js index 5d7bebc1de1..f5ce00ed8df 100644 --- a/test/spec/modules/outbrainBidAdapter_spec.js +++ b/test/spec/modules/outbrainBidAdapter_spec.js @@ -1,7 +1,7 @@ -import {expect} from 'chai'; -import {spec} from 'modules/outbrainBidAdapter.js'; -import {config} from 'src/config.js'; -import {server} from 'test/mocks/xhr'; +import { expect } from 'chai'; +import { spec } from 'modules/outbrainBidAdapter.js'; +import { config } from 'src/config.js'; +import { server } from 'test/mocks/xhr'; import { createEidsArray } from 'modules/userId/eids.js'; describe('Outbrain Adapter', function () { @@ -45,6 +45,26 @@ describe('Outbrain Adapter', function () { ] } + const videoBidRequestParams = { + mediaTypes: { + video: { + playerSize: [[640, 480]], + mimes: ['video/mp4'], + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [1], + skip: 1, + api: [2], + minbitrate: 1000, + maxbitrate: 3000, + minduration: 3, + maxduration: 10, + startdelay: 2, + placement: 4, + linearity: 1 + } + } + } + describe('isBidRequestValid', function () { before(() => { config.setConfig({ @@ -93,6 +113,34 @@ describe('Outbrain Adapter', function () { } expect(spec.isBidRequestValid(bid)).to.equal(true) }) + it('should succeed when bid contains video', function () { + const bid = { + bidder: 'outbrain', + params: { + publisher: { + id: 'publisher-id', + } + }, + ...videoBidRequestParams, + } + expect(spec.isBidRequestValid(bid)).to.equal(true) + }) + it('should fail when bid contains insufficient video information', function () { + const bid = { + bidder: 'outbrain', + params: { + publisher: { + id: 'publisher-id', + } + }, + mediaTypes: { + video: { + context: 'outstream' + } + }, + } + expect(spec.isBidRequestValid(bid)).to.equal(false) + }) it('should fail if publisher id is not set', function () { const bid = { bidder: 'outbrain', @@ -298,6 +346,61 @@ describe('Outbrain Adapter', function () { expect(res.data).to.deep.equal(JSON.stringify(expectedData)) }) + it('should build video request', function () { + const bidRequest = { + ...commonBidRequest, + ...videoBidRequestParams, + } + const expectedData = { + site: { + page: 'https://example.com/', + publisher: { + id: 'publisher-id' + } + }, + device: { + ua: navigator.userAgent + }, + source: { + fd: 1 + }, + cur: [ + 'USD' + ], + imp: [ + { + id: '1', + video: { + w: 640, + h: 480, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + playbackmethod: [1], + mimes: ['video/mp4'], + skip: 1, + api: [2], + minbitrate: 1000, + maxbitrate: 3000, + minduration: 3, + maxduration: 10, + startdelay: 2, + placement: 4, + linearity: 1 + } + } + ], + ext: { + prebid: { + channel: { + name: 'pbjs', version: '$prebid.version$' + } + } + } + } + const res = spec.buildRequests([bidRequest], commonBidderRequest) + expect(res.url).to.equal('https://bidder-url.com') + expect(res.data).to.deep.equal(JSON.stringify(expectedData)) + }) + it('should pass optional parameters in request', function () { const bidRequest = { ...commonBidRequest, @@ -390,7 +493,7 @@ describe('Outbrain Adapter', function () { ...commonBidRequest, ...nativeBidRequestParams, } - config.setConfig({coppa: true}) + config.setConfig({ coppa: true }) const res = spec.buildRequests([bidRequest], commonBidderRequest) const resData = JSON.parse(res.data) @@ -412,7 +515,7 @@ describe('Outbrain Adapter', function () { let res = spec.buildRequests([bidRequest], commonBidderRequest); const resData = JSON.parse(res.data) expect(resData.user.ext.eids).to.deep.equal([ - {source: 'liveramp.com', uids: [{id: 'id-value', atype: 3}]} + { source: 'liveramp.com', uids: [{ id: 'id-value', atype: 3 }] } ]); }); @@ -421,7 +524,7 @@ describe('Outbrain Adapter', function () { ...commonBidRequest, ...nativeBidRequestParams, } - bidRequest.getFloor = function() { + bidRequest.getFloor = function () { return { currency: 'USD', floor: 1.23, @@ -619,6 +722,67 @@ describe('Outbrain Adapter', function () { const res = spec.interpretResponse(serverResponse, request) expect(res).to.deep.equal(expectedRes) }); + + it('should interpret video response', function () { + const serverResponse = { + body: { + id: '123', + seatbid: [ + { + bid: [ + { + id: '111', + impid: '1', + price: 1.1, + adm: '\u003cVAST version="3.0"\u003e\u003cAd\u003e\u003cInLine\u003e\u003cAdSystem\u003ezemanta\u003c/AdSystem\u003e\u003cAdTitle\u003e1\u003c/AdTitle\u003e\u003cImpression\u003ehttp://win.com\u003c/Impression\u003e\u003cImpression\u003ehttp://example.com/imptracker\u003c/Impression\u003e\u003cCreatives\u003e\u003cCreative\u003e\u003cLinear\u003e\u003cDuration\u003e00:00:25\u003c/Duration\u003e\u003cTrackingEvents\u003e\u003cTracking event="start"\u003ehttp://example.com/start\u003c/Tracking\u003e\u003cTracking event="progress" offset="00:00:03"\u003ehttp://example.com/p3s\u003c/Tracking\u003e\u003c/TrackingEvents\u003e\u003cVideoClicks\u003e\u003cClickThrough\u003ehttp://link.com\u003c/ClickThrough\u003e\u003c/VideoClicks\u003e\u003cMediaFiles\u003e\u003cMediaFile delivery="progressive" type="video/mp4" bitrate="700" width="640" height="360"\u003ehttps://example.com/123_360p.mp4\u003c/MediaFile\u003e\u003c/MediaFiles\u003e\u003c/Linear\u003e\u003c/Creative\u003e\u003c/Creatives\u003e\u003c/InLine\u003e\u003c/Ad\u003e\u003c/VAST\u003e', + adid: '100', + cid: '5', + crid: '29998660', + cat: ['cat-1'], + adomain: [ + 'example.com' + ], + nurl: 'http://example.com/win/${AUCTION_PRICE}' + } + ], + seat: '100', + group: 1 + } + ], + bidid: '456', + cur: 'USD' + } + } + const request = { + bids: [ + { + ...commonBidRequest, + ...videoBidRequestParams + } + ] + } + const expectedRes = [ + { + requestId: request.bids[0].bidId, + cpm: 1.1, + creativeId: '29998660', + ttl: 360, + netRevenue: false, + currency: 'USD', + mediaType: 'video', + nurl: 'http://example.com/win/${AUCTION_PRICE}', + vastXml: 'zemanta1http://win.comhttp://example.com/imptracker00:00:25http://example.com/starthttp://example.com/p3shttp://link.comhttps://example.com/123_360p.mp4', + meta: { + 'advertiserDomains': [ + 'example.com' + ] + }, + } + ] + + const res = spec.interpretResponse(serverResponse, request) + expect(res).to.deep.equal(expectedRes) + }); }) }) @@ -637,41 +801,41 @@ describe('Outbrain Adapter', function () { }) it('should return user sync if pixel enabled with outbrain config', function () { - const ret = spec.getUserSyncs({pixelEnabled: true}) - expect(ret).to.deep.equal([{type: 'image', url: usersyncUrl}]) + const ret = spec.getUserSyncs({ pixelEnabled: true }) + expect(ret).to.deep.equal([{ type: 'image', url: usersyncUrl }]) }) it('should not return user sync if pixel disabled', function () { - const ret = spec.getUserSyncs({pixelEnabled: false}) + const ret = spec.getUserSyncs({ pixelEnabled: false }) expect(ret).to.be.an('array').that.is.empty }) it('should not return user sync if url is not set', function () { config.resetConfig() - const ret = spec.getUserSyncs({pixelEnabled: true}) + const ret = spec.getUserSyncs({ pixelEnabled: true }) expect(ret).to.be.an('array').that.is.empty }) - it('should pass GDPR consent', function() { - expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, undefined)).to.deep.equal([{ + it('should pass GDPR consent', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { gdprApplies: true, consentString: 'foo' }, undefined)).to.deep.equal([{ type: 'image', url: `${usersyncUrl}?gdpr=1&gdpr_consent=foo` }]); - expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: false, consentString: 'foo'}, undefined)).to.deep.equal([{ + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { gdprApplies: false, consentString: 'foo' }, undefined)).to.deep.equal([{ type: 'image', url: `${usersyncUrl}?gdpr=0&gdpr_consent=foo` }]); - expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: undefined}, undefined)).to.deep.equal([{ + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { gdprApplies: true, consentString: undefined }, undefined)).to.deep.equal([{ type: 'image', url: `${usersyncUrl}?gdpr=1&gdpr_consent=` }]); }); - it('should pass US consent', function() { + it('should pass US consent', function () { expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, '1NYN')).to.deep.equal([{ type: 'image', url: `${usersyncUrl}?us_privacy=1NYN` }]); }); - it('should pass GDPR and US consent', function() { - expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, '1NYN')).to.deep.equal([{ + it('should pass GDPR and US consent', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { gdprApplies: true, consentString: 'foo' }, '1NYN')).to.deep.equal([{ type: 'image', url: `${usersyncUrl}?gdpr=1&gdpr_consent=foo&us_privacy=1NYN` }]); }); From 9a83c0307f7d18e5f6a495c4681e098909eb9d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Sok=C3=B3=C5=82?= <88041828+smart-adserver@users.noreply.github.com> Date: Thu, 26 Jan 2023 21:04:47 +0100 Subject: [PATCH 299/367] Smartadserver Bid Adapter: support floors per media type (#9437) * Smartadserver Bid Adapter: Add support for SDA user and site * Smartadserver Bid Adapter: Fix SDA support getConfig and add to unit testing * support floors per media type * Rework payloads enriching Co-authored-by: Meven Courouble --- modules/smartadserverBidAdapter.js | 48 ++++----- .../modules/smartadserverBidAdapter_spec.js | 97 ++++++++++++++++++- 2 files changed, 116 insertions(+), 29 deletions(-) diff --git a/modules/smartadserverBidAdapter.js b/modules/smartadserverBidAdapter.js index 6ff0e592542..719d621b056 100644 --- a/modules/smartadserverBidAdapter.js +++ b/modules/smartadserverBidAdapter.js @@ -13,6 +13,7 @@ export const spec = { gvlid: GVL_ID, aliases: ['smart'], // short code supportedMediaTypes: [BANNER, VIDEO], + /** * Determines whether or not the given bid request is valid. * @@ -131,7 +132,6 @@ export const spec = { */ buildRequests: function (validBidRequests, bidderRequest) { // use bidderRequest.bids[] to get bidder-dependent request info - const adServerCurrency = config.getConfig('currency.adServerCurrency'); const sellerDefinedAudience = deepAccess(bidderRequest, 'ortb2.user.data', config.getAnyConfig('ortb2.user.data')); const sellerDefinedContext = deepAccess(bidderRequest, 'ortb2.site.content.data', config.getAnyConfig('ortb2.site.content.data')); @@ -144,7 +144,6 @@ export const spec = { pageid: bid.params.pageId, formatid: bid.params.formatId, currencyCode: adServerCurrency, - bidfloor: bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency), 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, @@ -175,24 +174,28 @@ export const spec = { payload.us_privacy = bidderRequest.uspConsent; } - const videoMediaType = deepAccess(bid, 'mediaTypes.video'); const bannerMediaType = deepAccess(bid, 'mediaTypes.banner'); - const isAdUnitContainingVideo = videoMediaType && (videoMediaType.context === 'instream' || videoMediaType.context === 'outstream'); - if (!isAdUnitContainingVideo && bannerMediaType) { - payload.sizes = spec.adaptBannerSizes(bannerMediaType.sizes); - bidRequests.push(spec.createServerRequest(payload, bid.params.domain)); - } else if (isAdUnitContainingVideo && !bannerMediaType) { - spec.fillPayloadForVideoBidRequest(payload, videoMediaType, bid.params.video); - bidRequests.push(spec.createServerRequest(payload, bid.params.domain)); - } else if (isAdUnitContainingVideo && bannerMediaType) { - // If there are video and banner media types in the ad unit, we clone the payload - // to create a specific one for video. - let videoPayload = deepClone(payload); + const videoMediaType = deepAccess(bid, 'mediaTypes.video'); + const isSupportedVideoContext = videoMediaType && (videoMediaType.context === 'instream' || videoMediaType.context === 'outstream'); - spec.fillPayloadForVideoBidRequest(videoPayload, videoMediaType, bid.params.video); - bidRequests.push(spec.createServerRequest(videoPayload, bid.params.domain)); + if (bannerMediaType || isSupportedVideoContext) { + let type; + if (bannerMediaType) { + type = BANNER; + payload.sizes = spec.adaptBannerSizes(bannerMediaType.sizes); - payload.sizes = spec.adaptBannerSizes(bannerMediaType.sizes); + if (isSupportedVideoContext) { + let videoPayload = deepClone(payload); + spec.fillPayloadForVideoBidRequest(videoPayload, videoMediaType, bid.params.video); + videoPayload.bidfloor = bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, VIDEO); + bidRequests.push(spec.createServerRequest(videoPayload, bid.params.domain)); + } + } else { + type = VIDEO; + spec.fillPayloadForVideoBidRequest(payload, videoMediaType, bid.params.video); + } + + payload.bidfloor = bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, type); bidRequests.push(spec.createServerRequest(payload, bid.params.domain)); } else { bidRequests.push({}); @@ -253,24 +256,21 @@ export const spec = { * * @param {object} bid Bid request object * @param {string} currency Ad server currency + * @param {string} mediaType Bid media type * @return {number} Floor price */ - getBidFloor: function (bid, currency) { + getBidFloor: function (bid, currency, mediaType) { if (!isFn(bid.getFloor)) { return DEFAULT_FLOOR; } const floor = bid.getFloor({ currency: currency || 'USD', - mediaType: '*', + mediaType, size: '*' }); - if (isPlainObject(floor) && !isNaN(floor.floor)) { - return floor.floor; - } - - return DEFAULT_FLOOR; + return isPlainObject(floor) && !isNaN(floor.floor) ? floor.floor : DEFAULT_FLOOR; }, /** diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js index db61983c9c9..4dacb356894 100644 --- a/test/spec/modules/smartadserverBidAdapter_spec.js +++ b/test/spec/modules/smartadserverBidAdapter_spec.js @@ -1,4 +1,5 @@ import { expect } from 'chai'; +import { BANNER, VIDEO } from 'src/mediaTypes.js'; import { config } from 'src/config.js'; import { spec } from 'modules/smartadserverBidAdapter.js'; @@ -394,7 +395,6 @@ describe('Smart bid adapter tests', function () { afterEach(function () { config.setConfig({ ortb2: undefined }); config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); it('Verify build request with GDPR', function () { @@ -446,7 +446,6 @@ 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 () { @@ -475,7 +474,6 @@ describe('Smart bid adapter tests', function () { describe('Instream video tests', function () { afterEach(function () { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); const INSTREAM_DEFAULT_PARAMS = [{ @@ -746,7 +744,6 @@ describe('Smart bid adapter tests', function () { describe('Outstream video tests', function () { afterEach(function () { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); const OUTSTREAM_DEFAULT_PARAMS = [{ @@ -1055,6 +1052,17 @@ describe('Smart bid adapter tests', function () { }); describe('Floors module', function () { + const getFloor = (bid) => { + switch (bid.mediaType) { + case BANNER: + return { currency: 'USD', floor: 1.93 }; + case VIDEO: + return { currency: 'USD', floor: 2.72 }; + default: + return {}; + } + }; + it('should include floor from bid params', function() { const bidRequest = JSON.parse((spec.buildRequests(DEFAULT_PARAMS))[0].data); expect(bidRequest.bidfloor).to.deep.equal(DEFAULT_PARAMS[0].params.bidfloor); @@ -1094,12 +1102,91 @@ describe('Smart bid adapter tests', function () { const floor = spec.getBidFloor(bidRequest, null); expect(floor).to.deep.equal(0); }); + + it('should take floor from bidder params over ad unit', function() { + const bidRequest = [{ + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + getFloor, + params: { siteId: 1234, pageId: 678, formatId: 73, bidfloor: 1.25 } + }]; + + const request = spec.buildRequests(bidRequest); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('bidfloor').and.to.equal(1.25); + }); + + it('should take floor from banner ad unit', function() { + const bidRequest = [{ + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + getFloor, + params: { siteId: 1234, pageId: 678, formatId: 73 } + }]; + + const request = spec.buildRequests(bidRequest); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('bidfloor').and.to.equal(1.93); + }); + + it('should take floor from video ad unit', function() { + const bidRequest = [{ + mediaTypes: { + video: { + context: 'outstream', + playerSize: [[640, 480]] + } + }, + getFloor, + params: { siteId: 1234, pageId: 678, formatId: 73 } + }]; + + const request = spec.buildRequests(bidRequest); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('bidfloor').and.to.equal(2.72); + }); + + it('should take floor from multiple media type ad unit', function() { + const bidRequest = [{ + mediaTypes: { + banner: { + sizes: [[300, 600]] + }, + video: { + context: 'outstream', + playerSize: [[640, 480]] + } + }, + getFloor, + params: { siteId: 1234, pageId: 678, formatId: 73 } + }]; + + const requests = spec.buildRequests(bidRequest); + expect(requests).to.have.lengthOf(2); + + const requestContents = requests.map(r => JSON.parse(r.data)); + const videoRequest = requestContents.filter(r => r.videoData)[0]; + expect(videoRequest).to.not.equal(null).and.to.not.be.undefined; + expect(videoRequest).to.have.property('bidfloor').and.to.equal(2.72); + + const bannerRequest = requestContents.filter(r => !r.videoData)[0]; + expect(bannerRequest).to.not.equal(null).and.to.not.be.undefined; + expect(bannerRequest).to.have.property('bidfloor').and.to.equal(1.93); + }); }); describe('Verify bid requests with multiple mediaTypes', function () { afterEach(function () { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); var DEFAULT_PARAMS_MULTIPLE_MEDIA_TYPES = [{ From f520803a19f0c62aacb82847e757d52d65250345 Mon Sep 17 00:00:00 2001 From: preved-medved Date: Fri, 27 Jan 2023 11:24:35 +0000 Subject: [PATCH 300/367] Smartytech Bid Adapter: Add video format (#9388) * Add new bid adapter for company smartytech * change domain to prod * update unit tests * remove unused code * remove unused code * add video type * update documentation --- modules/smartytechBidAdapter.js | 77 +++++++- modules/smartytechBidAdapter.md | 77 ++++---- .../spec/modules/smartytechBidAdapter_spec.js | 186 ++++++++++++++++-- 3 files changed, 283 insertions(+), 57 deletions(-) diff --git a/modules/smartytechBidAdapter.js b/modules/smartytechBidAdapter.js index 231ca315de8..9f275a761c7 100644 --- a/modules/smartytechBidAdapter.js +++ b/modules/smartytechBidAdapter.js @@ -1,29 +1,77 @@ +import {buildUrl, deepAccess} from '../src/utils.js' +import { BANNER, VIDEO } from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {buildUrl} from '../src/utils.js' const BIDDER_CODE = 'smartytech'; export const ENDPOINT_PROTOCOL = 'https'; export const ENDPOINT_DOMAIN = 'server.smartytech.io'; -export const ENDPOINT_PATH = '/hb/bidder'; +export const ENDPOINT_PATH = '/hb/v2/bidder'; export const spec = { + supportedMediaTypes: [ BANNER, VIDEO ], code: BIDDER_CODE, isBidRequestValid: function (bidRequest) { - return !!parseInt(bidRequest.params.endpointId); + return ( + !!parseInt(bidRequest.params.endpointId) && + spec._validateBanner(bidRequest) && + spec._validateVideo(bidRequest) + ); + }, + + _validateBanner: function(bidRequest) { + const bannerAdUnit = deepAccess(bidRequest, 'mediaTypes.banner'); + + if (bannerAdUnit === undefined) { + return true; + } + + if (!Array.isArray(bannerAdUnit.sizes)) { + return false; + } + + return true; + }, + + _validateVideo: function(bidRequest) { + const videoAdUnit = deepAccess(bidRequest, 'mediaTypes.video'); + + if (videoAdUnit === undefined) { + return true; + } + + if (!Array.isArray(videoAdUnit.playerSize)) { + return false; + } + + if (!videoAdUnit.context) { + return false; + } + + return true; }, buildRequests: function (validBidRequests, bidderRequest) { const referer = bidderRequest?.refererInfo?.page || window.location.href; const bidRequests = validBidRequests.map((validBidRequest) => { - return { + let video = deepAccess(validBidRequest, 'mediaTypes.video', false); + let banner = deepAccess(validBidRequest, 'mediaTypes.banner', false); + + let oneRequest = { endpointId: validBidRequest.params.endpointId, adUnitCode: validBidRequest.adUnitCode, - sizes: validBidRequest.sizes, - bidId: validBidRequest.bidId, - referer: referer + referer: referer, + bidId: validBidRequest.bidId }; + + if (video) { + oneRequest.video = video; + } else if (banner) { + oneRequest.banner = banner; + } + + return oneRequest }); let adPartnerRequestUrl = buildUrl({ @@ -55,12 +103,14 @@ export const spec = { bid: validBids.find(b => b.adUnitCode === key), response: responseBody[key] } - }).map(item => spec.adResponse(item.bid.bidId, item.response)); + }).map(item => spec._adResponse(item.bid, item.response)); }, - adResponse: function (requestId, response) { + _adResponse: function (request, response) { const bidObject = { - requestId, + requestId: request.bidId, + adUnitCode: request.adUnitCode, + bidderCode: BIDDER_CODE, ad: response.ad, cpm: response.cpm, width: response.width, @@ -69,7 +119,14 @@ export const spec = { creativeId: response.creativeId, netRevenue: true, currency: response.currency, + mediaType: BANNER } + + if (response.mediaType === VIDEO) { + bidObject.vastXml = response.ad; + bidObject.mediaType = VIDEO; + } + return bidObject; }, diff --git a/modules/smartytechBidAdapter.md b/modules/smartytechBidAdapter.md index dbfc2833c78..9df57ddbde7 100644 --- a/modules/smartytechBidAdapter.md +++ b/modules/smartytechBidAdapter.md @@ -1,44 +1,55 @@ # Overview -Module Name: SmartyTech Bidder Adapter - -Module Type: Bidder Adapter - +``` +Module Name: SmartyTech Bid Adapter +Module Type: Bidder Adapter Maintainer: info@adpartner.pro +``` # Description -You can use this adapter to get a bid from smartytech.io. +Connects to SmartyTech's exchange for bids. -About us : https://smartytech.io +SmartyTech bid adapter supports Banner and Video -# Test Parameters +# Sample Ad Unit: For Publishers +## Sample Banner Ad Unit +``` +var adUnits = [{ + code: '/123123123/prebidjs-banner', + mediaTypes: { + banner: { + sizes: [ + [300, 301], + [300, 250] + ] + } + }, + bids: [{ + bidder: 'smartytech', + params: { + endpointId: 12 + } + }] +}]; +``` -```javascript - var adUnits = [ - { - code: 'div-smartytech-example', - sizes: [[300, 250]], - bids: [ - { - bidder: "smartytech", - params: { - endpointId: 14 - } - } - ] +## Sample Video Ad Unit +``` +var videoAdUnit = { + code: '/123123123/video-vast-banner', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480], + mimes: ['video/mp4'], + } }, - { - code: 'div-smartytech-example-2', - sizes: [[300, 250]], - bids: [ - { - bidder: "smartytech", - params: { - endpointId: 14 - } - } - ] - } -]; + bids: [{ + bidder: 'smartytech', + params: { + endpointId: 12 + } + }] +}; ``` diff --git a/test/spec/modules/smartytechBidAdapter_spec.js b/test/spec/modules/smartytechBidAdapter_spec.js index 78503d7a6f0..b41b0280235 100644 --- a/test/spec/modules/smartytechBidAdapter_spec.js +++ b/test/spec/modules/smartytechBidAdapter_spec.js @@ -19,20 +19,116 @@ describe('SmartyTechDSPAdapter: inherited functions', function () { describe('SmartyTechDSPAdapter: isBidRequestValid', function () { it('Invalid bid request. Should return false', function () { - const invalidBidFixture = { + const bidFixture = { params: { use_id: 13144375 } } - expect(spec.isBidRequestValid(invalidBidFixture)).to.be.false + + expect(spec.isBidRequestValid(bidFixture)).to.be.false }); it('Valid bid request. Should return true', function () { - const validBidFixture = { + const bidFixture = { params: { endpointId: 13144375 } } - expect(spec.isBidRequestValid(validBidFixture)).to.be.true + expect(spec.isBidRequestValid(bidFixture)).to.be.true + }); + + it('Invalid bid request. Check video block', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + video: {} + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + + it('Invalid bid request. Check playerSize', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + video: { + playerSize: '300x250' + } + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + + it('Invalid bid request. Check context', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + video: { + playerSize: [300, 250] + } + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + + it('Valid bid request. valid video bid', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + video: { + playerSize: [300, 250], + context: 'instream' + } + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.true + }); + + it('Invalid bid request. Check banner block', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + banner: {} + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + + it('Invalid bid request. Check banner sizes', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + banner: { + sizes: '300x250' + } + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.false + }); + + it('Valid bid request. valid banner bid', function () { + const bidFixture = { + params: { + endpointId: 1 + }, + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + } + } + expect(spec.isBidRequestValid(bidFixture)).to.be.true }); }); @@ -42,12 +138,29 @@ function mockRandomSizeArray(len) { }); } -function mockBidRequestListData(size) { +function mockBidRequestListData(mediaType, size) { return Array.apply(null, {length: size}).map((i, index) => { const id = Math.floor(Math.random() * 800) * (index + 1); + let mediaTypes; + + if (mediaType == 'video') { + mediaTypes = { + video: { + playerSize: mockRandomSizeArray(1), + context: 'instream' + }, + } + } else { + mediaTypes = { + banner: { + sizes: mockRandomSizeArray(index + 1) + } + } + } + return { adUnitCode: `adUnitCode-${id}`, - sizes: mockRandomSizeArray(index + 1), + mediaTypes: mediaTypes, bidId: `bidId-${id}`, params: { endpointId: id @@ -66,18 +179,27 @@ function mockRefererData() { function mockResponseData(requestData) { let data = {} - requestData.data.forEach((request, index) => { - const sizeArrayIndex = Math.floor(Math.random() * (request.sizes.length - 1)); const rndIndex = Math.floor(Math.random() * 800); + let width, height, mediaType; + if (request.video !== undefined) { + width = request.video.playerSize[0][0]; + height = request.video.playerSize[0][1]; + mediaType = 'video'; + } else { + width = request.banner.sizes[0][0]; + height = request.banner.sizes[0][1]; + mediaType = 'banner'; + } data[request.adUnitCode] = { ad: `ad-${rndIndex}`, - width: request.sizes[sizeArrayIndex][0], - height: request.sizes[sizeArrayIndex][1], + width: width, + height: height, creativeId: `creative-id-${index}`, cpm: Math.floor(Math.random() * 100), - currency: `UAH-${rndIndex}` + currency: `UAH-${rndIndex}`, + mediaType: mediaType }; }); return { @@ -89,7 +211,7 @@ describe('SmartyTechDSPAdapter: buildRequests', () => { let mockBidRequest; let mockReferer; beforeEach(() => { - mockBidRequest = mockBidRequestListData(8); + mockBidRequest = mockBidRequestListData('banner', 8); mockReferer = mockRefererData(); }); it('has return data', () => { @@ -108,7 +230,7 @@ describe('SmartyTechDSPAdapter: buildRequests', () => { const data = spec.buildRequests(mockBidRequest, mockReferer).data; data.forEach((request, index) => { expect(request.adUnitCode).to.be.equal(mockBidRequest[index].adUnitCode); - expect(request.sizes).to.be.equal(mockBidRequest[index].sizes); + expect(request.banner).to.be.equal(mockBidRequest[index].mediaTypes.banner); expect(request.bidId).to.be.equal(mockBidRequest[index].bidId); expect(request.endpointId).to.be.equal(mockBidRequest[index].params.endpointId); expect(request.referer).to.be.equal(mockReferer.refererInfo.page); @@ -122,7 +244,7 @@ describe('SmartyTechDSPAdapter: interpretResponse', () => { let request; let mockResponse; beforeEach(() => { - const brData = mockBidRequestListData(2); + const brData = mockBidRequestListData('banner', 2); mockReferer = mockRefererData(); request = spec.buildRequests(brData, mockReferer); mockBidRequest = { @@ -157,6 +279,42 @@ describe('SmartyTechDSPAdapter: interpretResponse', () => { expect(responseItem.requestId).to.be.equal(mockBidRequest.data[index].bidId); expect(responseItem.width).to.be.equal(mockResponse.body[keys[index]].width); expect(responseItem.height).to.be.equal(mockResponse.body[keys[index]].height); + expect(responseItem.mediaType).to.be.equal(mockResponse.body[keys[index]].mediaType); + }); + }); +}); + +describe('SmartyTechDSPAdapter: interpretResponse video', () => { + let mockBidRequest; + let mockReferer; + let request; + let mockResponse; + beforeEach(() => { + const brData = mockBidRequestListData('video', 2); + mockReferer = mockRefererData(); + request = spec.buildRequests(brData, mockReferer); + mockBidRequest = { + data: brData + } + mockResponse = mockResponseData(request); + }); + + it('interpretResponse: convert to correct data', () => { + const keys = Object.keys(mockResponse.body); + const data = spec.interpretResponse(mockResponse, mockBidRequest); + + data.forEach((responseItem, index) => { + expect(responseItem.ad).to.be.equal(mockResponse.body[keys[index]].ad); + expect(responseItem.cpm).to.be.equal(mockResponse.body[keys[index]].cpm); + expect(responseItem.creativeId).to.be.equal(mockResponse.body[keys[index]].creativeId); + expect(responseItem.currency).to.be.equal(mockResponse.body[keys[index]].currency); + expect(responseItem.netRevenue).to.be.true; + expect(responseItem.ttl).to.be.equal(60); + expect(responseItem.requestId).to.be.equal(mockBidRequest.data[index].bidId); + expect(responseItem.width).to.be.equal(mockResponse.body[keys[index]].width); + expect(responseItem.height).to.be.equal(mockResponse.body[keys[index]].height); + expect(responseItem.mediaType).to.be.equal(mockResponse.body[keys[index]].mediaType); + expect(responseItem.vastXml).to.be.equal(mockResponse.body[keys[index]].ad); }); }); }); From a0e514cf9ad882f9f8bc1675d9f88a0a638e33c3 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Fri, 27 Jan 2023 06:56:19 -0700 Subject: [PATCH 301/367] Core & priceFloors: pass bid request to `bidCpmAdjustment`; warn about invalid `adUnit.floors` definitions (#9441) * Core & priceFloors: pass `bidRequest` as third arg to `bidCpmAdjustment` * Floors: warn when adUnit.floors is not valid --- modules/priceFloors.js | 15 ++++---- src/auction.js | 13 +------ src/utils/cpm.js | 17 +++++++++ test/spec/unit/utils/cpm_spec.js | 64 ++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 src/utils/cpm.js create mode 100644 test/spec/unit/utils/cpm_spec.js diff --git a/modules/priceFloors.js b/modules/priceFloors.js index 32b3cbaa607..92aecb0ca50 100644 --- a/modules/priceFloors.js +++ b/modules/priceFloors.js @@ -28,6 +28,7 @@ import {auctionManager} from '../src/auctionManager.js'; import {IMP, PBS, registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js'; import {timedAuctionHook, timedBidResponseHook} from '../src/utils/perfMetrics.js'; import {beConvertCurrency} from '../src/utils/currency.js'; +import {adjustCpm} from '../src/utils/cpm.js'; /** * @summary This Module is intended to provide users with the ability to dynamically set and enforce price floors on a per auction basis. @@ -179,12 +180,8 @@ function generatePossibleEnumerations(arrayOfFields, delimiter) { /** * @summary If a the input bidder has a registered cpmadjustment it returns the input CPM after being adjusted */ -export function getBiddersCpmAdjustment(bidderName, inputCpm, bid, bidRequest) { - const adjustmentFunction = bidderSettings.get(bidderName, 'bidCpmAdjustment'); - if (adjustmentFunction) { - return parseFloat(adjustmentFunction(inputCpm, { ...bid, cpm: inputCpm }, bidRequest)); - } - return parseFloat(inputCpm); +export function getBiddersCpmAdjustment(inputCpm, bid, bidRequest) { + return parseFloat(adjustCpm(inputCpm, {...bid, cpm: inputCpm}, bidRequest)); } /** @@ -254,7 +251,7 @@ export function getFloor(requestParams = {currency: 'USD', mediaType: '*', size: if (inverseFunction) { floorInfo.matchingFloor = inverseFunction(floorInfo.matchingFloor, bidRequest); } else { - let cpmAdjustment = getBiddersCpmAdjustment(bidRequest.bidder, floorInfo.matchingFloor, {}, bidRequest); + let cpmAdjustment = getBiddersCpmAdjustment(floorInfo.matchingFloor, null, bidRequest); floorInfo.matchingFloor = cpmAdjustment ? calculateAdjustedFloor(floorInfo.matchingFloor, cpmAdjustment) : floorInfo.matchingFloor; } } @@ -313,6 +310,8 @@ export function getFloorDataFromAdUnits(adUnits) { // copy over the new rules into our values object Object.assign(accum.values, newRules); } + } else if (adUnit.floors != null) { + logWarn(`adUnit '${adUnit.code}' provides an invalid \`floor\` definition, it will be ignored for floor calculations`, adUnit); } return accum; }, {}); @@ -737,7 +736,7 @@ export const addBidResponseHook = timedBidResponseHook('priceFloors', function a } // ok we got the bid response cpm in our desired currency. Now we need to run the bidders CPMAdjustment function if it exists - adjustedCpm = getBiddersCpmAdjustment(bid.bidderCode, adjustedCpm, bid, matchingBidRequest); + adjustedCpm = getBiddersCpmAdjustment(adjustedCpm, bid, matchingBidRequest); // add necessary data information for analytics adapters / floor providers would possibly need addFloorDataToBid(floorData, floorInfo, bid, adjustedCpm); diff --git a/src/auction.js b/src/auction.js index 87397b0dc15..41e6fe3565b 100644 --- a/src/auction.js +++ b/src/auction.js @@ -93,6 +93,7 @@ import CONSTANTS from './constants.json'; import {GreedyPromise} from './utils/promise.js'; import {useMetrics} from './utils/perfMetrics.js'; import {createBid} from './bidfactory.js'; +import {adjustCpm} from './utils/cpm.js'; const { syncUsers } = userSync; @@ -971,17 +972,7 @@ function setKeys(keyValues, bidderSettings, custBidObj, bidReq) { } export function adjustBids(bid) { - let code = bid.bidderCode; - let bidPriceAdjusted = bid.cpm; - const bidCpmAdjustment = bidderSettings.get(code || null, 'bidCpmAdjustment'); - - if (bidCpmAdjustment && typeof bidCpmAdjustment === 'function') { - try { - bidPriceAdjusted = bidCpmAdjustment(bid.cpm, Object.assign({}, bid)); - } catch (e) { - logError('Error during bid adjustment', 'bidmanager.js', e); - } - } + let bidPriceAdjusted = adjustCpm(bid.cpm, bid); if (bidPriceAdjusted >= 0) { bid.cpm = bidPriceAdjusted; diff --git a/src/utils/cpm.js b/src/utils/cpm.js new file mode 100644 index 00000000000..07113e7c944 --- /dev/null +++ b/src/utils/cpm.js @@ -0,0 +1,17 @@ +import {auctionManager} from '../auctionManager.js'; +import {bidderSettings} from '../bidderSettings.js'; +import {logError} from '../utils.js'; + +export function adjustCpm(cpm, bidResponse, bidRequest, {index = auctionManager.index, bs = bidderSettings} = {}) { + bidRequest = bidRequest || index.getBidRequest(bidResponse); + const bidCpmAdjustment = bs.get(bidResponse?.bidderCode || bidRequest?.bidder, 'bidCpmAdjustment'); + + if (bidCpmAdjustment && typeof bidCpmAdjustment === 'function') { + try { + return bidCpmAdjustment(cpm, Object.assign({}, bidResponse), bidRequest); + } catch (e) { + logError('Error during bid adjustment', e); + } + } + return cpm; +} diff --git a/test/spec/unit/utils/cpm_spec.js b/test/spec/unit/utils/cpm_spec.js new file mode 100644 index 00000000000..9d104b04d09 --- /dev/null +++ b/test/spec/unit/utils/cpm_spec.js @@ -0,0 +1,64 @@ +import {adjustCpm} from '../../../../src/utils/cpm.js'; + +describe('adjustCpm', () => { + const bidderCode = 'mockBidder'; + let adjustmentFn, bs, index; + beforeEach(() => { + bs = { + get: sinon.stub() + } + index = { + getBidRequest: sinon.stub() + } + adjustmentFn = sinon.stub().callsFake((cpm) => cpm * 2); + }) + + it('throws when neither bidRequest nor bidResponse are provided', () => { + expect(() => adjustCpm(1)).to.throw(); + }) + + it('always provides an object as bidResponse for the adjustment fn', () => { + bs.get.callsFake(() => adjustmentFn); + adjustCpm(1, null, {bidder: bidderCode}, {index, bs}); + sinon.assert.calledWith(adjustmentFn, 1, {}); + }); + + describe('when no bidRequest is provided', () => { + Object.entries({ + 'unavailable': undefined, + 'found': {foo: 'bar'} + }).forEach(([t, req]) => { + describe(`and it is ${t} in the index`, () => { + beforeEach(() => { + bs.get.callsFake(() => adjustmentFn); + index.getBidRequest.callsFake(() => req) + }); + + it('provides it to the adjustment fn', () => { + const bidResponse = {bidderCode}; + adjustCpm(1, bidResponse, undefined, {index, bs}); + sinon.assert.calledWith(index.getBidRequest, bidResponse); + sinon.assert.calledWith(adjustmentFn, 1, bidResponse, req); + }) + }) + }) + }); + + Object.entries({ + 'bidResponse': [{bidderCode}], + 'bidRequest': [null, {bidder: bidderCode}], + }).forEach(([t, [bidResp, bidReq]]) => { + describe(`when passed ${t}`, () => { + beforeEach(() => { + bs.get.callsFake((bidder) => { if (bidder === bidderCode) return adjustmentFn }); + }); + it('retrieves the correct bidder code', () => { + expect(adjustCpm(1, bidResp, bidReq, {bs, index})).to.eql(2); + }); + it('passes them to the adjustment fn', () => { + adjustCpm(1, bidResp, bidReq, {bs, index}); + sinon.assert.calledWith(adjustmentFn, 1, bidResp == null ? sinon.match.any : bidResp, bidReq); + }); + }); + }) +}); From d56aaba3edff7094072416638d2c0fa039102614 Mon Sep 17 00:00:00 2001 From: Paulius Imbrasas <880130+CremboC@users.noreply.github.com> Date: Fri, 27 Jan 2023 21:53:17 +0000 Subject: [PATCH 302/367] Fixes potential error when reading _pssps localStorage key (#9474) --- modules/permutiveRtdProvider.js | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/modules/permutiveRtdProvider.js b/modules/permutiveRtdProvider.js index c64080f3308..305e175bf2c 100644 --- a/modules/permutiveRtdProvider.js +++ b/modules/permutiveRtdProvider.js @@ -311,16 +311,19 @@ export function isPermutiveOnPage () { * @return {Object} */ export function getSegments (maxSegs) { - const legacySegs = readSegments('_psegs').map(Number).filter(seg => seg >= 1000000).map(String) - const _ppam = readSegments('_ppam') - const _pcrprs = readSegments('_pcrprs') + const legacySegs = readSegments('_psegs', []).map(Number).filter(seg => seg >= 1000000).map(String) + const _ppam = readSegments('_ppam', []) + const _pcrprs = readSegments('_pcrprs', []) const segments = { ac: [..._pcrprs, ..._ppam, ...legacySegs], - rubicon: readSegments('_prubicons'), - appnexus: readSegments('_papns'), - gam: readSegments('_pdfps'), - ssp: readSegments('_pssps'), + rubicon: readSegments('_prubicons', []), + appnexus: readSegments('_papns', []), + gam: readSegments('_pdfps', []), + ssp: readSegments('_pssps', { + cohorts: [], + ssps: [] + }), } for (const bidder in segments) { @@ -338,15 +341,17 @@ export function getSegments (maxSegs) { /** * Gets an array of segment IDs from LocalStorage - * or returns an empty array + * or return the default value provided. + * @template A * @param {string} key - * @return {string[]|number[]} + * @param {A} defaultValue + * @return {A} */ -function readSegments (key) { +function readSegments (key, defaultValue) { try { - return JSON.parse(storage.getDataFromLocalStorage(key) || '[]') + return JSON.parse(storage.getDataFromLocalStorage(key)) || defaultValue } catch (e) { - return [] + return defaultValue } } From 2c9fc250ffb2f24c77e415a8ea80d68cdd77fa37 Mon Sep 17 00:00:00 2001 From: rishko00 <43280707+rishko00@users.noreply.github.com> Date: Mon, 30 Jan 2023 12:07:39 +0200 Subject: [PATCH 303/367] SmartyadsBidAdapter: update request params (#9472) Co-authored-by: Vasyl Rishko --- modules/smartyadsBidAdapter.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/smartyadsBidAdapter.md b/modules/smartyadsBidAdapter.md index f078d905e62..e0d6023a794 100644 --- a/modules/smartyadsBidAdapter.md +++ b/modules/smartyadsBidAdapter.md @@ -10,6 +10,15 @@ Maintainer: supply@smartyads.com Module that connects to SmartyAds' demand sources +# Parameters + +| Name | Scope | Description | Example | +| :------------ | :------- | :------------------------ | :------------------- | +| `sourceid` | required (for prebid.js) | placement ID | "0" | +| `host` | required (for prebid-server) | const value, set to "prebid" | "prebid" | +| `accountid` | required (for prebid-server) | partner ID | "1901" | +| `traffic` | optional (for prebid.js) | Configures the mediaType that should be used. Values can be banner, native or video | "banner" | + # Test Parameters ``` var adUnits = [ From aa033bdf1f5092e0083303b7cd36da94bebe9fb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jan 2023 07:38:24 -0700 Subject: [PATCH 304/367] Bump tibdex/github-app-token from 1.7.0 to 1.8.0 (#9479) Bumps [tibdex/github-app-token](https://github.com/tibdex/github-app-token) from 1.7.0 to 1.8.0. - [Release notes](https://github.com/tibdex/github-app-token/releases) - [Commits](https://github.com/tibdex/github-app-token/compare/021a2405c7f990db57f5eae5397423dcc554159c...b62528385c34dbc9f38e5f4225ac829252d1ea92) --- updated-dependencies: - dependency-name: tibdex/github-app-token dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/issue_tracker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issue_tracker.yml b/.github/workflows/issue_tracker.yml index 29082a4990a..69cf4c5fc7f 100644 --- a/.github/workflows/issue_tracker.yml +++ b/.github/workflows/issue_tracker.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Generate token id: generate_token - uses: tibdex/github-app-token@021a2405c7f990db57f5eae5397423dcc554159c + uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 with: app_id: ${{ secrets.ISSUE_APP_ID }} private_key: ${{ secrets.ISSUE_APP_PEM }} From b1de163ef0171ae2f72f2791ced3a1312601d8d4 Mon Sep 17 00:00:00 2001 From: Espen <2290914+espen-j@users.noreply.github.com> Date: Tue, 31 Jan 2023 10:21:05 +0100 Subject: [PATCH 305/367] C-Wire Bid Adapter: Code refactorings (#9446) * Reduce c-wire adapter to basic functionality (c-wire/creatives#3) * Minimize processing of bids * Add basic tests for adapter * Read cw_creative parameter from url and pass it as creativeId to the request (c-wire/creative#9) * Attach slot dimensions and maxWidth to request (c-wire/creatives#22) * Add feature flag support (c-wire/creatives#22) * Propagate cw_debug flag to ad server payload * Implement CWID (c-wire/prebid#3) * Add maxHeight CSS attribute (c-wire/creatives#22) * Update Prebid endpoint (c-wire/prebid#3) * Rename referrer to old property name * Map pageViewId to auctionId (c-wire/prebid#3) * Re-introduce pageId as required parameter (c-wire/prebid#3) * Map response body's bid.html property to bid.ad (c-wire/prebid#3) * Rename creativeId property to cwcreative in the payload (c-wire/prebid#3) * Flatten pageId and placementId into bid object (c-wire/prebid#3) * Send bid won and error events (c-wire/prebid#3) * Align cw* parameters with documentation and PBS adapter (c-wire/prebid#3) * QA Fix featureFlag check * Add refgroups from URL parameters (c-wire/prebid#3) * Inline adapter specific payload (c-wire/prebid#3) * Make pageViewId per prebid instance (c-wire/prebid#3) * Extract cwire extensions into own method (c-wire/prebid#3) * Update documentation (c-wire/prebid#3) * Add validations for placementId and pageId (c-wire/prebid#3) * QA Fix linting error * Add prebid version to payload (c-wire/prebid#3) --- modules/cwireBidAdapter.js | 411 +++++++-------- modules/cwireBidAdapter.md | 29 +- test/spec/modules/cwireBidAdapter_spec.js | 584 +++++++++------------- 3 files changed, 433 insertions(+), 591 deletions(-) diff --git a/modules/cwireBidAdapter.js b/modules/cwireBidAdapter.js index a11899609bc..604d7235d0f 100644 --- a/modules/cwireBidAdapter.js +++ b/modules/cwireBidAdapter.js @@ -1,307 +1,234 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {getStorageManager} from '../src/storageManager.js'; -import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {OUTSTREAM} from '../src/video.js'; -import { - deepAccess, - generateUUID, - getBidIdParameter, - getParameterByName, - getValue, - isArray, - isNumber, - isStr, - logError, - logWarn, - parseSizesInput, -} from '../src/utils.js'; -import {Renderer} from '../src/Renderer.js'; -import {find} from '../src/polyfill.js'; +import {BANNER} from '../src/mediaTypes.js'; +import {generateUUID, getParameterByName, isNumber, logError, logInfo} from '../src/utils.js'; // ------------------------------------ const BIDDER_CODE = 'cwire'; -export const ENDPOINT_URL = 'https://embed.cwi.re/delivery/prebid'; -export const RENDERER_URL = 'https://cdn.cwi.re/prebid/renderer/LATEST/renderer.min.js'; -// ------------------------------------ -export const CW_PAGE_VIEW_ID = generateUUID(); -const LS_CWID_KEY = 'cw_cwid'; -const CW_GROUPS_QUERY = 'cwgroups'; -const CW_CREATIVE_QUERY = 'cwcreative'; +const CWID_KEY = 'cw_cwid'; -const storage = getStorageManager({bidderCode: BIDDER_CODE}); +export const BID_ENDPOINT = 'https://prebid.cwi.re/v1/bid'; +export const EVENT_ENDPOINT = 'https://prebid.cwi.re/v1/event'; /** - * ------------------------------------ - * ------------------------------------ - * @param bid - * @returns {Array} + * Allows limiting ad impressions per site render. Unique per prebid instance ID. */ -export function getSlotSizes(bid) { - return parseSizesInput(getAllMediaSizes(bid)); -} +export const pageViewId = generateUUID(); + +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); /** - * ------------------------------------ - * ------------------------------------ + * Retrieve dimensions and CSS max height/width from a given slot and attach the properties to the bidRequest. * @param bid - * @returns {*[]} + * @returns {*&{cwExt: {dimensions: {width: number, height: number}, style: {maxWidth: number, maxHeight: number}}}} */ -export function getAllMediaSizes(bid) { - let playerSizes = deepAccess(bid, 'mediaTypes.video.playerSize'); - let videoSizes = deepAccess(bid, 'mediaTypes.video.sizes'); - let bannerSizes = deepAccess(bid, 'mediaTypes.banner.sizes'); - - const sizes = []; - - if (isArray(playerSizes)) { - playerSizes.forEach((s) => { - sizes.push(s); - }) - } - - if (isArray(videoSizes)) { - videoSizes.forEach((s) => { - sizes.push(s); - }) +function slotDimensions(bid) { + let adUnitCode = bid.adUnitCode; + let slotEl = document.getElementById(adUnitCode); + + if (slotEl) { + logInfo(`Slot element found: ${adUnitCode}`) + const slotW = slotEl.offsetWidth + const slotH = slotEl.offsetHeight + const cssMaxW = slotEl.style?.maxWidth; + const cssMaxH = slotEl.style?.maxHeight; + logInfo(`Slot dimensions (w/h): ${slotW} / ${slotH}`) + logInfo(`Slot Styles (maxW/maxH): ${cssMaxW} / ${cssMaxH}`) + + bid = { + ...bid, + cwExt: { + dimensions: { + width: slotW, + height: slotH, + }, + style: { + ...(cssMaxW) && { + maxWidth: cssMaxW + }, + ...(cssMaxH) && { + maxHeight: cssMaxH + } + } + } + } } + return bid +} - if (isArray(bannerSizes)) { - bannerSizes.forEach((s) => { - sizes.push(s); - }) +/** + * Extracts feature flags from a comma-separated url parameter `cwfeatures`. + * + * @returns *[] + */ +function getFeatureFlags() { + let ffParam = getParameterByName('cwfeatures') + if (ffParam) { + return ffParam.split(',') } - return sizes; + return [] } -const getQueryVariable = (variable) => { - let value = getParameterByName(variable); - if (value === '') { - value = null; +function getRefGroups() { + const groups = getParameterByName('cwgroups') + if (groups) { + return groups.split(',') } - return value; -}; + return [] +} /** - * ------------------------------------ - * ------------------------------------ - * @param validBidRequests - * @returns {*[]} + * Reads the CWID from local storage. */ -export const mapSlotsData = function(validBidRequests) { - const slots = []; - validBidRequests.forEach(bid => { - const bidObj = {}; - // get testing / debug params - let cwcreative = getValue(bid.params, 'cwcreative'); - let refgroups = getValue(bid.params, 'refgroups'); - let cwapikey = getValue(bid.params, 'cwapikey'); +function getCwid() { + return storage.localStorageIsEnabled() ? storage.getDataFromLocalStorage(CWID_KEY) : null; +} - // get the pacement and page ids - let placementId = getValue(bid.params, 'placementId'); - let pageId = getValue(bid.params, 'pageId'); - // get the rest of the auction/bid/transaction info - bidObj.auctionId = getBidIdParameter('auctionId', bid); - bidObj.adUnitCode = getBidIdParameter('adUnitCode', bid); - bidObj.bidId = getBidIdParameter('bidId', bid); - bidObj.bidderRequestId = getBidIdParameter('bidderRequestId', bid); - bidObj.placementId = placementId; - bidObj.pageId = pageId; - bidObj.mediaTypes = getBidIdParameter('mediaTypes', bid); - bidObj.transactionId = getBidIdParameter('transactionId', bid); - bidObj.sizes = getSlotSizes(bid); - bidObj.cwcreative = cwcreative; - bidObj.refgroups = refgroups; - bidObj.cwapikey = cwapikey; - slots.push(bidObj); - }); +function hasCwid() { + return storage.localStorageIsEnabled() && storage.getDataFromLocalStorage(CWID_KEY); +} - return slots; -}; +/** + * Store the CWID to local storage. + */ +function updateCwid(cwid) { + if (storage.localStorageIsEnabled()) { + storage.setDataInLocalStorage(CWID_KEY, cwid) + } else { + logInfo(`Could not set CWID ${cwid} in localstorage`); + } +} + +/** + * Extract and collect cwire specific extensions. + */ +function getCwExtension() { + const cwId = getCwid(); + const cwCreative = getParameterByName('cwcreative') + const cwGroups = getRefGroups() + const cwFeatures = getFeatureFlags(); + // Enable debug flag by passing ?cwdebug=true as url parameter. + // Note: pbjs_debug=true enables it on prebid level + // More info: https://docs.prebid.org/troubleshooting/troubleshooting-guide.html#turn-on-prebidjs-debug-messages + const debug = getParameterByName('cwdebug'); + + return { + ...(cwId) && { + cwid: cwId + }, + ...(cwGroups.length > 0) && { + refgroups: cwGroups + }, + ...(cwFeatures.length > 0) && { + featureFlags: cwFeatures + }, + ...(cwCreative) && { + cwcreative: cwCreative + }, + ...(debug) && { + debug: true + } + }; +} export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER, VIDEO], + supportedMediaTypes: [BANNER], + /** - * Determines whether or not the given bid request is valid. + * Determines whether 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) { - bid.params = bid.params || {}; - - if (bid.params.cwcreative && !isStr(bid.params.cwcreative)) { - logError('cwcreative must be of type string!'); - return false; - } - - if (!bid.params.placementId || !isNumber(bid.params.placementId)) { - logError('placementId not provided or invalid'); + isBidRequestValid: function (bid) { + if (!bid.params?.placementId || !isNumber(bid.params.placementId)) { + logError('placementId not provided or not a number'); return false; } - if (!bid.params.pageId || !isNumber(bid.params.pageId)) { - logError('pageId not provided'); + if (!bid.params?.pageId || !isNumber(bid.params.pageId)) { + logError('pageId not provided or not a number'); return false; } - return true; }, /** - * ------------------------------------ - * itterate trough slots array and try - * to extract first occurence of a given - * key, if not found - return null - * ------------------------------------ - */ - getFirstValueOrNull: function(slots, key) { - const found = slots.find((item) => { - return (typeof item[key] !== 'undefined'); - }); - - return (found) ? found[key] : null; - }, - - /** - * ------------------------------------ - * Make a server request from the - * list of BidRequests. - * ------------------------------------ - * @param {validBidRequests[]} - an array of bids + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} validBidRequests An array of bids. * @return ServerRequest Info describing the request to the server. */ - buildRequests: function(validBidRequests, bidderRequest) { - let slots = []; - let referer; - try { - referer = bidderRequest?.refererInfo?.page; - slots = mapSlotsData(validBidRequests); - } catch (e) { - logWarn(e); - } + buildRequests: function (validBidRequests, bidderRequest) { + // There are more fields on the refererInfo object + let referrer = bidderRequest?.refererInfo?.page - let refgroups = []; - - const cwCreative = getQueryVariable(CW_CREATIVE_QUERY) || null; - const cwCreativeIdFromConfig = this.getFirstValueOrNull(slots, 'cwcreative'); - const refGroupsFromConfig = this.getFirstValueOrNull(slots, 'refgroups'); - const cwApiKeyFromConfig = this.getFirstValueOrNull(slots, 'cwapikey'); - const rgQuery = getQueryVariable(CW_GROUPS_QUERY); - - if (refGroupsFromConfig !== null) { - refgroups = refGroupsFromConfig.split(','); - } - - if (rgQuery !== null) { - // override if query param is present - refgroups = []; - refgroups = rgQuery.split(','); - } - - const localStorageCWID = storage.localStorageIsEnabled() ? storage.getDataFromLocalStorage(LS_CWID_KEY) : null; + // process bid requests + let processed = validBidRequests + .map(bid => slotDimensions(bid)) + // Flattens the pageId and placement Id for backwards compatibility. + .map((bid) => ({...bid, pageId: bid.params?.pageId, placementId: bid.params?.placementId})); + const extensions = getCwExtension(); const payload = { - cwid: localStorageCWID, - refgroups, - cwcreative: cwCreative || cwCreativeIdFromConfig, - slots: slots, - cwapikey: cwApiKeyFromConfig, - httpRef: referer || '', - pageViewId: CW_PAGE_VIEW_ID, + slots: processed, + httpRef: referrer, + // TODO: Verify whether the auctionId and the usage of pageViewId make sense. + pageViewId: pageViewId, + sdk: { + version: '$prebid.version$' + }, + ...extensions }; - + const payloadString = JSON.stringify(payload); return { method: 'POST', - url: ENDPOINT_URL, - data: payload + url: BID_ENDPOINT, + data: payloadString, }; }, - /** * Unpack the response from the server into a list of bids. * * @param {ServerResponse} serverResponse A successful response from the server. * @return {Bid[]} An array of bids which were nested inside the server. */ - interpretResponse: function(serverResponse, bidRequest) { - const bidResponses = []; - - try { - if (typeof bidRequest.data === 'string') { - bidRequest.data = JSON.parse(bidRequest.data); + interpretResponse: function (serverResponse, bidRequest) { + if (!hasCwid()) { + const cwid = serverResponse.body?.cwid + if (cwid) { + updateCwid(cwid); } - const serverBody = serverResponse.body; - serverBody.bids.forEach((br) => { - const bidReq = find(bidRequest.data.slots, bid => bid.bidId === br.requestId); - - let mediaType = BANNER; - - const bidResponse = { - requestId: br.requestId, - cpm: br.cpm, - bidderCode: BIDDER_CODE, - width: br.dimensions[0], - height: br.dimensions[1], - creativeId: br.creativeId, - currency: br.currency, - netRevenue: br.netRevenue, - ttl: br.ttl, - meta: { - advertiserDomains: br.adomains ? br.advertiserDomains : [], - }, - - }; - - // ------------------------------------ - // IF BANNER - // ------------------------------------ - - if (deepAccess(bidReq, 'mediaTypes.banner')) { - bidResponse.ad = br.html; - } - // ------------------------------------ - // IF VIDEO - // ------------------------------------ - if (deepAccess(bidReq, 'mediaTypes.video')) { - mediaType = VIDEO; - bidResponse.vastXml = br.vastXml; - bidResponse.videoScript = br.html; - const mediaTypeContext = deepAccess(bidReq, 'mediaTypes.video.context'); - if (mediaTypeContext === OUTSTREAM) { - const r = Renderer.install({ - id: bidResponse.requestId, - adUnitCode: bidReq.adUnitCode, - url: RENDERER_URL, - loaded: false, - config: { - ...deepAccess(bidReq, 'mediaTypes.video'), - ...deepAccess(br, 'outstream', {}) - } - }); + } - // set renderer - try { - bidResponse.renderer = r; - bidResponse.renderer.setRender(function(bid) { - if (window.CWIRE && window.CWIRE.outstream) { - window.CWIRE.outstream.renderAd(bid); - } - }); - } catch (err) { - logWarn('Prebid Error calling setRender on newRenderer', err); - } - } - } + // Rename `html` response property to `ad` as used by prebid. + const bids = serverResponse.body?.bids.map(({html, ...rest}) => ({...rest, ad: html})); + return bids || []; + }, - bidResponse.mediaType = mediaType; - bidResponses.push(bidResponse); - }); - } catch (e) { - logWarn(e); + onBidWon: function (bid) { + logInfo(`Bid won.`) + const event = { + type: 'BID_WON', + payload: { + bid: bid + } } + navigator.sendBeacon(EVENT_ENDPOINT, JSON.stringify(event)) + }, - return bidResponses; + onBidderError: function (error, bidderRequest) { + logInfo(`Bidder error: ${error}`) + const event = { + type: 'BID_ERROR', + payload: { + error: error, + bidderRequest: bidderRequest + } + } + navigator.sendBeacon(EVENT_ENDPOINT, JSON.stringify(event)) }, + }; registerBidder(spec); diff --git a/modules/cwireBidAdapter.md b/modules/cwireBidAdapter.md index 188894cd202..026c2943c6b 100644 --- a/modules/cwireBidAdapter.md +++ b/modules/cwireBidAdapter.md @@ -1,25 +1,27 @@ # Overview -Module Name: C-WIRE Bid Adapter -Module Type: Adagio Adapter -Maintainer: publishers@cwire.ch +``` +Module Name: C-WIRE Bid Adapter +Module Type: Bidder Adapter +Maintainer: devs@cwire.ch +``` ## Description -Connects to C-WIRE demand source to fetch bids. +Prebid.js Adapter for C-Wire. ## Configuration - Below, the list of C-WIRE params and where they can be set. -| Param name | Global config | AdUnit config | Type | Required | -| ---------- | ------------- | ------------- |--------| ---------| -| pageId | | x | number | YES | -| placementId | | x | number | YES | -| refgroups | | x | string | NO | -| cwcreative | | x | string | NO | -| cwapikey | | x | string | NO | +| Param name | URL parameter | AdUnit config | Type | Required | +|-------------|:-------------:|:-------------:|:--------:|:-------------:| +| pageId | | x | number | YES | +| placementId | | x | number | YES | +| cwgroups | x | | string | NO | +| cwcreative | x | | string | NO | +| cwdebug | x | | boolean | NO | +| cwfeatures | x | | string | NO | ### adUnit configuration @@ -32,7 +34,7 @@ var adUnits = [ bidder: 'cwire', mediaTypes: { banner: { - sizes: [[1, 1]], + sizes: [[400, 600]], } }, params: { @@ -40,7 +42,6 @@ var adUnits = [ placementId: 2211521, // required - number cwcreative: '42', // optional - id of creative to force refgroups: 'test-user', // optional - name of group or coma separated list of groups to force - cwapikey: 'api_key_xyz', // optional - api key for integration testing } }] } diff --git a/test/spec/modules/cwireBidAdapter_spec.js b/test/spec/modules/cwireBidAdapter_spec.js index f116b184b8c..88c54212aff 100644 --- a/test/spec/modules/cwireBidAdapter_spec.js +++ b/test/spec/modules/cwireBidAdapter_spec.js @@ -1,382 +1,296 @@ -import { expect } from 'chai'; -import * as utils from '../../../src/utils.js'; -import { config } from '../../../src/config.js'; -import { - spec, - CW_PAGE_VIEW_ID, - ENDPOINT_URL, - RENDERER_URL, -} from '../../../modules/cwireBidAdapter.js'; -import * as prebidGlobal from 'src/prebidGlobal.js'; - -// ------------------------------------ -// Bid Request Builder -// ------------------------------------ - -const BID_DEFAULTS = { - request: { - bidder: 'cwire', - auctionId: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', - transactionId: 'txaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', - bidId: 'bid123445', - bidderRequestId: 'brid12345', - code: 'original-div', - }, - params: { - placementId: 123456, - pageId: 777, - }, - sizes: [[300, 250], [1, 1]], -}; - -const BidderRequestBuilder = function BidderRequestBuilder(options) { - const defaults = { - bidderCode: 'cwire', - auctionId: BID_DEFAULTS.request.auctionId, - bidderRequestId: BID_DEFAULTS.request.bidderRequestId, - transactionId: BID_DEFAULTS.request.transactionId, - timeout: 3000, - }; - - const request = { - ...defaults, - ...options - }; - - this.build = () => request; -}; - -const BidRequestBuilder = function BidRequestBuilder(options, deleteKeys) { - const defaults = JSON.parse(JSON.stringify(BID_DEFAULTS)); - - const request = { - ...defaults.request, - ...options - }; - - if (request && utils.isArray(deleteKeys)) { - deleteKeys.forEach((k) => { - delete request[k]; - }) - } - - this.withParams = (options, deleteKeys) => { - request.params = { - ...defaults.params, - ...options - }; - if (request && utils.isArray(deleteKeys)) { - deleteKeys.forEach((k) => { - delete request.params[k]; - }) - } - return this; - }; - - this.build = () => request; -}; +import {expect} from 'chai'; +import {newBidder} from '../../../src/adapters/bidderFactory'; +import {BID_ENDPOINT, spec, storage} from '../../../modules/cwireBidAdapter'; +import {deepClone, logInfo} from '../../../src/utils'; +import * as utils from 'src/utils.js'; +import {sandbox, stub} from 'sinon'; +import {config} from '../../../src/config'; describe('C-WIRE bid adapter', () => { - let sandbox; - - beforeEach(() => { - sandbox = sinon.createSandbox(); + config.setConfig({debug: true}); + const adapter = newBidder(spec); + let bidRequests = [ + { + 'bidder': 'cwire', + 'params': { + 'pageId': '4057', + 'placementId': 'ad-slot-bla' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'transactionId': '04f2659e-c005-4eb1-a57c-fa93145e3843' + } + ]; + const response = { + body: { + 'cwid': '2ef90743-7936-4a82-8acf-e73382a64e94', + 'hash': '17112D98BBF55D3A', + 'bids': [{ + 'html': '

Hello world

', + 'cpm': 100, + 'currency': 'CHF', + 'dimensions': [1, 1], + 'netRevenue': true, + 'creativeId': '3454', + 'requestId': '2c634d4ca5ccfb', + 'placementId': 177, + 'transactionId': 'b4b32618-1350-4828-b6f0-fbb5c329e9a4', + 'ttl': 360 + }] + } + } + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + expect(spec.isBidRequestValid).to.exist.and.to.be.a('function'); + expect(spec.buildRequests).to.exist.and.to.be.a('function'); + expect(spec.interpretResponse).to.exist.and.to.be.a('function'); + }); }); - - afterEach(() => { - sandbox.restore(); - config.resetConfig(); + describe('buildRequests', function () { + it('sends bid request to ENDPOINT via POST', function () { + const request = spec.buildRequests(bidRequests); + expect(request.url).to.equal(BID_ENDPOINT); + expect(request.method).to.equal('POST'); + }); }); + describe('buildRequests with given creative', function () { + let utilsStub; - // START TESTING - describe('C-WIRE - isBidRequestValid', function () { - it('should return true when required params found', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - expect(spec.isBidRequestValid(bid01)).to.equal(true); + before(function () { + utilsStub = stub(utils, 'getParameterByName').callsFake(function () { + return 'str-str' + }); }); - it('should fail if there is no placementId', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - delete bid01.params.placementId - expect(spec.isBidRequestValid(bid01)).to.equal(false); + after(function () { + utilsStub.restore(); }); - it('should fail if invalid placementId type', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - delete bid01.params.placementId; - bid01.placementId = '322'; - expect(spec.isBidRequestValid(bid01)).to.equal(false); + it('should add creativeId if url parameter given', function () { + // set from bid.params + let bidRequest = deepClone(bidRequests[0]); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + expect(payload.cwcreative).to.exist; + expect(payload.cwcreative).to.deep.equal('str-str'); + }); + }) + + describe('buildRequests reads adUnit offsetWidth and offsetHeight', function () { + before(function () { + const documentStub = sandbox.stub(document, 'getElementById'); + documentStub.withArgs(`${bidRequests[0].adUnitCode}`).returns({ + offsetWidth: 200, + offsetHeight: 250 + }); }); + it('width and height should be set', function () { + let bidRequest = deepClone(bidRequests[0]); - it('should fail if there is no pageId', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - delete bid01.params.pageId - expect(spec.isBidRequestValid(bid01)).to.equal(false); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + const el = document.getElementById(`${bidRequest.adUnitCode}`) + + logInfo(JSON.stringify(payload)) + + expect(el).to.exist; + expect(payload.slots[0].cwExt.dimensions.width).to.equal(200); + expect(payload.slots[0].cwExt.dimensions.height).to.equal(250); + expect(payload.slots[0].cwExt.style.maxHeight).to.not.exist; + expect(payload.slots[0].cwExt.style.maxWidth).to.not.exist; + }); + after(function () { + sandbox.restore() + }); + }); + describe('buildRequests reads style attributes', function () { + before(function () { + const documentStub = sandbox.stub(document, 'getElementById'); + documentStub.withArgs(`${bidRequests[0].adUnitCode}`).returns({ + style: { + maxWidth: '400px', + maxHeight: '350px', + } + }); }); + it('css maxWidth should be set', function () { + let bidRequest = deepClone(bidRequests[0]); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + const el = document.getElementById(`${bidRequest.adUnitCode}`) + + logInfo(JSON.stringify(payload)) - it('should fail if invalid pageId type', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - delete bid01.params.pageId; - bid01.params.pageId = '3320'; - expect(spec.isBidRequestValid(bid01)).to.equal(false); + expect(el).to.exist; + expect(payload.slots[0].cwExt.style.maxWidth).to.eq('400px'); + !expect(payload.slots[0].cwExt.style.maxHeight).to.eq('350px'); }); + after(function () { + sandbox.restore() + }); + }); - it('should fail if cwcreative of type number', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - delete bid01.params.cwcreative; - bid01.params.cwcreative = 3320; - expect(spec.isBidRequestValid(bid01)).to.equal(false); + describe('buildRequests reads feature flags', function () { + before(function () { + sandbox.stub(utils, 'getParameterByName').callsFake(function () { + return 'feature1,feature2' + }); }); - it('should pass with valid cwcreative of type string', function () { - const bid01 = new BidRequestBuilder().withParams().build(); - bid01.params.cwcreative = 'i-am-a-string'; - expect(spec.isBidRequestValid(bid01)).to.equal(true); + it('read from url parameter', function () { + let bidRequest = deepClone(bidRequests[0]); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + logInfo(JSON.stringify(payload)) + + expect(payload.featureFlags).to.exist; + expect(payload.featureFlags).to.include.members(['feature1', 'feature2']); + }); + after(function () { + sandbox.restore() }); }); - describe('C-WIRE - buildRequests()', function () { - it('creates a valid request', function () { - const bid01 = new BidRequestBuilder({ - mediaTypes: { - banner: { - sizes: [[1, 1]], - } - } - }).withParams({ - cwcreative: '54321', - cwapikey: 'xxx-xxx-yyy-zzz-uuid', - refgroups: 'group_1', - }).build(); - - const bidderRequest01 = new BidderRequestBuilder().build(); - - const requests = spec.buildRequests([bid01], bidderRequest01); - - expect(requests.data.slots.length).to.equal(1); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.slots[0].sizes[0]).to.equal('1x1'); - expect(requests.data.cwcreative).to.equal('54321'); - expect(requests.data.cwapikey).to.equal('xxx-xxx-yyy-zzz-uuid'); - expect(requests.data.refgroups[0]).to.equal('group_1'); + describe('buildRequests reads cwgroups flag', function () { + before(function () { + sandbox.stub(utils, 'getParameterByName').callsFake(function () { + return 'group1,group2' + }); }); - it('creates a valid request - read debug params from second bid', function () { - const bid01 = new BidRequestBuilder().withParams().build(); + it('read from url parameter', function () { + let bidRequest = deepClone(bidRequests[0]); - const bid02 = new BidRequestBuilder({ - mediaTypes: { - banner: { - sizes: [[1, 1]], - } - } - }).withParams({ - cwcreative: '1234', - cwapikey: 'api_key_5', - refgroups: 'group_5', - }).build(); - - const bidderRequest01 = new BidderRequestBuilder().build(); - - const requests = spec.buildRequests([bid01, bid02], bidderRequest01); - - expect(requests.data.slots.length).to.equal(2); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwcreative).to.equal('1234'); - expect(requests.data.cwapikey).to.equal('api_key_5'); - expect(requests.data.refgroups[0]).to.equal('group_5'); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + logInfo(JSON.stringify(payload)) + + expect(payload.refgroups).to.exist; + expect(payload.refgroups).to.include.members(['group1', 'group2']); + }); + after(function () { + sandbox.restore() }); + }) - it('creates a valid request - read debug params from first bid, ignore second', function () { - const bid01 = new BidRequestBuilder() - .withParams({ - cwcreative: '33', - cwapikey: 'api_key_33', - refgroups: 'group_33', - }).build(); - - const bid02 = new BidRequestBuilder() - .withParams({ - cwcreative: '1234', - cwapikey: 'api_key_5', - refgroups: 'group_5', - }).build(); - - const bidderRequest01 = new BidderRequestBuilder().build(); - - const requests = spec.buildRequests([bid01, bid02], bidderRequest01); - - expect(requests.data.slots.length).to.equal(2); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwcreative).to.equal('33'); - expect(requests.data.cwapikey).to.equal('api_key_33'); - expect(requests.data.refgroups[0]).to.equal('group_33'); + describe('buildRequests reads debug flag', function () { + before(function () { + sandbox.stub(utils, 'getParameterByName').callsFake(function () { + return 'true' + }); }); - it('creates a valid request - read debug params from 3 different slots', function () { - const bid01 = new BidRequestBuilder() - .withParams({ - cwcreative: '33', - }).build(); - - const bid02 = new BidRequestBuilder() - .withParams({ - cwapikey: 'api_key_5', - }).build(); - - const bid03 = new BidRequestBuilder() - .withParams({ - refgroups: 'group_5', - }).build(); - const bidderRequest01 = new BidderRequestBuilder().build(); - - const requests = spec.buildRequests([bid01, bid02, bid03], bidderRequest01); - - expect(requests.data.slots.length).to.equal(3); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwcreative).to.equal('33'); - expect(requests.data.cwapikey).to.equal('api_key_5'); - expect(requests.data.refgroups[0]).to.equal('group_5'); + it('read from url parameter', function () { + let bidRequest = deepClone(bidRequests[0]); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + logInfo(JSON.stringify(payload)) + + expect(payload.debug).to.exist; + expect(payload.debug).to.equal(true); + }); + after(function () { + sandbox.restore() }); + }) - it('creates a valid request - config is overriden by URL params', function () { - // for whatever reason stub for getWindowLocation does not work - // so this was the closest way to test for get params - const params = sandbox.stub(utils, 'getParameterByName'); - params.withArgs('cwgroups').returns('group_2'); - params.withArgs('cwcreative').returns('654321'); - - const bid01 = new BidRequestBuilder({ - mediaTypes: { - banner: { - sizes: [[1, 1]], - } - } - }).withParams({ - cwcreative: '54321', - cwapikey: 'xxx-xxx-yyy-zzz', - refgroups: 'group_1', - }).build(); - - const bidderRequest01 = new BidderRequestBuilder().build(); - - const requests = spec.buildRequests([bid01], bidderRequest01); - - expect(requests.data.slots.length).to.equal(1); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.slots[0].sizes[0]).to.equal('1x1'); - expect(requests.data.cwcreative).to.equal('654321'); - expect(requests.data.cwapikey).to.equal('xxx-xxx-yyy-zzz'); - expect(requests.data.refgroups[0]).to.equal('group_2'); + describe('buildRequests reads cw_id from Localstorage', function () { + before(function () { + sandbox.stub(storage, 'localStorageIsEnabled').callsFake(() => true); + sandbox.stub(storage, 'setDataInLocalStorage'); + sandbox.stub(storage, 'getDataFromLocalStorage').callsFake((key) => 'taerfagerg'); }); - it('creates a valid request - if params are not set, null or empty array are sent to the API', function () { - const bid01 = new BidRequestBuilder({ - mediaTypes: { - banner: { - sizes: [[1, 1]], - } - } - }).withParams().build(); + it('cw_id is set', function () { + let bidRequest = deepClone(bidRequests[0]); - const bidderRequest01 = new BidderRequestBuilder().build(); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); - const requests = spec.buildRequests([bid01], bidderRequest01); + logInfo(JSON.stringify(payload)) - expect(requests.data.slots.length).to.equal(1); - expect(requests.data.cwid).to.be.null; - expect(requests.data.cwid).to.be.null; - expect(requests.data.slots[0].sizes[0]).to.equal('1x1'); - expect(requests.data.cwcreative).to.equal(null); - expect(requests.data.cwapikey).to.equal(null); - expect(requests.data.refgroups.length).to.equal(0); + expect(payload.cwid).to.exist; + expect(payload.cwid).to.equal('taerfagerg'); }); - }); + after(function () { + sandbox.restore() + }); + }) - describe('C-WIRE - interpretResponse()', function () { - const serverResponse = { - body: { - bids: [{ - html: '

AD CONTENT

', - currency: 'CHF', - cpm: 43.37, - dimensions: [1, 1], - netRevenue: true, - creativeId: '1337', - requestId: BID_DEFAULTS.request.bidId, - ttl: 3500, - }], - } - }; - - const expectedResponse = [{ - ad: JSON.parse(JSON.stringify(serverResponse.body.bids[0].html)), - bidderCode: BID_DEFAULTS.request.bidder, - cpm: JSON.parse(JSON.stringify(serverResponse.body.bids[0].cpm)), - creativeId: JSON.parse(JSON.stringify(serverResponse.body.bids[0].creativeId)), - currency: JSON.parse(JSON.stringify(serverResponse.body.bids[0].currency)), - height: JSON.parse(JSON.stringify(serverResponse.body.bids[0].dimensions[0])), - width: JSON.parse(JSON.stringify(serverResponse.body.bids[0].dimensions[1])), - netRevenue: JSON.parse(JSON.stringify(serverResponse.body.bids[0].netRevenue)), - requestId: JSON.parse(JSON.stringify(serverResponse.body.bids[0].requestId)), - ttl: JSON.parse(JSON.stringify(serverResponse.body.bids[0].ttl)), - meta: { - advertiserDomains: [], - }, - mediaType: 'banner', - }] - - it('correctly parses response', function () { - const bid01 = new BidRequestBuilder({ - mediaTypes: { - banner: { - sizes: [[1, 1]], - } - } - }).withParams().build(); + describe('buildRequests maps flattens params for legacy compat', function () { + before(function () { + const documentStub = sandbox.stub(document, 'getElementById'); + documentStub.withArgs(`${bidRequests[0].adUnitCode}`).returns({}); + }); + it('pageId flattened', function () { + let bidRequest = deepClone(bidRequests[0]); - const bidderRequest01 = new BidderRequestBuilder().build(); - const requests = spec.buildRequests([bid01], bidderRequest01); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); - const response = spec.interpretResponse(serverResponse, requests); - expect(response).to.deep.equal(expectedResponse); + logInfo(JSON.stringify(payload)) + + expect(payload.slots[0].pageId).to.exist; + }); + after(function () { + sandbox.restore() }); + }) - it('attaches renderer', function () { - const bid01 = new BidRequestBuilder({ - mediaTypes: { - video: { - playerSize: [[640, 480]], - context: 'outstream', - } - } - }).withParams().build(); - const bidderRequest01 = new BidderRequestBuilder().build(); + describe('pageId and placementId are required params', function () { + it('invalid request', function () { + let bidRequest = deepClone(bidRequests[0]); + delete bidRequest.params + + const valid = spec.isBidRequestValid(bidRequest); + expect(valid).to.be.false; + }) - const _serverResponse = utils.deepClone(serverResponse); - _serverResponse.body.bids[0].vastXml = ''; + it('valid request', function () { + let bidRequest = deepClone(bidRequests[0]); + bidRequest.params.pageId = 42 + bidRequest.params.placementId = 42 - const _expectedResponse = utils.deepClone(expectedResponse); - _expectedResponse[0].mediaType = 'video'; - _expectedResponse[0].videoScript = JSON.parse(JSON.stringify(_serverResponse.body.bids[0].html)); - _expectedResponse[0].vastXml = JSON.parse(JSON.stringify(_serverResponse.body.bids[0].vastXml)); - delete _expectedResponse[0].ad; + const valid = spec.isBidRequestValid(bidRequest); + expect(valid).to.be.true; + }) - const requests = spec.buildRequests([bid01], bidderRequest01); - expect(requests.data.slots[0].sizes).to.deep.equal(['640x480']); + it('cwcreative must be of type string', function () { + let bidRequest = deepClone(bidRequests[0]); + bidRequest.params.pageId = 42 + bidRequest.params.placementId = 42 - const response = spec.interpretResponse(_serverResponse, requests); - expect(response[0].renderer).to.exist; - expect(response[0].renderer.url).to.equals(RENDERER_URL); - expect(response[0].renderer.loaded).to.equals(false); + const valid = spec.isBidRequestValid(bidRequest); + expect(valid).to.be.true; + }) - delete response[0].renderer; - expect(response).to.deep.equal(_expectedResponse); - }); + it('build request adds pageId', function () { + let bidRequest = deepClone(bidRequests[0]); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.slots[0].pageId).to.exist; + }) + }); + + describe('process serverResponse', function () { + it('html to ad mapping', function () { + let bidResponse = deepClone(response); + const bids = spec.interpretResponse(bidResponse, {}); + + expect(bids[0].ad).to.exist; + }) }); }); From 9be4e4d5e7b1306a1ead728bc6a755a8c98d3e76 Mon Sep 17 00:00:00 2001 From: Gabriel Chicoye Date: Tue, 31 Jan 2023 20:36:35 +0100 Subject: [PATCH 306/367] bidderCode fix (#9485) --- modules/nexx360BidAdapter.js | 3 +-- test/spec/modules/nexx360BidAdapter_spec.js | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/nexx360BidAdapter.js b/modules/nexx360BidAdapter.js index b04bb47543f..6ead44175e9 100644 --- a/modules/nexx360BidAdapter.js +++ b/modules/nexx360BidAdapter.js @@ -258,14 +258,13 @@ function interpretResponse(response, req) { currency: respBody.cur || 'USD', netRevenue: true, ttl: 120, - bidderCode: allowAlternateBidderCodes ? `n360-${bid.ssp}` : 'nexx360', mediaType: bid.type === 'banner' ? 'banner' : 'video', meta: { advertiserDomains: bid.adomain, demandSource: ssp, }, }; - // if (bid.dealid) response.dealid = bid.dealid; + if (allowAlternateBidderCodes) response.bidderCode = `n360-${bid.ssp}`; if (response.mediaType === 'banner') { response.adUrl = bid.adUrl; diff --git a/test/spec/modules/nexx360BidAdapter_spec.js b/test/spec/modules/nexx360BidAdapter_spec.js index a5da8b29fbc..7645ee59f63 100644 --- a/test/spec/modules/nexx360BidAdapter_spec.js +++ b/test/spec/modules/nexx360BidAdapter_spec.js @@ -372,7 +372,6 @@ describe('Nexx360 bid adapter tests', function () { } }; const output = spec.interpretResponse(response); - expect(output[0].bidderCode).to.be.eql('nexx360'); expect(output[0].adUrl).to.be.eql(response.body.seatbid[0].bid[0].adUrl); expect(output[0].mediaType).to.be.eql(response.body.seatbid[0].bid[0].type); expect(output[0].currency).to.be.eql(response.body.cur); @@ -411,7 +410,6 @@ describe('Nexx360 bid adapter tests', function () { } }; const output = spec.interpretResponse(response); - expect(output[0].bidderCode).to.be.eql('nexx360'); expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].vastXml); expect(output[0].mediaType).to.be.eql('video'); expect(output[0].currency).to.be.eql(response.body.cur); @@ -454,7 +452,6 @@ describe('Nexx360 bid adapter tests', function () { } }; const output = spec.interpretResponse(response); - expect(output[0].bidderCode).to.be.eql('nexx360'); expect(output[0].adUrl).to.be.eql(response.body.seatbid[0].bid[0].adUrl); expect(output[0].mediaType).to.be.eql(response.body.seatbid[0].bid[0].type); expect(output[0].currency).to.be.eql(response.body.cur); @@ -490,7 +487,6 @@ describe('Nexx360 bid adapter tests', function () { } }; const output = spec.interpretResponse(response); - expect(output[0].bidderCode).to.be.eql('nexx360'); expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].vastXml); expect(output[0].mediaType).to.be.eql('video'); expect(output[0].currency).to.be.eql(response.body.cur); From cb1a982182816e8a8b47ec1c769dd40bfd223c37 Mon Sep 17 00:00:00 2001 From: ahmadlob <109217988+ahmadlob@users.noreply.github.com> Date: Tue, 31 Jan 2023 21:42:40 +0200 Subject: [PATCH 307/367] Taboola Bid Adapter: pass nurl to bidResponse (#9482) * nurl-bugfix * nurl-bugfix --- modules/taboolaBidAdapter.js | 3 ++- test/spec/modules/taboolaBidAdapter_spec.js | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/modules/taboolaBidAdapter.js b/modules/taboolaBidAdapter.js index 2e10a8d8951..026d5a098df 100644 --- a/modules/taboolaBidAdapter.js +++ b/modules/taboolaBidAdapter.js @@ -279,7 +279,7 @@ function getBid(bids, currency, bidResponse) { return; } const { - price: cpm, crid: creativeId, adm: ad, w: width, h: height, exp: ttl, adomain: advertiserDomains, meta = {} + price: cpm, nurl, crid: creativeId, adm: ad, w: width, h: height, exp: ttl, adomain: advertiserDomains, meta = {} } = bidResponse; let requestId = bids[bidResponse.impid - 1].bidId; if (advertiserDomains && advertiserDomains.length > 0) { @@ -297,6 +297,7 @@ function getBid(bids, currency, bidResponse) { width, height, meta, + nurl, netRevenue: true }; } diff --git a/test/spec/modules/taboolaBidAdapter_spec.js b/test/spec/modules/taboolaBidAdapter_spec.js index 17cc5fc0213..0c01244033e 100644 --- a/test/spec/modules/taboolaBidAdapter_spec.js +++ b/test/spec/modules/taboolaBidAdapter_spec.js @@ -460,7 +460,9 @@ describe('Taboola Adapter', function () { 'w': 300, 'h': 250, 'exp': 60, - 'lurl': 'http://us-trc.taboola.com/sample' + 'lurl': 'http://us-trc.taboola.com/sample', + 'nurl': 'http://win.example.com/', + } ], 'seat': '14204545260' @@ -546,7 +548,8 @@ describe('Taboola Adapter', function () { 'w': 300, 'h': 250, 'exp': 60, - 'lurl': 'http://us-trc.taboola.com/sample' + 'lurl': 'http://us-trc.taboola.com/sample', + 'nurl': 'http://win.example.com/' }, { 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c', @@ -562,7 +565,9 @@ describe('Taboola Adapter', function () { 'w': 300, 'h': 250, 'exp': 60, - 'lurl': 'http://us-trc.taboola.com/sample' + 'lurl': 'http://us-trc.taboola.com/sample', + 'nurl': 'http://win.example.com/' + } ], 'seat': '14204545260' @@ -586,6 +591,7 @@ describe('Taboola Adapter', function () { ad: multiServerResponse.body.seatbid[0].bid[0].adm, width: bid.w, height: bid.h, + nurl: 'http://win.example.com/', meta: { 'advertiserDomains': bid.adomain }, @@ -601,6 +607,7 @@ describe('Taboola Adapter', function () { ad: multiServerResponse.body.seatbid[0].bid[1].adm, width: bid.w, height: bid.h, + nurl: 'http://win.example.com/', meta: { 'advertiserDomains': bid.adomain }, @@ -625,6 +632,7 @@ describe('Taboola Adapter', function () { ad: bid.adm, width: bid.w, height: bid.h, + nurl: 'http://win.example.com/', meta: { 'advertiserDomains': bid.adomain }, @@ -651,6 +659,7 @@ describe('Taboola Adapter', function () { ad: bid.adm, width: bid.w, height: bid.h, + nurl: 'http://win.example.com/', meta: { 'advertiserDomains': bid.adomain }, From 4796d132242ea2a4b6bbeecbded027a861faa79e Mon Sep 17 00:00:00 2001 From: Saar Amrani Date: Wed, 1 Feb 2023 14:15:26 +0200 Subject: [PATCH 308/367] Vidazoo Bid Adapter: support for gpp consent and bid data (#9480) * feat(module): multi size request * fix getUserSyncs added tests * update(module): package-lock.json from master * feat(module): VidazooBidAdapter - send top query params to server * feat(module): pass gpp consent and bid data to server. * fix(module): change spec bidder timeout to 3000. --------- Co-authored-by: Udi Talias Co-authored-by: roman --- modules/vidazooBidAdapter.js | 78 +++++++++++++------ test/spec/modules/vidazooBidAdapter_spec.js | 83 +++++++++++++++------ 2 files changed, 117 insertions(+), 44 deletions(-) diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index bb3e4abd838..96dcc182436 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -1,8 +1,9 @@ -import { _each, deepAccess, parseSizesInput, parseUrl, uniques, isFn } from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER, VIDEO } from '../src/mediaTypes.js'; -import { getStorageManager } from '../src/storageManager.js'; -import { bidderSettings } from '../src/bidderSettings.js'; +import {_each, deepAccess, parseSizesInput, parseUrl, uniques, isFn} from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {getStorageManager} from '../src/storageManager.js'; +import {bidderSettings} from '../src/bidderSettings.js'; +import { config } from '../src/config.js'; const GVLID = 744; const DEFAULT_SUB_DOMAIN = 'prebid'; @@ -26,11 +27,11 @@ export const SUPPORTED_ID_SYSTEMS = { 'tdid': 1, 'pubProvidedId': 1 }; -const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }); +const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE}); function getTopWindowQueryParams() { try { - const parsedUrl = parseUrl(window.top.document.URL, { decodeSearchAsString: true }); + const parsedUrl = parseUrl(window.top.document.URL, {decodeSearchAsString: true}); return parsedUrl.search; } catch (e) { return ''; @@ -58,10 +59,23 @@ function isBidRequestValid(bid) { return !!(extractCID(params) && extractPID(params)); } -function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { - const { params, bidId, userId, adUnitCode, schain, mediaTypes } = bid; - const { ext } = params; - let { bidFloor } = params; +function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { + const { + params, + bidId, + userId, + adUnitCode, + schain, + mediaTypes, + auctionId, + transactionId, + bidderRequestId, + bidRequestsCount, + bidderRequestsCount, + bidderWinsCount + } = bid; + const {ext} = params; + let {bidFloor} = params; const hashUrl = hashCode(topWindowUrl); const dealId = getNextDealId(hashUrl); const uniqueDealId = getUniqueDealId(hashUrl); @@ -110,7 +124,14 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { isStorageAllowed: isStorageAllowed, gpid: gpid, cat: cat, - pagecat: pagecat + pagecat: pagecat, + auctionId: auctionId, + transactionId: transactionId, + bidderRequestId: bidderRequestId, + bidRequestsCount: bidRequestsCount, + bidderRequestsCount: bidderRequestsCount, + bidderWinsCount: bidderWinsCount, + bidderTimeout: bidderTimeout }; appendUserIdsToRequestPayload(data, userId); @@ -127,6 +148,14 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { data.usPrivacy = bidderRequest.uspConsent; } + if (bidderRequest.gppConsent) { + data.gppString = bidderRequest.gppConsent.gppString; + data.gppSid = bidderRequest.gppConsent.applicableSections; + } else if (bidderRequest.ortb2?.regs?.gpp) { + data.gppString = bidderRequest.ortb2.regs.gpp; + data.gppSid = bidderRequest.ortb2.regs.gpp_sid; + } + const dto = { method: 'POST', url: `${createDomain(subDomain)}/prebid/multi/${cId}`, @@ -169,10 +198,11 @@ function appendUserIdsToRequestPayload(payloadRef, userIds) { function buildRequests(validBidRequests, bidderRequest) { // TODO: does the fallback make sense here? const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; + const bidderTimeout = config.getConfig('bidderTimeout'); const requests = []; validBidRequests.forEach(validBidRequest => { const sizes = parseSizesInput(validBidRequest.sizes); - const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest); + const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout); requests.push(request); }); return requests; @@ -182,14 +212,14 @@ function interpretResponse(serverResponse, request) { if (!serverResponse || !serverResponse.body) { return []; } - const { bidId } = request.data; - const { results } = serverResponse.body; + const {bidId} = request.data; + const {results} = serverResponse.body; let output = []; try { results.forEach(result => { - const { creativeId, ad, price, exp, width, height, currency, advertiserDomains, mediaType = BANNER } = result; + const {creativeId, ad, price, exp, width, height, currency, advertiserDomains, mediaType = BANNER} = result; if (!ad || !price) { return; } @@ -228,8 +258,8 @@ function interpretResponse(serverResponse, request) { function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '') { let syncs = []; - const { iframeEnabled, pixelEnabled } = syncOptions; - const { gdprApplies, consentString = '' } = gdprConsent; + const {iframeEnabled, pixelEnabled} = syncOptions; + const {gdprApplies, consentString = ''} = gdprConsent; const cidArr = responses.filter(resp => deepAccess(resp, 'body.cid')).map(resp => resp.body.cid).filter(uniques); const params = `?cid=${encodeURIComponent(cidArr.join(','))}&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}` @@ -253,7 +283,9 @@ export function hashCode(s, prefix = '_') { let h = 0 let i = 0; if (l > 0) { - while (i < l) { h = (h << 5) - h + s.charCodeAt(i++) | 0; } + while (i < l) { + h = (h << 5) - h + s.charCodeAt(i++) | 0; + } } return prefix + h; } @@ -310,7 +342,8 @@ export function getCacheOpt() { export function getStorageItem(key) { try { return tryParseJSON(storage.getDataFromLocalStorage(key)); - } catch (e) { } + } catch (e) { + } return null; } @@ -318,9 +351,10 @@ export function getStorageItem(key) { export function setStorageItem(key, value, timestamp) { try { const created = timestamp || Date.now(); - const data = JSON.stringify({ value, created }); + const data = JSON.stringify({value, created}); storage.setDataInLocalStorage(key, data); - } catch (e) { } + } catch (e) { + } } export function tryParseJSON(value) { diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index 2ddb65469af..134e3e66256 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -1,4 +1,4 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import { spec as adapter, SUPPORTED_ID_SYSTEMS, @@ -15,9 +15,10 @@ import { getVidazooSessionId, } from 'modules/vidazooBidAdapter.js'; import * as utils from 'src/utils.js'; -import { version } from 'package.json'; -import { useFakeTimers } from 'sinon'; -import { BANNER, VIDEO } from '../../../src/mediaTypes'; +import {version} from 'package.json'; +import {useFakeTimers} from 'sinon'; +import {BANNER, VIDEO} from '../../../src/mediaTypes'; +import {config} from '../../../src/config'; const SUB_DOMAIN = 'openrtb'; @@ -38,6 +39,10 @@ const BID = { 'transactionId': 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', 'sizes': [[300, 250], [300, 600]], 'bidderRequestId': '1fdb5ff1b6eaa7', + 'auctionId': 'auction_id', + 'bidRequestsCount': 4, + 'bidderRequestsCount': 3, + 'bidderWinsCount': 1, 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', 'mediaTypes': [BANNER], @@ -53,6 +58,10 @@ const VIDEO_BID = { 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560', 'bidderRequestId': '12a8ae9ada9c13', 'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee', + 'auctionId': 'auction_id', + 'bidRequestsCount': 4, + 'bidderRequestsCount': 3, + 'bidderWinsCount': 1, 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', 'params': { 'subDomain': SUB_DOMAIN, @@ -85,6 +94,8 @@ const BIDDER_REQUEST = { 'consentString': 'consent_string', 'gdprApplies': true }, + 'gppString': 'gpp_string', + 'gppSid': [7], 'uspConsent': 'consent_string', 'refererInfo': { 'page': 'https://www.greatsite.com', @@ -94,6 +105,10 @@ const BIDDER_REQUEST = { 'site': { 'cat': ['IAB2'], 'pagecat': ['IAB2-2'] + }, + 'regs': { + 'gpp': 'gpp_string', + 'gpp_sid': [7] } }, }; @@ -147,7 +162,7 @@ const REQUEST = { function getTopWindowQueryParams() { try { - const parsedUrl = utils.parseUrl(window.top.document.URL, { decodeSearchAsString: true }); + const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true}); return parsedUrl.search; } catch (e) { return ''; @@ -226,6 +241,9 @@ describe('VidazooBidAdapter', function () { it('should build video request', function () { const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + config.setConfig({ + bidderTimeout: 3000 + }); const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST); expect(requests).to.have.length(1); expect(requests[0]).to.deep.equal({ @@ -243,6 +261,15 @@ describe('VidazooBidAdapter', function () { gdpr: 1, gdprConsent: 'consent_string', usPrivacy: 'consent_string', + gppString: 'gpp_string', + gppSid: [7], + auctionId: 'auction_id', + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, + transactionId: '56e184c6-bde9-497b-b9b9-cf47a61381ee', + bidderRequestId: '12a8ae9ada9c13', gpid: '', prebidVersion: version, ptrace: '1000', @@ -278,6 +305,9 @@ describe('VidazooBidAdapter', function () { }); it('should build banner request for each size', function () { + config.setConfig({ + bidderTimeout: 3000 + }); const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); const requests = adapter.buildRequests([BID], BIDDER_REQUEST); expect(requests).to.have.length(1); @@ -288,6 +318,15 @@ describe('VidazooBidAdapter', function () { gdprConsent: 'consent_string', gdpr: 1, usPrivacy: 'consent_string', + gppString: 'gpp_string', + gppSid: [7], + auctionId: 'auction_id', + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, + transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + bidderRequestId: '1fdb5ff1b6eaa7', sizes: ['300x250', '300x600'], url: 'https%3A%2F%2Fwww.greatsite.com', referrer: 'https://www.somereferrer.com', @@ -324,7 +363,7 @@ describe('VidazooBidAdapter', function () { describe('getUserSyncs', function () { it('should have valid user sync with iframeEnabled', function () { - const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ type: 'iframe', @@ -333,7 +372,7 @@ describe('VidazooBidAdapter', function () { }); it('should have valid user sync with cid on response', function () { - const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ type: 'iframe', url: 'https://sync.cootlogix.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' @@ -341,7 +380,7 @@ describe('VidazooBidAdapter', function () { }); it('should have valid user sync with pixelEnabled', function () { - const result = adapter.getUserSyncs({ pixelEnabled: true }, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ 'url': 'https://sync.cootlogix.com/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=', @@ -357,12 +396,12 @@ describe('VidazooBidAdapter', function () { }); it('should return empty array when there is no ad', function () { - const responses = adapter.interpretResponse({ price: 1, ad: '' }); + const responses = adapter.interpretResponse({price: 1, ad: ''}); expect(responses).to.be.empty; }); it('should return empty array when there is no price', function () { - const responses = adapter.interpretResponse({ price: null, ad: 'great ad' }); + const responses = adapter.interpretResponse({price: null, ad: 'great ad'}); expect(responses).to.be.empty; }); @@ -422,11 +461,11 @@ describe('VidazooBidAdapter', function () { const userId = (function () { switch (idSystemProvider) { case 'lipb': - return { lipbid: id }; + return {lipbid: id}; case 'parrableId': - return { eid: id }; + return {eid: id}; case 'id5id': - return { uid: id }; + return {uid: id}; default: return id; } @@ -445,18 +484,18 @@ describe('VidazooBidAdapter', function () { describe('alternate param names extractors', function () { it('should return undefined when param not supported', function () { - const cid = extractCID({ 'c_id': '1' }); - const pid = extractPID({ 'p_id': '1' }); - const subDomain = extractSubDomain({ 'sub_domain': 'prebid' }); + const cid = extractCID({'c_id': '1'}); + const pid = extractPID({'p_id': '1'}); + const subDomain = extractSubDomain({'sub_domain': 'prebid'}); expect(cid).to.be.undefined; expect(pid).to.be.undefined; expect(subDomain).to.be.undefined; }); it('should return value when param supported', function () { - const cid = extractCID({ 'cID': '1' }); - const pid = extractPID({ 'Pid': '2' }); - const subDomain = extractSubDomain({ 'subDOMAIN': 'prebid' }); + const cid = extractCID({'cID': '1'}); + const pid = extractPID({'Pid': '2'}); + const subDomain = extractSubDomain({'subDOMAIN': 'prebid'}); expect(cid).to.be.equal('1'); expect(pid).to.be.equal('2'); expect(subDomain).to.be.equal('prebid'); @@ -569,7 +608,7 @@ describe('VidazooBidAdapter', function () { now }); setStorageItem('myKey', 2020); - const { value, created } = getStorageItem('myKey'); + const {value, created} = getStorageItem('myKey'); expect(created).to.be.equal(now); expect(value).to.be.equal(2020); expect(typeof value).to.be.equal('number'); @@ -585,8 +624,8 @@ describe('VidazooBidAdapter', function () { }); it('should parse JSON value', function () { - const data = JSON.stringify({ event: 'send' }); - const { event } = tryParseJSON(data); + const data = JSON.stringify({event: 'send'}); + const {event} = tryParseJSON(data); expect(event).to.be.equal('send'); }); From 76f00021c4aa5a9248dcdea8be5c90a6e144f8b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Sok=C3=B3=C5=82?= <88041828+smart-adserver@users.noreply.github.com> Date: Wed, 1 Feb 2023 13:23:46 +0100 Subject: [PATCH 309/367] Smartadserver Bid Adapter: support GPP consent (#9489) * Smartadserver Bid Adapter: Add support for SDA user and site * Smartadserver Bid Adapter: Fix SDA support getConfig and add to unit testing * support floors per media type * Add GPP support * Rework payloads enriching --------- Co-authored-by: Meven Courouble --- modules/smartadserverBidAdapter.js | 19 +++++++++++---- .../modules/smartadserverBidAdapter_spec.js | 24 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/modules/smartadserverBidAdapter.js b/modules/smartadserverBidAdapter.js index 719d621b056..c07b2abe933 100644 --- a/modules/smartadserverBidAdapter.js +++ b/modules/smartadserverBidAdapter.js @@ -160,10 +160,21 @@ export const spec = { sdc: sellerDefinedContext }; - if (bidderRequest && bidderRequest.gdprConsent) { - payload.addtl_consent = bidderRequest.gdprConsent.addtlConsent; - payload.gdpr_consent = bidderRequest.gdprConsent.consentString; - payload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side + if (bidderRequest) { + if (bidderRequest.gdprConsent) { + payload.addtl_consent = bidderRequest.gdprConsent.addtlConsent; + payload.gdpr_consent = bidderRequest.gdprConsent.consentString; + payload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side + } + + if (bidderRequest.gppConsent) { + payload.gpp = bidderRequest.gppConsent.gppString; + payload.gpp_sid = bidderRequest.gppConsent.applicableSections; + } + + if (bidderRequest.uspConsent) { + payload.us_privacy = bidderRequest.uspConsent; + } } if (bid && bid.userId) { diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js index 4dacb356894..97250ad0ebc 100644 --- a/test/spec/modules/smartadserverBidAdapter_spec.js +++ b/test/spec/modules/smartadserverBidAdapter_spec.js @@ -443,6 +443,30 @@ describe('Smart bid adapter tests', function () { }); }); + describe('GPP', function () { + it('should be added to payload when gppConsent available in bidder request', function () { + const options = { + gppConsent: { + gppString: 'some-gpp-string', + applicableSections: [3, 5] + } + }; + const request = spec.buildRequests(DEFAULT_PARAMS_WO_OPTIONAL, options); + const payload = JSON.parse(request[0].data); + + expect(payload).to.have.property('gpp').and.to.equal(options.gppConsent.gppString); + expect(payload).to.have.property('gpp_sid').and.to.be.an('array'); + expect(payload.gpp_sid).to.have.lengthOf(2).and.to.deep.equal(options.gppConsent.applicableSections); + }); + + it('should be undefined on payload when gppConsent unavailable in bidder request', function () { + const request = spec.buildRequests(DEFAULT_PARAMS_WO_OPTIONAL, {}); + const payload = JSON.parse(request[0].data); + + expect(payload.gpp).to.be.undefined; + }); + }); + describe('ccpa/us privacy tests', function () { afterEach(function () { config.resetConfig(); From fc5d01439423f3a3f78dffe4d545c37c0247445f Mon Sep 17 00:00:00 2001 From: Jason Quaccia Date: Wed, 1 Feb 2023 04:46:11 -0800 Subject: [PATCH 310/367] Prebid Core: Added aliasRegistry to the Public API (#9467) * added aliasRegistry to the public api * reverted a few changes made for local dev * addressed feedback --- src/prebid.js | 8 ++++++++ test/spec/unit/pbjs_api_spec.js | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/prebid.js b/src/prebid.js index 3fb131fb02c..9ad72409990 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -915,6 +915,14 @@ $$PREBID_GLOBAL$$.aliasBidder = function (bidderCode, alias, options) { } }; +/** + * @alias module:pbjs.aliasRegistry + */ +$$PREBID_GLOBAL$$.aliasRegistry = adapterManager.aliasRegistry; +config.getConfig('aliasRegistry', config => { + if (config.aliasRegistry === 'private') delete $$PREBID_GLOBAL$$.aliasRegistry; +}); + /** * The bid response object returned by an external bidder adapter during the auction. * @typedef {Object} AdapterBidResponse diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index ae9ea09908a..0867cb0e399 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -3017,6 +3017,20 @@ describe('Unit: Prebid Module', function () { }); }); + describe('aliasRegistry', function () { + it('should return the same value as adapterManager.aliasRegistry by default', function () { + const adapterManagerAliasRegistry = adapterManager.aliasRegistry; + const pbjsAliasRegistry = $$PREBID_GLOBAL$$.aliasRegistry; + assert.equal(adapterManagerAliasRegistry, pbjsAliasRegistry); + }); + + it('should return undefined if the aliasRegistry config option is set to private', function () { + configObj.setConfig({ aliasRegistry: 'private' }); + const pbjsAliasRegistry = $$PREBID_GLOBAL$$.aliasRegistry; + assert.equal(pbjsAliasRegistry, undefined); + }); + }); + describe('setPriceGranularity', function () { it('should log error when not passed granularity', function () { const logErrorSpy = sinon.spy(utils, 'logError'); From be7bd91ff86273aa0eceb8dfa945a49f4ff31560 Mon Sep 17 00:00:00 2001 From: guiann Date: Wed, 1 Feb 2023 13:55:38 +0100 Subject: [PATCH 311/367] AdYouLike Bid Adapter : add pbjs version information (#9476) * add required clickurl in every native adrequest * allows the native response to be given as is to prebid if possible * add unit tests on new Native case * Handle meta object in bid response with default addomains array * fix icon retrieval in Native case * Update priorities in case of multiple mediatypes given * improve robustness and fix associated unit test on picture urls * add support for params.size parameter * add unit test on new size format * Makes sure the playerSize format is consistent * enable Vast response on bidder adapter * fix lint errors * add test on Vast format case * add userId to bidrequest * revert package-lock.json changes * improve multiple mediatype handling * Expose adyoulike GVL id * fix icurl issue when retreiving icon for Native mediatype * update unit tests on icon url in native mediatype * target video endpoint when video mediatype is present * add unit test on video endpoint * detect if bid request has video * remove console log * Add size information in Video bid + unit tests * Remove unused method (old video retrieval) * update pagereferrer and pageUrl values * improve null robustness in native getAssetValue * change function body and add unit test * fix pageUrl in case not given i ortb2 * adjust pageUrl and referrer values * add unit tests on new priority behaviour * add pbjsversion in bid request * add unit test --------- Co-authored-by: GuillaumeA --- modules/adyoulikeBidAdapter.js | 2 ++ test/spec/modules/adyoulikeBidAdapter_spec.js | 3 +++ 2 files changed, 5 insertions(+) diff --git a/modules/adyoulikeBidAdapter.js b/modules/adyoulikeBidAdapter.js index f7473b3bad4..e6cdc7698bf 100644 --- a/modules/adyoulikeBidAdapter.js +++ b/modules/adyoulikeBidAdapter.js @@ -126,6 +126,8 @@ export const spec = { payload.userId = createEidsArray(bidderRequest.userId); } + payload.pbjs_version = '$prebid.version$'; + const data = JSON.stringify(payload); const options = { withCredentials: true diff --git a/test/spec/modules/adyoulikeBidAdapter_spec.js b/test/spec/modules/adyoulikeBidAdapter_spec.js index e6a153d501a..24cede20352 100644 --- a/test/spec/modules/adyoulikeBidAdapter_spec.js +++ b/test/spec/modules/adyoulikeBidAdapter_spec.js @@ -722,6 +722,7 @@ describe('Adyoulike Adapter', function () { expect(payload.Version).to.equal('1.0'); expect(payload.Bids['bid_id_0'].PlacementID).to.be.equal('placement_0'); expect(payload.PageRefreshed).to.equal(false); + expect(payload.pbjs_version).to.equal('$prebid.version$'); expect(payload.Bids['bid_id_0'].TransactionID).to.be.equal('bid_id_0_transaction_id'); }); @@ -736,6 +737,7 @@ describe('Adyoulike Adapter', function () { expect(payload.Version).to.equal('1.0'); expect(payload.Bids['bid_id_0'].PlacementID).to.be.equal('placement_0'); expect(payload.PageRefreshed).to.equal(false); + expect(payload.pbjs_version).to.equal('$prebid.version$'); expect(payload.Bids['bid_id_0'].TransactionID).to.be.equal('bid_id_0_transaction_id'); }); @@ -758,6 +760,7 @@ describe('Adyoulike Adapter', function () { expect(payload.Bids['bid_id_1'].TransactionID).to.be.equal('bid_id_1_transaction_id'); expect(payload.Bids['bid_id_3'].TransactionID).to.be.equal('bid_id_3_transaction_id'); expect(payload.PageRefreshed).to.equal(false); + expect(payload.pbjs_version).to.equal('$prebid.version$'); }); it('sends bid request to endpoint setted by parameters', function () { From c925e50c6b191c8141f3593c66c10587d3863162 Mon Sep 17 00:00:00 2001 From: Zachary Carlin Date: Wed, 1 Feb 2023 15:54:23 -0500 Subject: [PATCH 312/367] Sonobi Bid Adapter: add additional sizes to bid request (#9413) * Added mediaTypes.video playerSize and sizes. * Save. * Order from least to most important. 1. Deprecated bid.size 2. bid.params.sizes. 3. mediaTypes.video.playerSize 4. mediaTypes.video.sizes 5. mediaTypes.banner.sizes * check for null. * Accepting multiple uniques sizes from different props. * Comments. * Added mediaTypes.video playerSize and sizes. * Save. * Order from least to most important. 1. Deprecated bid.size 2. bid.params.sizes. 3. mediaTypes.video.playerSize 4. mediaTypes.video.sizes 5. mediaTypes.banner.sizes * check for null. * Accepting multiple uniques sizes from different props. * Comments. * Circle CI error. Circle CI failing on line 298 due to trailing space, but there isnt one. * Circle CI error. Circle CI failing on line 298 due to trailing space, but there isnt one. * Readded hello_world.html --------- Co-authored-by: Zac Carlin --- integrationExamples/gpt/hello_world.html | 0 modules/sonobiBidAdapter.js | 27 ++++++++++++++-------- test/spec/modules/sonobiBidAdapter_spec.js | 3 ++- 3 files changed, 19 insertions(+), 11 deletions(-) mode change 100755 => 100644 integrationExamples/gpt/hello_world.html diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html old mode 100755 new mode 100644 diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 3c841cc4d8a..f9cc1f3b353 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -295,22 +295,29 @@ function _findBidderRequest(bidderRequests, bidId) { } } +// This function takes all the possible sizes. +// returns string csv. function _validateSize(bid) { - if (deepAccess(bid, 'mediaTypes.video')) { - return ''; // Video bids arent allowed to override sizes via the trinity request + let size = []; + if (deepAccess(bid, 'mediaTypes.video.playerSize')) { + size.push(deepAccess(bid, 'mediaTypes.video.playerSize')) } - - if (bid.params.sizes) { - return parseSizesInput(bid.params.sizes).join(','); + if (deepAccess(bid, 'mediaTypes.video.sizes')) { + size.push(deepAccess(bid, 'mediaTypes.video.sizes')) + } + if (deepAccess(bid, 'params.sizes')) { + size.push(deepAccess(bid, 'params.sizes')); } if (deepAccess(bid, 'mediaTypes.banner.sizes')) { - return parseSizesInput(deepAccess(bid, 'mediaTypes.banner.sizes')).join(','); + size.push(deepAccess(bid, 'mediaTypes.banner.sizes')) } - - // Handle deprecated sizes definition - if (bid.sizes) { - return parseSizesInput(bid.sizes).join(','); + if (deepAccess(bid, 'sizes')) { + size.push(deepAccess(bid, 'sizes')) } + // Pass the 2d sizes array into parseSizeInput to flatten it into an array of x separated sizes. + // Then throw it into Set to uniquify it. + // Then spread it to an array again. Then join it into a csv of sizes. + return [...new Set(parseSizesInput(...size))].join(','); } function _validateSlot(bid) { diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js index 7803cfff394..a9382f092e2 100644 --- a/test/spec/modules/sonobiBidAdapter_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -287,6 +287,7 @@ describe('SonobiBidAdapter', function () { }, mediaTypes: { video: { + sizes: [[300, 250], [300, 600]], context: 'outstream' } } @@ -331,7 +332,7 @@ describe('SonobiBidAdapter', function () { }]; let keyMakerData = { - '30b31c1838de1f': '1a2b3c4d5e6f1a2b3c4d||f=1.25,gpid=/123123/gpt_publisher/adunit-code-1,c=v,', + '30b31c1838de1f': '1a2b3c4d5e6f1a2b3c4d|300x250,300x600|f=1.25,gpid=/123123/gpt_publisher/adunit-code-1,c=v,', '30b31c1838de1d': '1a2b3c4d5e6f1a2b3c4e|300x250,300x600|f=0.42,gpid=/123123/gpt_publisher/adunit-code-3,c=d,', '/7780971/sparks_prebid_LB|30b31c1838de1e': '300x250,300x600|gpid=/7780971/sparks_prebid_LB,c=d,', }; From 3b396cfa8228402fe14c3bb4fcba49f17a15b570 Mon Sep 17 00:00:00 2001 From: Stephen Johnston Date: Wed, 1 Feb 2023 16:02:03 -0500 Subject: [PATCH 313/367] Add ESLint Plugin Recommendation for VSCODE (#9498) Just a quality of life improvement for any VSCode users. --- .devcontainer/devcontainer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0176b8317b3..104d9a38132 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -16,7 +16,8 @@ // Add the IDs of extensions you want installed when the container is created. "extensions": [ - "nickdodd79.gulptasks" + "nickdodd79.gulptasks", + "dbaeumer.vscode-eslint" ], // 9999 is web server, 9876 is karma From fef5c5a62c465fb8982c286e6f158dd28f57aed0 Mon Sep 17 00:00:00 2001 From: Matt Crute <872334+mbcrute@users.noreply.github.com> Date: Wed, 1 Feb 2023 16:03:57 -0500 Subject: [PATCH 314/367] Deprecate zeusPrimeRtdProvider submodule (#9358) Deprecates the zeusPrimeRtdProvider submodule and updates the associated documentation and tests. --- modules/zeusPrimeRtdProvider.js | 326 +------------- modules/zeusPrimeRtdProvider.md | 3 + .../spec/modules/zeusPrimeRtdProvider_spec.js | 410 ------------------ 3 files changed, 6 insertions(+), 733 deletions(-) delete mode 100644 test/spec/modules/zeusPrimeRtdProvider_spec.js diff --git a/modules/zeusPrimeRtdProvider.js b/modules/zeusPrimeRtdProvider.js index 28c46957c50..2a455a14f7b 100644 --- a/modules/zeusPrimeRtdProvider.js +++ b/modules/zeusPrimeRtdProvider.js @@ -1,328 +1,8 @@ -/** - * This module adds Zeus Insights For Publishers (ZIP) provider to the real time data module - * The {@link module:modules/realTimeData} module is required - * - * This module will request the article topics for the current page and add them as page keyvalues - * for the ad requests. - * - * @module modules/zeusInsightsForPublishersRtdProvider - * @requires module:modules/realTimeData - */ - -import { logInfo, logError, logWarn, logMessage } from '../src/utils.js' +import { logWarn } from '../src/utils.js' import { submodule } from '../src/hook.js' -import { ajaxBuilder } from '../src/ajax.js' - -class Logger { - get showDebug() { - if (this._showDebug === true || this._showDebug === false) { - return this._showDebug - } - - return window.zeusPrime?.debug || false - } - set showDebug(shouldShow) { - this._showDebug = shouldShow - } - - get error() { - return logError.bind(this, 'zeusPrimeRtdProvider: ') - } - get warn() { - return logWarn.bind(this, 'zeusPrimeRtdProvider: ') - } - get info() { - return logInfo.bind(this, 'zeusPrimeRtdProvider: ') - } - get debug() { - if (this.showDebug) { - return logMessage.bind(this, 'zeusPrimeRtdProvider: ') - } - - return () => {} - } -} - -var logger = new Logger() - -function loadCommandQueue() { - window.zeusPrime = window.zeusPrime || { cmd: [] } - const queue = [...window.zeusPrime.cmd] - - window.zeusPrime.cmd = [] - window.zeusPrime.cmd.push = (callback) => { - callback(window.zeusPrime) - } - - queue.forEach((callback) => callback(window.zeusPrime)) -} - -function markStatusComplete(key) { - const status = window?.zeusPrime?.status - if (status) { - status[key] = true - } -} - -function createStatus() { - if (window.zeusPrime && !window.zeusPrime.status) { - Object.defineProperty(window.zeusPrime, 'status', { - enumerable: false, - value: { - initComplete: false, - primeKeyValueSet: false, - insightsReqSent: false, - insightsReqReceived: false, - insightsKeyValueSet: false, - scriptComplete: false, - }, - }) - } -} - -function loadPrimeQueryParams() { - try { - const params = new URLSearchParams(window.location.search) - params.forEach((paramValue, paramKey) => { - if (!paramKey.startsWith('zeus_prime_')) { - return - } - - let key = paramKey.replace('zeus_prime_', '') - let value = paramValue.toLowerCase() - - if (value === 'true' || value === '1') { - value = true - } else if (value === 'false' || value === '0') { - value = false - } - - window.zeusPrime[key] = value - }) - } catch (_) {} -} - -const DEFAULT_API = 'https://insights.zeustechnology.com' - -function init(gamId = null, options = {}) { - window.zeusPrime = window.zeusPrime || { cmd: [] } - - window.zeusPrime.gamId = gamId || options.gamId || window.zeusPrime.gamId || undefined - window.zeusPrime.api = DEFAULT_API - window.zeusPrime.hostname = options.hostname || window.location?.hostname || '' - window.zeusPrime.pathname = options.pathname || window.location?.pathname || '' - window.zeusPrime.pageUrl = `${window.zeusPrime.hostname}${window.zeusPrime.pathname}` - window.zeusPrime.pageHash = options.pageHash || null - window.zeusPrime.debug = window.zeusPrime.debug || options.debug === true || false - window.zeusPrime.disabled = window.zeusPrime.disabled || options.disabled === true || false - - loadPrimeQueryParams() - - logger.showDebug = window.zeusPrime.debug - - createStatus() - markStatusComplete('initComplete') -} - -function setTargeting() { - const { gamId, hostname } = window.zeusPrime - - if (typeof gamId !== 'string') { - throw new Error(`window.zeusPrime.gamId must be a string. Received: ${String(gamId)}`) - } - - addKeyValueToGoogletag(`zeus_${gamId}`, hostname) - logger.debug(`Setting zeus_${gamId}=${hostname}`) - markStatusComplete('primeKeyValueSet') -} -function setPrimeAsDisabled() { - addKeyValueToGoogletag('zeus_prime', 'false') - logger.debug('Disabling prime; Setting key-value zeus_prime to false') -} - -function addKeyValueToGoogletag(key, value) { - window.googletag = window.googletag || { cmd: [] } - window.googletag.cmd.push(function () { - window.googletag.pubads().setTargeting(key, value) - }) -} - -function isInsightsPage(pathname = '') { - const NOT_SECTIONS = [ - { - test: /\/search/, - type: 'search', - }, - { - test: /\/author/, - type: 'author', - }, - { - test: /\/event/, - type: 'event', - }, - { - test: /\/homepage/, - type: 'front', - }, - { - test: /^\/?$/, - type: 'front', - }, - ] - - const typeObj = NOT_SECTIONS.find((pg) => pathname.match(pg.test)) - return typeObj === undefined -} - -async function getUrlHash(canonical) { - try { - const buf = await window.crypto.subtle.digest( - 'SHA-1', - new TextEncoder('utf-8').encode(canonical) - ) - const hashed = Array.prototype.map - .call(new Uint8Array(buf), (x) => `00${x.toString(16)}`.slice(-2)) - .join('') - - return hashed - } catch (e) { - logger.error('Failed to load hash', e.message) - logger.debug('Exception', e) - return '' - } -} - -async function sendPrebidRequest(url) { - return new Promise((resolve, reject) => { - const ajax = ajaxBuilder() - ajax(url, { - success: (responseText, response) => { - resolve({ - ...response, - status: response.status, - json: () => JSON.parse(responseText), - }) - }, - - error: (responseText, response) => { - if (!response.status) { - reject(response) - } - - let json = responseText - if (responseText) { - try { - json = JSON.parse(responseText) - } catch (_) { - json = null - } - } - - resolve({ - status: response.status, - json: () => json || null, - responseValue: json, - }) - }, - }) - }) -} - -async function requestTopics() { - const { api, hostname, pageUrl } = window.zeusPrime - - if (!window.zeusPrime.pageHash) { - window.zeusPrime.pageHash = await getUrlHash(pageUrl) - } - - const pageHash = window.zeusPrime.pageHash - const zeusInsightsUrl = `${api}/${hostname}/${pageHash}?article_location=${pageUrl}` - - logger.debug('Requesting topics', zeusInsightsUrl) - try { - markStatusComplete('insightsReqSent') - const response = await sendPrebidRequest(zeusInsightsUrl) - if (response.status === 200) { - logger.debug('topics found') - markStatusComplete('insightsReqReceived') - return await response.json() - } else if ( - response.status === 204 || - response.status < 200 || - (response.status >= 300 && response.status <= 399) - ) { - logger.debug('no topics found') - markStatusComplete('insightsReqReceived') - return null - } else { - logger.error(`Topics request returned error: ${response.status}`) - markStatusComplete('insightsReqReceived') - return null - } - } catch (e) { - logger.error('failed to request topics', e) - return null - } -} - -function setTopicsTargeting(topics = []) { - if (topics.length === 0) { - return - } - - window.googletag = window.googletag || { cmd: [] } - window.googletag.cmd.push(function () { - window.googletag.pubads().setTargeting('zeus_insights', topics) - }) - - markStatusComplete('insightsKeyValueSet') -} - -async function startTopicsRequest() { - if (isInsightsPage(window.zeusPrime.pathname)) { - const response = await requestTopics() - if (response) { - setTopicsTargeting(response?.topics) - } - } else { - logger.debug('This page is not eligible for topics, request will be skipped') - } -} - -async function run(gamId, options = {}) { - logger.showDebug = options.debug || false - - try { - init(gamId, options) - loadCommandQueue() - - if (window.zeusPrime.disabled) { - setPrimeAsDisabled() - } else { - setTargeting() - await startTopicsRequest() - } - } catch (e) { - logger.error('Failed to run.', e.message || e) - } finally { - markStatusComplete('scriptComplete') - } -} - -/** - * @preserve - * Initializes the ZeusPrime RTD Submodule. The config provides the GamID for this - * site that is used to configure Prime. - * @param {object} config The Prebid configuration for this module. - * @param {object} config.params The parameters for this module. - * @param {string} config.params.gamId The Gam ID (or Network Code) in GAM for this site. - */ -function initModule(config) { - const { params } = config || {} - const { gamId, ...rest } = params || {} - run(gamId, rest) +function initModule() { + logWarn('Zeus Prime has been deprecated. This module will be removed in Prebid 8.') } /** diff --git a/modules/zeusPrimeRtdProvider.md b/modules/zeusPrimeRtdProvider.md index f3a6c5018d5..40b44e76f1c 100644 --- a/modules/zeusPrimeRtdProvider.md +++ b/modules/zeusPrimeRtdProvider.md @@ -1,5 +1,8 @@ # Overview +# NOTE: ZEUS PRIME HAS BEEN DEPRECATED! +# THIS MODULE WILL BE REMOVED IN PREBID 8. + Module Name: Zeus Prime RTD Provider Module Type: Rtd Provider Maintainer: support@zeustechnology.com diff --git a/test/spec/modules/zeusPrimeRtdProvider_spec.js b/test/spec/modules/zeusPrimeRtdProvider_spec.js deleted file mode 100644 index 294d98df377..00000000000 --- a/test/spec/modules/zeusPrimeRtdProvider_spec.js +++ /dev/null @@ -1,410 +0,0 @@ -import { zeusPrimeSubmodule } from 'modules/zeusPrimeRtdProvider'; -import { server } from 'test/mocks/xhr.js'; -import * as utils from 'src/utils'; - -async function waitForStatus(statusVar) { - const MAX_COUNT = 20; - let count = 0; - while ( - count <= MAX_COUNT && - window.zeusPrime.status && - window.zeusPrime.status[statusVar] !== true - ) { - count += 1; - await new Promise((resolve) => setTimeout(resolve, 10)); - } - - if (count === MAX_COUNT) { - throw new Error('Timeout waiting for zeusPrimeRtdProvider to complete'); - } -} - -/** - * Execute all the commands in the googletag.cmd queue. - */ -function executeGoogletagTargeting() { - window.googletag.cmd.forEach((cmd) => cmd()); -} - -describe('Zeus Prime RTD submodule', () => { - let logErrorSpy; - let logMessageSpy; - let setTargetingStub; - let originalGtag; - - beforeEach(() => { - logErrorSpy = sinon.spy(utils, 'logError'); - logMessageSpy = sinon.spy(utils, 'logMessage'); - setTargetingStub = sinon.stub(); - window.zeusPrime = { cmd: [] }; - originalGtag = window.googletag; - window.googletag = { - cmd: [], - pubads: () => ({ - setTargeting: setTargetingStub, - }), - }; - - // Mock subtle since this doesnt exists in some test environments due to security in newer browsers. - if (typeof window.crypto.subtle === 'undefined') { - Object.defineProperty(crypto, 'subtle', { value: { digest: () => 'mockHash' } }) - } - }); - - afterEach(() => { - logErrorSpy.restore(); - logMessageSpy.restore(); - window.googletag = originalGtag; - }); - - it('should init and set key-value for zeus_', async () => { - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - hostname: 'www.example.com', - pathname: '/', - }, - }); - - // wait for the script to finish - await waitForStatus('scriptComplete'); - - // execute any googletag commands added to the queue during execution - executeGoogletagTargeting(); - - expect(window.googletag.cmd).to.have.length(1); - sinon.assert.callCount(setTargetingStub, 1); - sinon.assert.calledWith(setTargetingStub, 'zeus_1234', 'www.example.com'); - }); - - it('should init and set key-value for zeus_ from command queue', async () => { - window.zeusPrime.cmd.push((prime) => (prime.gamId = '9876')); - zeusPrimeSubmodule.init({ - params: { - hostname: 'www.example.com', - pathname: '/', - }, - }); - - // wait for the script to finish - await waitForStatus('scriptComplete'); - - // execute any googletag commands added to the queue during execution - executeGoogletagTargeting(); - - expect(window.googletag.cmd).to.have.length(1); - sinon.assert.callCount(setTargetingStub, 1); - sinon.assert.calledWith(setTargetingStub, 'zeus_9876', 'www.example.com'); - }); - - it('should init with values from location and set key-value for zeus_', async () => { - zeusPrimeSubmodule.init({ params: { gamId: '1234' } }); - - // wait for the script to finish - await waitForStatus('scriptComplete'); - - // execute any googletag commands added to the queue during execution - executeGoogletagTargeting(); - - expect(window.googletag.cmd).to.have.length(1); - sinon.assert.callCount(setTargetingStub, 1); - sinon.assert.calledWith(setTargetingStub, 'zeus_1234', 'localhost'); - expect(window.zeusPrime.pathname).to.equal('/context.html'); - }); - - it('should emit error when gamId is not set', async () => { - zeusPrimeSubmodule.init({}); - - // wait for the script to finish - await waitForStatus('scriptComplete'); - - // execute any googletag commands added to the queue during execution - executeGoogletagTargeting(); - - expect(window.googletag.cmd).to.have.length(0); - sinon.assert.callCount(setTargetingStub, 0); - sinon.assert.calledWith( - logErrorSpy, - 'zeusPrimeRtdProvider: ', - 'Failed to run.', - 'window.zeusPrime.gamId must be a string. Received: undefined' - ); - }); - - it('should not make a call to the server when url is a homepage', async () => { - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - hostname: 'www.example.com', - pathname: '/', - }, - }); - - // wait for the script to finish - await waitForStatus('scriptComplete'); - - expect(server.requests).to.have.length(0); - }); - - it('should make a call to the server and set key-vlaue when url is an article page and returns topics', async () => { - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - hostname: 'www.example.com', - pathname: '/article/some-article', - }, - }); - - // Wait for request to be sent - await waitForStatus('insightsReqReceived'); - - // Response - server.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - '{"topics": ["bs0"]}' - ); - - // Wait for the script to process the response - await waitForStatus('scriptComplete'); - - // execute any googletag commands added to the queue during execution - executeGoogletagTargeting(); - - expect(server.requestCount).to.be.equal(1); - expect(window.googletag.cmd).to.have.length(2); - sinon.assert.calledTwice(setTargetingStub); - sinon.assert.calledWith( - setTargetingStub.firstCall, - 'zeus_1234', - 'www.example.com' - ); - sinon.assert.calledWith(setTargetingStub.secondCall, 'zeus_insights', [ - 'bs0', - ]); - sinon.assert.notCalled(logErrorSpy); - }); - - it('should not set insights keyvalue when server returns 204', async () => { - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - hostname: 'www.example.com', - pathname: '/article/some-article', - }, - }); - - // Wait for request to be sent - await waitForStatus('insightsReqReceived'); - - // Response - server.requests[0].respond(204, { 'Content-Type': 'application/json' }); - - // Wait for the script to process the response - await waitForStatus('scriptComplete'); - - // execute any googletag commands added to the queue during execution - executeGoogletagTargeting(); - - expect(server.requestCount).to.be.equal(1); - expect(window.googletag.cmd).to.have.length(1); - sinon.assert.calledOnce(setTargetingStub); - sinon.assert.calledWith( - setTargetingStub.firstCall, - 'zeus_1234', - 'www.example.com' - ); - sinon.assert.notCalled(logErrorSpy); - }); - - it('should not set insights keyvalue when server returns empty topics array', async () => { - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - hostname: 'www.example.com', - pathname: '/article/some-article', - }, - }); - - // Wait for request to be sent - await waitForStatus('insightsReqReceived'); - - // Respond - server.requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - '{ "topics": [] }' - ); - - // Wait for the script to process the response - await waitForStatus('scriptComplete'); - - // execute any googletag commands added to the queue during execution - executeGoogletagTargeting(); - - expect(server.requestCount).to.be.equal(1); - expect(window.googletag.cmd).to.have.length(1); - sinon.assert.calledOnce(setTargetingStub); - sinon.assert.calledWith( - setTargetingStub.firstCall, - 'zeus_1234', - 'www.example.com' - ); - sinon.assert.notCalled(logErrorSpy); - }); - - it('should not set insights keyvalue and emit error when server returns error status (400)', async () => { - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - hostname: 'www.example.com', - pathname: '/article/some-article', - }, - }); - - // Wait for request to be sent - await waitForStatus('insightsReqReceived'); - - // Response - server.requests[0].respond( - 404, - { 'Content-Type': 'application/json' }, - '{"message": "Not found"}' - ); - - // Wait for the script to process the response - await waitForStatus('scriptComplete'); - - // execute any googletag commands added to the queue during execution - executeGoogletagTargeting(); - - expect(server.requestCount).to.be.equal(1); - expect(window.googletag.cmd).to.have.length(1); - sinon.assert.calledOnce(setTargetingStub); - sinon.assert.calledWith( - setTargetingStub.firstCall, - 'zeus_1234', - 'www.example.com' - ); - sinon.assert.calledWith( - logErrorSpy, - 'zeusPrimeRtdProvider: ', - 'Topics request returned error: 404' - ); - }); - - it('should not set insights keyvalue and emit error when response is not received (network request)', async () => { - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - hostname: 'www.example.com', - pathname: '/article/some-article', - }, - }); - - // Wait for request to be sent - await waitForStatus('insightsReqReceived'); - - // Response - server.requests[0].error(); - - // Wait for the script to process the response - await waitForStatus('scriptComplete'); - - // execute any googletag commands added to the queue during execution - executeGoogletagTargeting(); - - expect(server.requestCount).to.be.equal(1); - expect(window.googletag.cmd).to.have.length(1); - sinon.assert.calledOnce(setTargetingStub); - sinon.assert.calledWith( - setTargetingStub.firstCall, - 'zeus_1234', - 'www.example.com' - ); - sinon.assert.calledWith( - logErrorSpy, - 'zeusPrimeRtdProvider: ', - 'failed to request topics' - ); - }); - - it('fails gracefully when crypto fails', async () => { - const digestStub = sinon.stub(window.crypto.subtle, 'digest'); - digestStub.throwsException('Failed to generate digest.'); - - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - hostname: 'www.example.com', - pathname: '/article/some-article', - }, - }); - - // Wait for request to be sent - await waitForStatus('scriptComplete'); - - sinon.assert.calledWith( - logErrorSpy, - 'zeusPrimeRtdProvider: ', - 'Failed to load hash' - ); - - digestStub.restore(); - }); - - it('script should add zeus_prime key and not send request when disabled is set', async () => { - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - disabled: true, - hostname: 'www.example.com', - pathname: '/article/some-article', - }, - }); - - // Wait for request to be sent - await waitForStatus('scriptComplete'); - - // execute any googletag commands added to the queue during execution - executeGoogletagTargeting(); - - expect(server.requestCount).to.be.equal(0); - expect(window.googletag.cmd).to.have.length(1); - sinon.assert.calledWith(setTargetingStub, 'zeus_prime', 'false'); - }); - - it('debug true enables debug logging', async () => { - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - debug: true, - hostname: 'www.example.com', - pathname: '/article/some-article', - }, - }); - - // Wait for request to be sent - await waitForStatus('scriptComplete'); - - sinon.assert.called(logMessageSpy); - sinon.assert.notCalled(logErrorSpy); - }); - - it('debug false disables debug logging', async () => { - window.zeusPrime.disabled = false; - zeusPrimeSubmodule.init({ - params: { - gamId: '1234', - hostname: 'www.example.com', - pathname: '/article/some-article', - }, - }); - - // Wait for request to be sent - await waitForStatus('scriptComplete'); - - sinon.assert.notCalled(logMessageSpy); - sinon.assert.notCalled(logErrorSpy); - }); -}); From b04f56d7b76b2493803939948e6096227decc3f0 Mon Sep 17 00:00:00 2001 From: Jason Quaccia Date: Thu, 2 Feb 2023 05:46:13 -0800 Subject: [PATCH 315/367] Consent Management: Added config option for user action timeout (#9365) * progress * fixed tests and refactored * reverted some changes made while devloping on my local * in progress * updated action timeout logic * removed comment * reverted a few changes * reverted another change * addressed feedback * refactored actionTimeout logic --- modules/consentManagement.js | 38 +++++++++++++--- test/spec/modules/consentManagement_spec.js | 50 ++++++++++++++++++++- 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/modules/consentManagement.js b/modules/consentManagement.js index 217ceecb1c4..bdf6649bcba 100644 --- a/modules/consentManagement.js +++ b/modules/consentManagement.js @@ -18,12 +18,16 @@ const CMP_VERSION = 2; export let userCMP; export let consentTimeout; +export let actionTimeout; export let gdprScope; export let staticConsentData; let consentData; let addedConsentHook = false; let provisionalConsent; +let onTimeout; +let timer = null; +let actionTimer = null; // add new CMPs here, with their dedicated lookup function const cmpCallMap = { @@ -39,6 +43,12 @@ function lookupStaticConsentData({onSuccess, onError}) { processCmpData(staticConsentData, {onSuccess, onError}) } +export function setActionTimeout(timeout = setTimeout) { + clearTimeout(timer); + timer = null; + actionTimer = timeout(onTimeout, actionTimeout); +} + /** * This function handles interacting with an IAB compliant CMP to obtain the consent information of the user. * Given the async nature of the CMP's API, we pass in acting success/error callback functions to exit this function @@ -84,6 +94,7 @@ function lookupIabConsent({onSuccess, onError}) { processCmpData(tcfData, {onSuccess, onError}); } else { provisionalConsent = tcfData; + if (!isNaN(actionTimeout) && actionTimer === null && timer != null) setActionTimeout(); } } else { onError('CMP unable to register callback function. Please check CMP setup.'); @@ -162,14 +173,20 @@ function lookupIabConsent({onSuccess, onError}) { * @param cb A callback that takes: a boolean that is true if the auction should be canceled; an error message and extra * error arguments that will be undefined if there's no error. */ -function loadConsentData(cb) { +export function loadConsentData(cb, callMap = cmpCallMap, timeout = setTimeout) { let isDone = false; - let timer = null; function done(consentData, shouldCancelAuction, errMsg, ...extraArgs) { if (timer != null) { clearTimeout(timer); + timer = null; + } + + if (actionTimer != null) { + clearTimeout(actionTimer); + actionTimer = null; } + isDone = true; gdprDataHandler.setConsentData(consentData); if (typeof cb === 'function') { @@ -188,10 +205,11 @@ function loadConsentData(cb) { done(null, true, msg, ...extraArgs); } } - cmpCallMap[userCMP](callbacks); + + callMap[userCMP](callbacks); if (!isDone) { - const onTimeout = () => { + onTimeout = () => { const continueToAuction = (data) => { done(data, false, 'CMP did not load, continuing auction...'); } @@ -200,10 +218,16 @@ function loadConsentData(cb) { onError: () => continueToAuction(storeConsentData(undefined)) }) } + if (consentTimeout === 0) { onTimeout(); } else { - timer = setTimeout(onTimeout, consentTimeout); + if (timer != null) { + clearTimeout(timer); + timer = null; + } + + timer = timeout(onTimeout, consentTimeout); } } } @@ -328,6 +352,10 @@ export function setConsentConfig(config) { logInfo(`consentManagement config did not specify cmp. Using system default setting (${DEFAULT_CMP}).`); } + if (isNumber(config.actionTimeout)) { + actionTimeout = config.actionTimeout; + } + if (isNumber(config.timeout)) { consentTimeout = config.timeout; } else { diff --git a/test/spec/modules/consentManagement_spec.js b/test/spec/modules/consentManagement_spec.js index 47a2e2ab3d9..506b88ad839 100644 --- a/test/spec/modules/consentManagement_spec.js +++ b/test/spec/modules/consentManagement_spec.js @@ -1,4 +1,15 @@ -import { setConsentConfig, requestBidsHook, resetConsentData, userCMP, consentTimeout, staticConsentData, gdprScope } from 'modules/consentManagement.js'; +import { + setConsentConfig, + requestBidsHook, + resetConsentData, + userCMP, + consentTimeout, + actionTimeout, + staticConsentData, + gdprScope, + loadConsentData, + setActionTimeout +} from 'modules/consentManagement.js'; import { gdprDataHandler } from 'src/adapterManager.js'; import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; @@ -726,4 +737,41 @@ describe('consentManagement', function () { }); }); }); + + describe('actionTimeout', function () { + afterEach(function () { + config.resetConfig(); + resetConsentData(); + }); + + it('should set actionTimeout if present', () => { + setConsentConfig({ + gdpr: { timeout: 5000, actionTimeout: 5500 } + }); + + expect(userCMP).to.be.equal('iab'); + expect(consentTimeout).to.be.equal(5000); + expect(actionTimeout).to.be.equal(5500); + }); + + it('should utilize actionTimeout duration on initial user visit when user action is pending', () => { + const cb = () => {}; + const cmpCallMap = { + 'iab': () => {}, + 'static': () => {} + }; + const timeout = sinon.spy(); + + setConsentConfig({ + gdpr: { timeout: 5000, actionTimeout: 5500 } + }); + loadConsentData(cb, cmpCallMap, timeout); + + sinon.assert.calledWith(timeout, sinon.match.any, 5000); + + setActionTimeout(); + + timeout.lastCall.lastArg === 5500; + }); + }); }); From 04bc713d1aff97af7b1c4806d2daadc9d6fe6fa2 Mon Sep 17 00:00:00 2001 From: asurovenko-zeta <80847074+asurovenko-zeta@users.noreply.github.com> Date: Thu, 2 Feb 2023 16:29:15 +0100 Subject: [PATCH 316/367] ZetaGlobalSsp bid adapter: bidfloor module (#9490) * ZetaGlobalSspBidAdapter: support bidfloors module * remove added space for linting * fix test --------- Co-authored-by: Surovenko Alexey Co-authored-by: Alexey Surovenko Co-authored-by: Chris Huie --- modules/zeta_global_sspBidAdapter.js | 15 +++++++++++++++ .../modules/zeta_global_sspBidAdapter_spec.js | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/modules/zeta_global_sspBidAdapter.js b/modules/zeta_global_sspBidAdapter.js index 6c5b9783782..74ddfc0bd06 100644 --- a/modules/zeta_global_sspBidAdapter.js +++ b/modules/zeta_global_sspBidAdapter.js @@ -90,6 +90,21 @@ export const spec = { if (!impData.banner && !impData.video) { impData.banner = buildBanner(request); } + + if (typeof request.getFloor === 'function') { + const floorInfo = request.getFloor({ + currency: 'USD', + mediaType: impData.video ? 'video' : 'banner', + size: [ impData.video ? impData.video.w : impData.banner.w, impData.video ? impData.video.h : impData.banner.h ] + }); + if (floorInfo && floorInfo.floor) { + impData.bidfloor = floorInfo.floor; + } + } + if (!impData.bidfloor && params.bidfloor) { + impData.bidfloor = params.bidfloor; + } + return impData; }); diff --git a/test/spec/modules/zeta_global_sspBidAdapter_spec.js b/test/spec/modules/zeta_global_sspBidAdapter_spec.js index d6befa0fc78..f616403cfcd 100644 --- a/test/spec/modules/zeta_global_sspBidAdapter_spec.js +++ b/test/spec/modules/zeta_global_sspBidAdapter_spec.js @@ -41,6 +41,7 @@ describe('Zeta Ssp Bid Adapter', function () { app: { bundle: 'testBundle' }, + bidfloor: 0.2, test: 1 }; @@ -359,4 +360,11 @@ describe('Zeta Ssp Bid Adapter', function () { expect(payload.tmax).to.be.undefined; }); + + it('Test provide bidfloor', function () { + const request = spec.buildRequests(bannerRequest, bannerRequest[0]); + const payload = JSON.parse(request.data); + + expect(payload.imp[0].bidfloor).to.eql(params.bidfloor); + }); }); From 3be964e4854bafbc1ef224407cb3a6227c7871cf Mon Sep 17 00:00:00 2001 From: onetag-dev <38786435+onetag-dev@users.noreply.github.com> Date: Thu, 2 Feb 2023 16:34:50 +0100 Subject: [PATCH 317/367] OneTag Bid Adapter: add gppConsent fetch (#9487) Co-authored-by: federico --- modules/onetagBidAdapter.js | 13 ++++++- test/spec/modules/onetagBidAdapter_spec.js | 43 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/modules/onetagBidAdapter.js b/modules/onetagBidAdapter.js index b5217e77cd6..70238294c38 100644 --- a/modules/onetagBidAdapter.js +++ b/modules/onetagBidAdapter.js @@ -61,6 +61,12 @@ function buildRequests(validBidRequests, bidderRequest) { consentRequired: bidderRequest.gdprConsent.gdprApplies }; } + if (bidderRequest && bidderRequest.gppConsent) { + payload.gppConsent = { + consentString: bidderRequest.gppConsent.gppString, + applicableSections: bidderRequest.gppConsent.applicableSections + } + } if (bidderRequest && bidderRequest.uspConsent) { payload.usPrivacy = bidderRequest.uspConsent; } @@ -340,7 +346,7 @@ function getSizes(sizes) { return ret; } -function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { +function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) { let syncs = []; let params = ''; if (gdprConsent) { @@ -351,6 +357,11 @@ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { params += '&gdpr_consent=' + gdprConsent.consentString; } } + if (gppConsent) { + if (typeof gppConsent.gppString === 'string') { + params += '&gpp_consent=' + gppConsent.gppString; + } + } if (uspConsent && typeof uspConsent === 'string') { params += '&us_privacy=' + uspConsent; } diff --git a/test/spec/modules/onetagBidAdapter_spec.js b/test/spec/modules/onetagBidAdapter_spec.js index 71e897c7f9e..5bd65cf0fd5 100644 --- a/test/spec/modules/onetagBidAdapter_spec.js +++ b/test/spec/modules/onetagBidAdapter_spec.js @@ -266,6 +266,27 @@ 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 GPP consent data', function () { + let consentString = 'consentString'; + let applicableSections = [1, 2, 3]; + let bidderRequest = { + 'bidderCode': 'onetag', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gppConsent': { + gppString: consentString, + applicableSections: applicableSections + } + }; + let serverRequest = spec.buildRequests([bannerBid], bidderRequest); + const payload = JSON.parse(serverRequest.data); + + expect(payload).to.exist; + expect(payload.gppConsent).to.exist; + expect(payload.gppConsent.consentString).to.exist.and.to.equal(consentString); + expect(payload.gppConsent.applicableSections).to.have.same.members(applicableSections); + }); it('Should send us privacy string', function () { let consentString = 'us_foo'; let bidderRequest = { @@ -375,6 +396,28 @@ describe('onetag', function () { expect(syncs[0].url).to.include(sync_endpoint); expect(syncs[0].url).to.not.match(/(?:[?&](?:gdpr_consent=([^&]*)|gdpr=([^&]*)))+$/); }); + it('Must pass gpp consent string when gppConsent object is available', function () { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, {}, { + gppString: 'foo' + }); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.include(sync_endpoint); + expect(syncs[0].url).to.match(/(?:[?&](?:gpp_consent=foo([^&]*)))+$/); + }); + it('Must pass no gpp params when consentString is null', function () { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, {}, { + gppString: null + }); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.include(sync_endpoint); + expect(syncs[0].url).to.not.match(/(?:[?&](?:gpp_consent=([^&]*)))+$/); + }); + it('Must pass no gpp params when consentString is empty', function () { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, {}, {}); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.include(sync_endpoint); + expect(syncs[0].url).to.not.match(/(?:[?&](?:gpp_consent=([^&]*)))+$/); + }); it('Should send us privacy string', function () { let usConsentString = 'us_foo'; const syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, usConsentString); From 50e107faf3e49e67f7d8bb20eb04ccb5cbe42e5d Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 2 Feb 2023 17:08:08 +0000 Subject: [PATCH 318/367] Prebid 7.35.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6249ef52c04..96f6a796918 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.35.0-pre", + "version": "7.35.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 6467045121b..9d3fbb66093 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.35.0-pre", + "version": "7.35.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From ae21d87dbe50bb9f20fe8ecb29fadc32e80c41c8 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 2 Feb 2023 17:08:08 +0000 Subject: [PATCH 319/367] Increment version to 7.36.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 96f6a796918..d766178d188 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.35.0", + "version": "7.36.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 9d3fbb66093..cf3a7703aac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.35.0", + "version": "7.36.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 3e2b9fca2ab41eb8280925c27b5d970ca43cd6f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Feb 2023 12:38:37 -0500 Subject: [PATCH 320/367] Bump http-cache-semantics from 4.1.0 to 4.1.1 (#9502) Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/kornelski/http-cache-semantics/releases) - [Commits](https://github.com/kornelski/http-cache-semantics/commits) --- updated-dependencies: - dependency-name: http-cache-semantics dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index d766178d188..587b7897394 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.34.0-pre", + "version": "7.36.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -13818,9 +13818,9 @@ } }, "node_modules/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==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-errors": { @@ -36045,9 +36045,9 @@ "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==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "http-errors": { From dacbd1b6003000f8b0675f4aae1f9c35c69f5942 Mon Sep 17 00:00:00 2001 From: Stephen Johnston Date: Thu, 2 Feb 2023 12:41:51 -0500 Subject: [PATCH 321/367] Fix gpg Key Expiration for Debian Containers (#9497) Debian containers for yarn are having issues with key expirations. This change resolves that. Eventually the base images should be updated, but that timeline is unknown. There are a number of proposed solutions for the issue, but this one fixes ours. References to the issue: https://github.com/yarnpkg/yarn/issues/7866 Similar in AWS Builds: https://github.com/yarnpkg/yarn/issues/7866 --- .devcontainer/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index cfb29ebdfa9..69e13850258 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,8 @@ ARG VARIANT="12" FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:${VARIANT} +RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor > /usr/share/keyrings/yarn-archive-keyring.gpg + # [Optional] Uncomment this section to install additional OS packages. # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ # && apt-get -y install --no-install-recommends From 62fbcb491b6d40816e84a15ff182dbbe31446e07 Mon Sep 17 00:00:00 2001 From: Nitin Nimbalkar <96475150+nitin0610@users.noreply.github.com> Date: Fri, 3 Feb 2023 01:10:36 +0530 Subject: [PATCH 322/367] Topics Module: Mark Down file added (#9484) * Topics MD file added * Topics MD file changes --- modules/fpdModule/index.md | 7 +++-- modules/topicsFpdModule.md | 62 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 modules/topicsFpdModule.md diff --git a/modules/fpdModule/index.md b/modules/fpdModule/index.md index 638c966883a..238881db96b 100644 --- a/modules/fpdModule/index.md +++ b/modules/fpdModule/index.md @@ -16,9 +16,11 @@ Validation Submodule: - verify that certain OpenRTB attributes are not specified - optionally suppress user FPD based on the existence of _pubcid_optout +Topic Submodule: +- populate first party/third party topics data onto user.data in bid stream. 1. Module initializes on first load and set bidRequestHook -2. When hook runs, corresponding submodule init functions are run to perform enrichments/validations dependant on submodule +2. When hook runs, corresponding submodule init functions are run to perform enrichments/validations/topics dependant on submodule 3. After hook complete, it is disabled - meaning module only runs on first auction 4. To reinitiate the module, run pbjs.refreshFPD(), which allows module to rerun as if initial load @@ -43,4 +45,5 @@ pbjs.setConfig({ At least one of the submodules must be included in order to successfully run the corresponding above operations. enrichmentFpdModule -validationFpdModule \ No newline at end of file +validationFpdModule +topicsFpdModule \ No newline at end of file diff --git a/modules/topicsFpdModule.md b/modules/topicsFpdModule.md new file mode 100644 index 00000000000..b1bc3cb0d5b --- /dev/null +++ b/modules/topicsFpdModule.md @@ -0,0 +1,62 @@ +# Overview + +Module Name: topicsFpdModule + +# Description +Purpose of this module is to call the Topics API (document.browsingTopics()) which will fetch the first party domain as well third party domain(Iframe) topics data which will be sent onto user.data in bid stream. + +The intent of the Topics API is to provide callers (including third-party ad-tech or advertising providers on the page that run script) with coarse-grained advertising topics that the page visitor might currently be interested in. + +Topics Module(topicsFpdModule) should be included in prebid final package to call topics API. +Module topicsFpdModule helps to call the Topics API which will send topics data in bid stream (onto user.data) + +``` +try { + if ('browsingTopics' in document && document.featurePolicy.allowsFeature('browsing-topics')) { + topics = document.browsingTopics(); + } +} catch (e) { + console.error('Could not call topics API', e); +} +``` + +# Topics Iframe Configuration + +Topics iframe implementation is the enhancements of existing module under topicsFpdModule.js where different bidders will call the topic API under their domain to fetch the topics for respective domain and the segment data will be part of ORTB request under user.data object. Default config is maintained in the module itself. + +Below are the configuration which can be used to configure and override the default config maintained in the module. + +``` +pbjs.setConfig({ + userSync: { + ..., + topics: { + maxTopicCaller: 3, // SSP rotation + bidders: [{ + bidder: 'pubmatic', + iframeURL: 'https://ads.pubmatic.com/AdServer/js/topics/topics_frame.html', + expiry: 7 // Configurable expiry days + },{ + bidder: 'rubicon', + iframeURL: 'https://rubicon.com:8080/topics/fpd/topic.html', // dummy URL + expiry: 7 // Configurable expiry days + },{ + bidder: 'appnexus', + iframeURL: 'https://appnexus.com:8080/topics/fpd/topic.html', // dummy URL + expiry: 7 // Configurable expiry days + }] + } + .... + } +}) +``` + +## Topics Config Descriptions + +| Field | Required? | Type | Description | +|---|---|---|---| +| topics.maxTopicCaller | no | integer | Defines the maximum numbers of Bidders Iframe which needs to be loaded on the publisher page. Default is 1 which is hardcoded in Module. Eg: topics.maxTopicCaller is set to 3. If there are 10 bidders configured along with their iframe URLS, random 3 bidders iframe URL is loaded which will call TOPICS API. If topics.maxTopicCaller is set to 0, it will load random 1(default) bidder iframe atleast. | +| topics.bidders | no | Array of objects | Array of topics callers with the iframe locations and other necessary informations like bidder(Bidder code) and expiry. Default Array of topics in the module itself.| +| topics.bidders[].bidder | yes | string | Bidder Code of the bidder(SSP). | +| topics.bidders[].iframeURL | yes | string | URL which is hosted on bidder/SSP/third-party domains which will call Topics API. | +| topics.bidders[].expiry | no | integer | Max number of days where Topics data will be persist. If Data is stored for more than mentioned expiry day, it will be deleted from storage. Default is 21 days which is hardcoded in Module. | \ No newline at end of file From e9cc90742d332f2c6211414acd88d8ea506994ab Mon Sep 17 00:00:00 2001 From: Alexandru Date: Sat, 4 Feb 2023 17:07:24 +0200 Subject: [PATCH 323/367] BrightcomSSP bid adapter: add new adapter (#9411) * BrightcomSSP: add new adapter * BrightcomSSP: add glvid * BrightcomSSP: add missing gvlid; update isBidRequestValidC --- modules/brightcomBidAdapter.js | 1 + modules/brightcomSSPBidAdapter.js | 323 ++++++++++++++ modules/brightcomSSPBidAdapter.md | 46 ++ .../modules/brightcomSSPBidAdapter_spec.js | 411 ++++++++++++++++++ 4 files changed, 781 insertions(+) create mode 100644 modules/brightcomSSPBidAdapter.js create mode 100644 modules/brightcomSSPBidAdapter.md create mode 100644 test/spec/modules/brightcomSSPBidAdapter_spec.js diff --git a/modules/brightcomBidAdapter.js b/modules/brightcomBidAdapter.js index bbe0203772a..15b4175b59a 100644 --- a/modules/brightcomBidAdapter.js +++ b/modules/brightcomBidAdapter.js @@ -9,6 +9,7 @@ const URL = 'https://brightcombid.marphezis.com/hb'; export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER], + gvlid: 883, isBidRequestValid, buildRequests, interpretResponse, diff --git a/modules/brightcomSSPBidAdapter.js b/modules/brightcomSSPBidAdapter.js new file mode 100644 index 00000000000..b7a9aa3fdc9 --- /dev/null +++ b/modules/brightcomSSPBidAdapter.js @@ -0,0 +1,323 @@ +import { + getBidIdParameter, + isArray, + getWindowTop, + getUniqueIdentifierStr, + deepSetValue, + logError, + logWarn, + createTrackPixelHtml, + getWindowSelf, + isFn, + isPlainObject, +} from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; +import {config} from '../src/config.js'; +import {ajax} from '../src/ajax.js'; + +const BIDDER_CODE = 'bcmssp'; +const URL = 'https://rt.marphezis.com/hb'; +const TRACK_EVENT_URL = 'https://rt.marphezis.com/prebid' + +export const spec = { + code: BIDDER_CODE, + gvlid: 883, + supportedMediaTypes: [BANNER], + isBidRequestValid, + buildRequests, + interpretResponse, + onBidderError, + onTimeout, + onBidWon, + getUserSyncs, +}; + +function buildRequests(bidReqs, bidderRequest) { + try { + const impressions = bidReqs.map(bid => { + let bidSizes = bid?.mediaTypes?.banner?.sizes || bid.sizes; + bidSizes = ((isArray(bidSizes) && isArray(bidSizes[0])) ? bidSizes : [bidSizes]); + bidSizes = bidSizes.filter(size => isArray(size)); + const processedSizes = bidSizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)})); + + const element = document.getElementById(bid.adUnitCode); + const minSize = _getMinSize(processedSizes); + const viewabilityAmount = _isViewabilityMeasurable(element) ? _getViewability(element, getWindowTop(), minSize) : 'na'; + const viewabilityAmountRounded = isNaN(viewabilityAmount) ? viewabilityAmount : Math.round(viewabilityAmount); + + const imp = { + id: bid.bidId, + banner: { + format: processedSizes, + ext: { + viewability: viewabilityAmountRounded + } + }, + tagid: String(bid.adUnitCode) + }; + + const bidFloor = _getBidFloor(bid); + + if (bidFloor) { + imp.bidfloor = bidFloor; + } + + return imp; + }) + + const referrer = bidderRequest?.refererInfo?.page || ''; + const publisherId = getBidIdParameter('publisherId', bidReqs[0].params); + + const payload = { + id: getUniqueIdentifierStr(), + imp: impressions, + site: { + domain: bidderRequest?.refererInfo?.domain || '', + page: referrer, + publisher: { + id: publisherId + } + }, + device: { + devicetype: _getDeviceType(), + w: screen.width, + h: screen.height + }, + tmax: config.getConfig('bidderTimeout') + }; + + if (bidderRequest?.gdprConsent) { + deepSetValue(payload, 'regs.ext.gdpr', +bidderRequest.gdprConsent.gdprApplies); + deepSetValue(payload, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + + if (bidderRequest?.uspConsent) { + deepSetValue(payload, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + + if (config.getConfig('coppa') === true) { + deepSetValue(payload, 'regs.coppa', 1); + } + + if (bidReqs?.[0]?.schain) { + deepSetValue(payload, 'source.ext.schain', bidReqs[0].schain) + } + + if (bidReqs?.[0]?.userIdAsEids) { + deepSetValue(payload, 'user.ext.eids', bidReqs[0].userIdAsEids || []) + } + + if (bidReqs?.[0].userId) { + deepSetValue(payload, 'user.ext.ids', bidReqs[0].userId || []) + } + + return { + method: 'POST', + url: URL, + data: JSON.stringify(payload), + options: {contentType: 'text/plain', withCredentials: false} + }; + } catch (e) { + logError(e, {bidReqs, bidderRequest}); + } +} + +function isBidRequestValid(bid) { + if (bid.bidder !== BIDDER_CODE || !bid.params || !bid.params.publisherId) { + return false; + } + + return true; +} + +function interpretResponse(serverResponse) { + let response = []; + if (!serverResponse.body || typeof serverResponse.body != 'object') { + logWarn('Brightcom server returned empty/non-json response: ' + JSON.stringify(serverResponse.body)); + return response; + } + + const {body: {id, seatbid}} = serverResponse; + + try { + if (id && seatbid && seatbid.length > 0 && seatbid[0].bid && seatbid[0].bid.length > 0) { + response = seatbid[0].bid.map(bid => { + return { + requestId: bid.impid, + cpm: parseFloat(bid.price), + width: parseInt(bid.w), + height: parseInt(bid.h), + creativeId: bid.crid || bid.id, + currency: 'USD', + netRevenue: true, + mediaType: BANNER, + ad: _getAdMarkup(bid), + ttl: 60, + meta: { + advertiserDomains: bid?.adomain || [] + } + }; + }); + } + } catch (e) { + logError(e, {id, seatbid}); + } + + return response; +} + +// Don't do user sync for now +function getUserSyncs(syncOptions, responses, gdprConsent) { + return []; +} + +function onTimeout(timeoutData) { + if (timeoutData === null) { + return; + } + + _trackEvent('timeout', timeoutData); +} + +function onBidderError(errorData) { + if (errorData === null || !errorData.bidderRequest) { + return; + } + + _trackEvent('error', errorData.bidderRequest) +} + +function onBidWon(bid) { + if (bid === null) { + return; + } + + _trackEvent('bidwon', bid) +} + +function _trackEvent(endpoint, data) { + ajax(`${TRACK_EVENT_URL}/${endpoint}`, null, JSON.stringify(data), { + method: 'POST', + withCredentials: false + }); +} + +function _isMobile() { + return (/(ios|ipod|ipad|iphone|android)/i).test(navigator.userAgent); +} + +function _isConnectedTV() { + return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(navigator.userAgent); +} + +function _getDeviceType() { + return _isMobile() ? 1 : _isConnectedTV() ? 3 : 2; +} + +function _getAdMarkup(bid) { + let adm = bid.adm; + if ('nurl' in bid) { + adm += createTrackPixelHtml(bid.nurl); + } + return adm; +} + +function _isViewabilityMeasurable(element) { + return !_isIframe() && element !== null; +} + +function _getViewability(element, topWin, {w, h} = {}) { + return getWindowTop().document.visibilityState === 'visible' ? _getPercentInView(element, topWin, {w, h}) : 0; +} + +function _isIframe() { + try { + return getWindowSelf() !== getWindowTop(); + } catch (e) { + return true; + } +} + +function _getMinSize(sizes) { + return sizes.reduce((min, size) => size.h * size.w < min.h * min.w ? size : min); +} + +function _getBoundingBox(element, {w, h} = {}) { + let {width, height, left, top, right, bottom} = element.getBoundingClientRect(); + + if ((width === 0 || height === 0) && w && h) { + width = w; + height = h; + right = left + w; + bottom = top + h; + } + + return {width, height, left, top, right, bottom}; +} + +function _getIntersectionOfRects(rects) { + const bbox = { + left: rects[0].left, right: rects[0].right, top: rects[0].top, bottom: rects[0].bottom + }; + + for (let i = 1; i < rects.length; ++i) { + bbox.left = Math.max(bbox.left, rects[i].left); + bbox.right = Math.min(bbox.right, rects[i].right); + + if (bbox.left >= bbox.right) { + return null; + } + + bbox.top = Math.max(bbox.top, rects[i].top); + bbox.bottom = Math.min(bbox.bottom, rects[i].bottom); + + if (bbox.top >= bbox.bottom) { + return null; + } + } + + bbox.width = bbox.right - bbox.left; + bbox.height = bbox.bottom - bbox.top; + + return bbox; +} + +function _getPercentInView(element, topWin, {w, h} = {}) { + const elementBoundingBox = _getBoundingBox(element, {w, h}); + + // Obtain the intersection of the element and the viewport + const elementInViewBoundingBox = _getIntersectionOfRects([{ + left: 0, top: 0, right: topWin.innerWidth, bottom: topWin.innerHeight + }, elementBoundingBox]); + + let elementInViewArea, elementTotalArea; + + if (elementInViewBoundingBox !== null) { + // Some or all of the element is in view + elementInViewArea = elementInViewBoundingBox.width * elementInViewBoundingBox.height; + elementTotalArea = elementBoundingBox.width * elementBoundingBox.height; + + return ((elementInViewArea / elementTotalArea) * 100); + } + + // No overlap between element and the viewport; therefore, the element + // lies completely out of view + return 0; +} + +function _getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return bid.params.bidFloor ? bid.params.bidFloor : null; + } + + let floor = bid.getFloor({ + currency: 'USD', mediaType: '*', size: '*' + }); + if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') { + return floor.floor; + } + return null; +} + +registerBidder(spec); diff --git a/modules/brightcomSSPBidAdapter.md b/modules/brightcomSSPBidAdapter.md new file mode 100644 index 00000000000..8d0e4ec70dc --- /dev/null +++ b/modules/brightcomSSPBidAdapter.md @@ -0,0 +1,46 @@ +# Overview + +``` +Module Name: Brightcom SSP Bid Adapter +Module Type: Bidder Adapter +Maintainer: alexandruc@brightcom.com +``` + +# Description + +Brightcom's adapter integration to the Prebid library. + +# Test Parameters + +``` +var adUnits = [ + { + code: 'test-leaderboard', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + bids: [{ + bidder: 'bcmssp', + params: { + publisherId: 2141020, + bidFloor: 0.01 + } + }] + }, { + code: 'test-banner', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [{ + bidder: 'bcmssp', + params: { + publisherId: 2141020 + } + }] + } +] +``` diff --git a/test/spec/modules/brightcomSSPBidAdapter_spec.js b/test/spec/modules/brightcomSSPBidAdapter_spec.js new file mode 100644 index 00000000000..6f35a7a290b --- /dev/null +++ b/test/spec/modules/brightcomSSPBidAdapter_spec.js @@ -0,0 +1,411 @@ +import { expect } from 'chai'; +import * as utils from 'src/utils.js'; +import { spec } from 'modules/brightcomSSPBidAdapter'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import {config} from '../../../src/config'; + +const URL = 'https://rt.marphezis.com/hb'; + +describe('brightcomSSPBidAdapter', 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': 'bcmssp', + 'params': { + 'publisherId': 1234567 + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, + 'bidId': '5fb26ac22bde4', + 'bidderRequestId': '4bf93aeb730cb9', + 'auctionId': 'ffe9a1f7-7b67-4bda-a8e0-9ee5dc9f442e', + 'schain': { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'exchange1.com', + 'sid': '1234', + 'hp': 1, + 'rid': 'bid-request-1', + 'name': 'publisher', + 'domain': 'publisher.com' + } + ] + }, + }]; + + 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': 'bcmssp', + '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); + }); + + it('sends gdpr info if exists', function () { + const consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; + const bidderRequest = { + 'bidderCode': 'bcmssp', + 'auctionId': '1d1a030790a437', + 'bidderRequestId': '22edbae2744bf5', + 'timeout': 3000, + gdprConsent: { + consentString: consentString, + gdprApplies: true + }, + refererInfo: { + page: 'http://example.com/page.html', + domain: 'example.com', + } + }; + bidderRequest.bids = bidRequests; + + const data = JSON.parse(spec.buildRequests(bidRequests, bidderRequest).data); + + expect(data.regs.ext.gdpr).to.exist.and.to.be.a('number'); + expect(data.regs.ext.gdpr).to.equal(1); + expect(data.user.ext.consent).to.exist.and.to.be.a('string'); + expect(data.user.ext.consent).to.equal(consentString); + }); + + it('sends us_privacy', function () { + const bidderRequest = { + uspConsent: '1YYY' + }; + const data = JSON.parse(spec.buildRequests(bidRequests, bidderRequest).data) + + expect(data.regs).to.not.equal(null); + expect(data.regs.ext).to.not.equal(null); + expect(data.regs.ext.us_privacy).to.equal('1YYY'); + }); + + it('sends coppa', function () { + sandbox.stub(config, 'getConfig').withArgs('coppa').returns(true); + + const data = JSON.parse(spec.buildRequests(bidRequests).data) + expect(data.regs).to.not.be.undefined; + expect(data.regs.coppa).to.equal(1); + }); + + it('sends schain', function () { + const data = JSON.parse(spec.buildRequests(bidRequests).data); + expect(data).to.not.be.undefined; + expect(data.source).to.not.be.undefined; + expect(data.source.ext).to.not.be.undefined; + expect(data.source.ext.schain).to.not.be.undefined; + expect(data.source.ext.schain.complete).to.equal(1); + expect(data.source.ext.schain.ver).to.equal('1.0'); + expect(data.source.ext.schain.nodes).to.not.be.undefined; + expect(data.source.ext.schain.nodes).to.lengthOf(1); + expect(data.source.ext.schain.nodes[0].asi).to.equal('exchange1.com'); + expect(data.source.ext.schain.nodes[0].sid).to.equal('1234'); + expect(data.source.ext.schain.nodes[0].hp).to.equal(1); + expect(data.source.ext.schain.nodes[0].rid).to.equal('bid-request-1'); + expect(data.source.ext.schain.nodes[0].name).to.equal('publisher'); + expect(data.source.ext.schain.nodes[0].domain).to.equal('publisher.com'); + }); + + it('sends user eid parameters', function () { + bidRequests[0].userIdAsEids = [{ + source: 'pubcid.org', + uids: [{ + id: 'userid_pubcid' + }] + }, { + source: 'adserver.org', + uids: [{ + id: 'userid_ttd', + ext: { + rtiPartner: 'TDID' + } + }] + } + ]; + + const data = JSON.parse(spec.buildRequests(bidRequests).data); + + expect(data.user).to.not.be.undefined; + expect(data.user.ext).to.not.be.undefined; + expect(data.user.ext.eids).to.not.be.undefined; + expect(data.user.ext.eids).to.deep.equal(bidRequests[0].userIdAsEids); + }); + + it('sends user id parameters', function () { + const userId = { + sharedid: { + id: '01*******', + third: '01E*******' + } + }; + + bidRequests[0].userId = userId; + + const data = JSON.parse(spec.buildRequests(bidRequests).data); + expect(data.user).to.not.be.undefined; + expect(data.user.ext).to.not.be.undefined; + expect(data.user.ext.ids).is.deep.equal(userId); + }); + + 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, + 'adomain': ['example.com'] + }] + }] + } + }; + }); + + 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, + 'meta': { + 'advertiserDomains': ['example.com'] + } + }]; + + 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, + 'meta': { + 'advertiserDomains': ['example.com'] + } + }]; + + 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; + }); + }); +}); From c8ac9db51d5ff92ba9da054daca2d8bc355d48bc Mon Sep 17 00:00:00 2001 From: AndreaC <67786179+darkstarac@users.noreply.github.com> Date: Sun, 5 Feb 2023 15:36:09 +0100 Subject: [PATCH 324/367] AIDEM Bidder Adapter: changed required params and win notice payload (#9457) * AIDEM Bid Adapter * Added _spec.js * update * Fix Navigator in _spec.js * Removed timeout handler. * Added publisherId as required bidder params * moved publisherId into site publisher object * Added wpar to environment * Added placementId parameter * added unit tests for the wpar environment object * PlacementId is now a required parameter Added optional rateLimit parameter Added publisherId, siteId, placementId in win notice payload Added unit tests * Revert to optional placementId parameter Added missing semicolons --------- Co-authored-by: Giovanni Sollazzo Co-authored-by: darkstar --- modules/aidemBidAdapter.js | 155 +++++++++++++--------- modules/aidemBidAdapter.md | 17 ++- test/spec/modules/aidemBidAdapter_spec.js | 87 ++++++++++-- 3 files changed, 177 insertions(+), 82 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 081a0324ddb..e4d5c618b77 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -1,4 +1,4 @@ -import {_each, contains, deepAccess, deepSetValue, getDNT, isBoolean, isStr, logError, logInfo} from '../src/utils.js'; +import {_each, contains, deepAccess, deepSetValue, getDNT, isBoolean, isStr, isNumber, logError, logInfo} from '../src/utils.js'; import {config} from '../src/config.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; @@ -21,6 +21,8 @@ export const ERROR_CODES = { SITE_ID_INVALID_VALUE: 4, MEDIA_TYPE_NOT_SUPPORTED: 5, PUBLISHER_ID_INVALID_VALUE: 6, + INVALID_RATELIMIT: 7, + PLACEMENT_ID_INVALID_VALUE: 8, }; const endpoints = { @@ -30,29 +32,29 @@ const endpoints = { timeout: `${BASE_URL}/notice/timeout`, error: `${BASE_URL}/notice/error`, } -} +}; export function setEndPoints(env = null, path = '', mediaType = BANNER) { switch (env) { case 'local': - endpoints.request = mediaType === BANNER ? `${LOCAL_BASE_URL}${path}/bid/request` : `${LOCAL_BASE_URL}${path}/bid/videorequest` - endpoints.notice.win = `${LOCAL_BASE_URL}${path}/notice/win` - endpoints.notice.error = `${LOCAL_BASE_URL}${path}/notice/error` - endpoints.notice.timeout = `${LOCAL_BASE_URL}${path}/notice/timeout` + endpoints.request = mediaType === BANNER ? `${LOCAL_BASE_URL}${path}/bid/request` : `${LOCAL_BASE_URL}${path}/bid/videorequest`; + endpoints.notice.win = `${LOCAL_BASE_URL}${path}/notice/win`; + endpoints.notice.error = `${LOCAL_BASE_URL}${path}/notice/error`; + endpoints.notice.timeout = `${LOCAL_BASE_URL}${path}/notice/timeout`; break; case 'main': - endpoints.request = mediaType === BANNER ? `${BASE_URL}${path}/bid/request` : `${BASE_URL}${path}/bid/videorequest` - endpoints.notice.win = `${BASE_URL}${path}/notice/win` - endpoints.notice.error = `${BASE_URL}${path}/notice/error` - endpoints.notice.timeout = `${BASE_URL}${path}/notice/timeout` + endpoints.request = mediaType === BANNER ? `${BASE_URL}${path}/bid/request` : `${BASE_URL}${path}/bid/videorequest`; + endpoints.notice.win = `${BASE_URL}${path}/notice/win`; + endpoints.notice.error = `${BASE_URL}${path}/notice/error`; + endpoints.notice.timeout = `${BASE_URL}${path}/notice/timeout`; break; } - return endpoints + return endpoints; } config.getConfig('aidem', function (config) { - if (config.aidem.env) { setEndPoints(config.aidem.env, config.aidem.path, config.aidem.mediaType) } -}) + if (config.aidem.env) { setEndPoints(config.aidem.env, config.aidem.path, config.aidem.mediaType); } +}); // AIDEM Custom FN function recur(obj) { @@ -121,8 +123,8 @@ function getDevice() { function getRegs() { let regs = {}; - const consentManagement = config.getConfig('consentManagement') - const coppa = config.getConfig('coppa') + const consentManagement = config.getConfig('consentManagement'); + const coppa = config.getConfig('coppa'); if (consentManagement && !!(consentManagement.gdpr)) { deepSetValue(regs, 'gdpr_applies', !!consentManagement.gdpr); } else { @@ -145,11 +147,15 @@ function getRegs() { } function getPageUrl(bidderRequest) { - return bidderRequest?.refererInfo?.page + return bidderRequest?.refererInfo?.page; } function buildWinNotice(bid) { + const params = bid.params[0]; return { + publisherId: params.publisherId, + siteId: params.siteId, + placementId: params.placementId, burl: deepAccess(bid, 'meta.burl'), cpm: bid.cpm, currency: bid.currency, @@ -161,7 +167,7 @@ function buildWinNotice(bid) { ttl: bid.ttl, requestTimestamp: bid.requestTimestamp, responseTimestamp: bid.responseTimestamp, - } + }; } function buildErrorNotice(prebidErrorResponse) { @@ -171,29 +177,29 @@ function buildErrorNotice(prebidErrorResponse) { auctionId: prebidErrorResponse.auctionId, bidderRequestId: prebidErrorResponse.bidderRequestId, metrics: {} - } + }; } function hasValidFloor(obj) { - if (!obj) return false - const hasValue = !isNaN(Number(obj.value)) - const hasCurrency = contains(AVAILABLE_CURRENCIES, obj.currency) - return hasValue && hasCurrency + if (!obj) return false; + const hasValue = !isNaN(Number(obj.value)); + const hasCurrency = contains(AVAILABLE_CURRENCIES, obj.currency); + return hasValue && hasCurrency; } function getMediaType(bidRequest) { - if ((bidRequest.mediaTypes && bidRequest.mediaTypes.hasOwnProperty('video')) || bidRequest.params.hasOwnProperty('video')) { return VIDEO } - return BANNER + if ((bidRequest.mediaTypes && bidRequest.mediaTypes.hasOwnProperty('video')) || bidRequest.params.hasOwnProperty('video')) { return VIDEO; } + return BANNER; } function getPrebidRequestFields(bidderRequest, bidRequests) { - const payload = {} + const payload = {}; // Base Payload Data deepSetValue(payload, 'id', bidderRequest.auctionId); // Impressions - setPrebidImpressionObject(bidRequests, payload) + setPrebidImpressionObject(bidRequests, payload); // Device - deepSetValue(payload, 'device', getDevice()) + deepSetValue(payload, 'device', getDevice()); // Timeout deepSetValue(payload, 'tmax', bidderRequest.timeout); // Currency @@ -203,13 +209,13 @@ function getPrebidRequestFields(bidderRequest, bidRequests) { // Privacy Regs deepSetValue(payload, 'regs', getRegs()); // Site - setPrebidSiteObject(bidderRequest, payload) + setPrebidSiteObject(bidderRequest, payload); // Environment - setPrebidRequestEnvironment(payload) + setPrebidRequestEnvironment(payload); // AT auction type deepSetValue(payload, 'at', 1); - return payload + return payload; } function setPrebidImpressionObject(bidRequests, payload) { @@ -220,24 +226,24 @@ function setPrebidImpressionObject(bidRequests, payload) { deepSetValue(impressionObject, 'id', bidRequest.bidId); // Transaction id deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'transactionId')); - // Placement id + // placement id deepSetValue(impressionObject, 'tagid', deepAccess(bidRequest, 'params.placementId', null)); // Publisher id deepSetValue(payload, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); // Site id deepSetValue(payload, 'site.id', deepAccess(bidRequest, 'params.siteId')); - const mediaType = getMediaType(bidRequest) + const mediaType = getMediaType(bidRequest); switch (mediaType) { case 'banner': - setPrebidImpressionObjectBanner(bidRequest, impressionObject) + setPrebidImpressionObjectBanner(bidRequest, impressionObject); break; case 'video': - setPrebidImpressionObjectVideo(bidRequest, impressionObject) + setPrebidImpressionObjectVideo(bidRequest, impressionObject); break; } // Floor (optional) - setPrebidImpressionObjectFloor(bidRequest, impressionObject) + setPrebidImpressionObjectFloor(bidRequest, impressionObject); impressionObject.imp_ext = {}; @@ -272,10 +278,10 @@ function setPrebidRequestEnvironment(payload) { } function setPrebidImpressionObjectFloor(bidRequest, impressionObject) { - const floor = deepAccess(bidRequest, 'params.floor') + const floor = deepAccess(bidRequest, 'params.floor'); if (hasValidFloor(floor)) { - deepSetValue(impressionObject, 'floor.value', floor.value) - deepSetValue(impressionObject, 'floor.currency', floor.currency) + deepSetValue(impressionObject, 'floor.value', floor.value); + deepSetValue(impressionObject, 'floor.currency', floor.currency); } } @@ -322,7 +328,7 @@ function getPrebidResponseBidObject(openRTBResponseBidObject) { deepSetValue(prebidResponseBidObject, 'currency', openRTBResponseBidObject.cur ? openRTBResponseBidObject.cur.toUpperCase() : DEFAULT_CURRENCY); deepSetValue(prebidResponseBidObject, 'width', openRTBResponseBidObject.w); deepSetValue(prebidResponseBidObject, 'height', openRTBResponseBidObject.h); - deepSetValue(prebidResponseBidObject, 'dealId', openRTBResponseBidObject.dealid) + deepSetValue(prebidResponseBidObject, 'dealId', openRTBResponseBidObject.dealid); deepSetValue(prebidResponseBidObject, 'netRevenue', true); deepSetValue(prebidResponseBidObject, 'ttl', 60000); @@ -335,13 +341,13 @@ function getPrebidResponseBidObject(openRTBResponseBidObject) { deepSetValue(prebidResponseBidObject, 'mediaType', BANNER); deepSetValue(prebidResponseBidObject, 'ad', openRTBResponseBidObject.adm); } - setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) - return prebidResponseBidObject + setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject); + return prebidResponseBidObject; } function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) { logInfo('AIDEM Bid Adapter meta', openRTBResponseBidObject); - deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', openRTBResponseBidObject.adomain); + deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', deepAccess(openRTBResponseBidObject, 'meta.advertiserDomains')); if (openRTBResponseBidObject.cat && Array.isArray(openRTBResponseBidObject.cat)) { const primaryCatId = openRTBResponseBidObject.cat.shift(); deepSetValue(prebidResponseBidObject, 'meta.primaryCatId', primaryCatId); @@ -357,28 +363,28 @@ function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponse } function hasValidMediaType(bidRequest) { - const supported = hasBannerMediaType(bidRequest) || hasVideoMediaType(bidRequest) + const supported = hasBannerMediaType(bidRequest) || hasVideoMediaType(bidRequest); if (!supported) { logError('AIDEM Bid Adapter: media type not supported', { bidder: BIDDER_CODE, code: ERROR_CODES.MEDIA_TYPE_NOT_SUPPORTED }); } - return supported + return supported; } function hasBannerMediaType(bidRequest) { - return !!deepAccess(bidRequest, 'mediaTypes.banner') + return !!deepAccess(bidRequest, 'mediaTypes.banner'); } function hasVideoMediaType(bidRequest) { - return !!deepAccess(bidRequest, 'mediaTypes.video') + return !!deepAccess(bidRequest, 'mediaTypes.video'); } function hasValidBannerMediaType(bidRequest) { - const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes') + const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); if (!sizes) { logError('AIDEM Bid Adapter: media type sizes missing', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); return false; } - return true + return true; } function hasValidVideoMediaType(bidRequest) { @@ -387,23 +393,38 @@ function hasValidVideoMediaType(bidRequest) { logError('AIDEM Bid Adapter: media type playerSize missing', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); return false; } - return true + return true; } function hasValidVideoParameters(bidRequest) { - let valid = true + let valid = true; const adUnitsParameters = deepAccess(bidRequest, 'mediaTypes.video'); const bidderParameter = deepAccess(bidRequest, 'params.video'); for (let property of REQUIRED_VIDEO_PARAMS) { - const hasAdUnitParameter = adUnitsParameters.hasOwnProperty(property) - const hasBidderParameter = bidderParameter && bidderParameter.hasOwnProperty(property) + const hasAdUnitParameter = adUnitsParameters.hasOwnProperty(property); + const hasBidderParameter = bidderParameter && bidderParameter.hasOwnProperty(property); if (!hasAdUnitParameter && !hasBidderParameter) { logError(`AIDEM Bid Adapter: ${property} is not included in either the adunit or params level`, { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); - valid = false + valid = false; } } - return valid + return valid; +} + +function passesRateLimit(bidRequest) { + const rateLimit = deepAccess(bidRequest, 'params.rateLimit', 1); + if (!isNumber(rateLimit) || rateLimit > 1 || rateLimit < 0) { + logError('AIDEM Bid Adapter: invalid rateLimit (must be a number between 0 and 1)', { bidder: BIDDER_CODE, code: ERROR_CODES.INVALID_RATELIMIT }); + return false; + } + if (rateLimit !== 1) { + const randomRateValue = Math.random(); + if (randomRateValue > rateLimit) { + return false; + } + } + return true; } function hasValidParameters(bidRequest) { @@ -421,7 +442,7 @@ function hasValidParameters(bidRequest) { return false; } - return true + return true; } export const spec = { @@ -431,28 +452,32 @@ export const spec = { logInfo('bid: ', bidRequest); // check if request has valid mediaTypes - if (!hasValidMediaType(bidRequest)) return false + if (!hasValidMediaType(bidRequest)) return false; // check if request has valid media type parameters at adUnit level if (hasBannerMediaType(bidRequest) && !hasValidBannerMediaType(bidRequest)) { - return false + return false; } if (hasVideoMediaType(bidRequest) && !hasValidVideoMediaType(bidRequest)) { - return false + return false; } if (hasVideoMediaType(bidRequest) && !hasValidVideoParameters(bidRequest)) { - return false + return false; } - return hasValidParameters(bidRequest) + if (!hasValidParameters(bidRequest)) { + return false; + } + + return passesRateLimit(bidRequest); }, buildRequests: function(validBidRequests, bidderRequest) { logInfo('validBidRequests: ', validBidRequests); logInfo('bidderRequest: ', bidderRequest); - const prebidRequest = getPrebidRequestFields(bidderRequest, validBidRequests) + const prebidRequest = getPrebidRequestFields(bidderRequest, validBidRequests); const payloadString = JSON.stringify(prebidRequest); return { @@ -474,7 +499,7 @@ export const spec = { return; } logInfo('CPM OK'); - const bid = getPrebidResponseBidObject(bidObject) + const bid = getPrebidResponseBidObject(bidObject); bids.push(bid); }); return bids; @@ -483,14 +508,14 @@ export const spec = { onBidWon: function(bid) { // Bidder specific code logInfo('onBidWon bid: ', bid); - const notice = buildWinNotice(bid) + const notice = buildWinNotice(bid); ajax(endpoints.notice.win, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); }, onBidderError: function({ bidderRequest }) { // Bidder specific code - const notice = buildErrorNotice(bidderRequest) + const notice = buildErrorNotice(bidderRequest); ajax(endpoints.notice.error, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); }, -} +}; registerBidder(spec); diff --git a/modules/aidemBidAdapter.md b/modules/aidemBidAdapter.md index 342a264da01..b59014c76ed 100644 --- a/modules/aidemBidAdapter.md +++ b/modules/aidemBidAdapter.md @@ -14,11 +14,12 @@ This module is GDPR and CCPA compliant, and no 3rd party userIds are allowed. ## Global Bid Params -| Name | Scope | Description | Example | Type | -|---------------|----------|---------------------|---------------|----------| -| `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | -| `publisherId` | required | Unique publisher ID | `'ABCDEF'` | `String` | -| `placementId` | optional | Unique publisher tag ID | `'ABCDEF'` | `String` | +| Name | Scope | Description | Example | Type | +|---------------|----------|-------------------------|------------|----------| +| `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | +| `publisherId` | required | Unique publisher ID | `'ABCDEF'` | `String` | +| `placementId` | optional | Unique publisher tag ID | `'ABCDEF'` | `String` | +| `rateLimit` | optional | Limit the volume sent to AIDEM. Must be between 0 and 1 | `0.6` | `Number` | ### Banner Bid Params @@ -67,7 +68,8 @@ var adUnits = [{ bids: [{ bidder: 'aidem', params: { - siteId: 'prebid-test-site', + siteId: 'prebid-test-siteId', + publisherId: 'prebid-test-publisherId', }, }] }]; @@ -90,7 +92,8 @@ var adUnits = [{ bids: [{ bidder: 'aidem', params: { - siteId: 'prebid-test-site', + siteId: 'prebid-test-siteId', + publisherId: 'prebid-test-publisherId', }, }] }]; diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 71edfcf82fb..f58e49eb364 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -13,7 +13,7 @@ const VALID_BIDS = [ params: { siteId: '301491', publisherId: '3021491', - placementId: 13144370, + placementId: '13144370', }, mediaTypes: { banner: { @@ -26,7 +26,7 @@ const VALID_BIDS = [ params: { siteId: '301491', publisherId: '3021491', - placementId: 13144370, + placementId: '13144370', }, mediaTypes: { video: { @@ -110,7 +110,7 @@ const INVALID_BIDS = [ }, params: { siteId: '301491', - placementId: 13144370, + placementId: '13144370', }, }, { @@ -126,7 +126,7 @@ const INVALID_BIDS = [ }, params: { siteId: '301491', - placementId: 13144370, + placementId: '13144370', }, }, { @@ -143,7 +143,7 @@ const INVALID_BIDS = [ }, params: { siteId: '301491', - placementId: 13144370, + placementId: '13144370', video: { size: [480, 40] } @@ -167,8 +167,8 @@ const DEFAULT_VALID_BANNER_REQUESTS = [ } }, params: { - siteId: 1, - placementId: 13144370 + siteId: '1', + placementId: '13144370' }, src: 'client', transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c' @@ -192,8 +192,8 @@ const DEFAULT_VALID_VIDEO_REQUESTS = [ } }, params: { - siteId: 1, - placementId: 13144370 + siteId: '1', + placementId: '13144370' }, src: 'client', transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c' @@ -289,14 +289,25 @@ const WIN_NOTICE = { 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', - 'hb_adomain': 'tenutabene.it' + 'hb_adomain': 'example.com' }, + 'auctionId': '85864730-6cbc-4e56-bc3c-a4a6596dca5b', 'currency': [ 'USD' ], 'mediaType': 'banner', + 'advertiserDomains': [ + 'abc.com' + ], 'size': '300x250', + 'params': [ + { + 'placementId': '13144370', + 'siteId': '23434', + 'publisherId': '7689670753' + } + ], 'width': 300, 'height': 250, 'status': 'rendered', @@ -365,6 +376,62 @@ describe('Aidem adapter', () => { deepSetValue(validVideoRequest.params, 'video.size', [640, 480]) expect(spec.isBidRequestValid(validVideoRequest)).to.be.true }); + + it('BANNER: should return true if rateLimit is 1', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', 1) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.true + }); + + it('BANNER: should return false if rateLimit is 0', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', 0) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('BANNER: should return false if rateLimit is not between 0 and 1', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', 1.2) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('BANNER: should return false if rateLimit is not a number', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', '0.5') + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('VIDEO: should return true if rateLimit is 1', function () { + // spec.isBidRequestValid() + const validVideoRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validVideoRequest.params, 'rateLimit', 1) + expect(spec.isBidRequestValid(validVideoRequest)).to.be.true + }); + + it('VIDEO: should return false if rateLimit is 0', function () { + // spec.isBidRequestValid() + const validVideoRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validVideoRequest.params, 'rateLimit', 0) + expect(spec.isBidRequestValid(validVideoRequest)).to.be.false + }); + + it('VIDEO: should return false if rateLimit is not between 0 and 1', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validBannerRequest.params, 'rateLimit', 1.2) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('VIDEO: should return false if rateLimit is not a number', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validBannerRequest.params, 'rateLimit', '0.5') + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); }); describe('buildRequests', () => { From 3d3b0d7dcdd18e67ca6a168275bc49a276af1580 Mon Sep 17 00:00:00 2001 From: Maxim Schuwalow <16665913+mschuwalow@users.noreply.github.com> Date: Mon, 6 Feb 2023 15:43:08 +0100 Subject: [PATCH 325/367] LiveIntent Id module: Update live-connect-js version (#9505) * Update live-connect-js version * fix eslint comment --- modules/liveIntentIdSystem.js | 2 +- package-lock.json | 14 +++++++------- package.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/liveIntentIdSystem.js b/modules/liveIntentIdSystem.js index de70b0eaccd..9f45daeea29 100644 --- a/modules/liveIntentIdSystem.js +++ b/modules/liveIntentIdSystem.js @@ -7,7 +7,7 @@ import { triggerPixel, logError } from '../src/utils.js'; import { ajaxBuilder } from '../src/ajax.js'; import { submodule } from '../src/hook.js'; -import { LiveConnect } from 'live-connect-js/esm/initializer.js'; +import { LiveConnect } from 'live-connect-js'; // eslint-disable-line prebid/validate-imports import { gdprDataHandler, uspDataHandler } from '../src/adapterManager.js'; import { getStorageManager } from '../src/storageManager.js'; diff --git a/package-lock.json b/package-lock.json index 587b7897394..dca60dbf37e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "express": "^4.15.4", "fun-hooks": "^0.9.9", "just-clone": "^1.0.2", - "live-connect-js": "3.0.5" + "live-connect-js": "^4.0.0" }, "devDependencies": { "@babel/eslint-parser": "^7.16.5", @@ -16229,9 +16229,9 @@ "dev": true }, "node_modules/live-connect-js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-3.0.5.tgz", - "integrity": "sha512-KqxE+V/050nK2tUx8PnAtQBOK4E29WVasQTrLkkCwSebmV5uqMu+VMcwhJSbnyh/g+GhDAE/LL9RB6X9vcmLrg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-4.0.0.tgz", + "integrity": "sha512-uycBgFBdEwSq95NImrsOSkTlszUMTGf8luK9GZDWw4D+DL5yFNnCPcrjxUk15U9n9aPmaM1SKmWH5qUXFr8aIA==", "dependencies": { "tiny-hashes": "1.0.1" }, @@ -37865,9 +37865,9 @@ "dev": true }, "live-connect-js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-3.0.5.tgz", - "integrity": "sha512-KqxE+V/050nK2tUx8PnAtQBOK4E29WVasQTrLkkCwSebmV5uqMu+VMcwhJSbnyh/g+GhDAE/LL9RB6X9vcmLrg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-4.0.0.tgz", + "integrity": "sha512-uycBgFBdEwSq95NImrsOSkTlszUMTGf8luK9GZDWw4D+DL5yFNnCPcrjxUk15U9n9aPmaM1SKmWH5qUXFr8aIA==", "requires": { "tiny-hashes": "1.0.1" } diff --git a/package.json b/package.json index cf3a7703aac..7163c732634 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "express": "^4.15.4", "fun-hooks": "^0.9.9", "just-clone": "^1.0.2", - "live-connect-js": "3.0.5" + "live-connect-js": "^4.0.0" }, "optionalDependencies": { "fsevents": "^2.3.2" From d694fe01fe9781ceecb41d71508638a733d1f61b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udi=20Talias=20=E2=9A=9B=EF=B8=8F?= Date: Mon, 6 Feb 2023 16:44:42 +0200 Subject: [PATCH 326/367] Vidazoo Bid Adapter - webSessionId request param (#9504) * feat(module): multi size request * fix getUserSyncs added tests * update(module): package-lock.json from master * feat(module): VidazooBidAdapter - send top query params to server * Vidazoo Bid Adapter - added webSessionId to request --------- Co-authored-by: roman Co-authored-by: Saar Amrani <89377180+saar120@users.noreply.github.com> Co-authored-by: Saar Amrani --- modules/vidazooBidAdapter.js | 4 +++- test/spec/modules/vidazooBidAdapter_spec.js | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index 96dcc182436..3f3bb66d8ae 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -27,6 +27,7 @@ export const SUPPORTED_ID_SYSTEMS = { 'tdid': 1, 'pubProvidedId': 1 }; +export const webSessionId = 'wsid_' + parseInt(Date.now() * Math.random()); const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE}); function getTopWindowQueryParams() { @@ -131,7 +132,8 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { bidRequestsCount: bidRequestsCount, bidderRequestsCount: bidderRequestsCount, bidderWinsCount: bidderWinsCount, - bidderTimeout: bidderTimeout + bidderTimeout: bidderTimeout, + webSessionId: webSessionId }; appendUserIdsToRequestPayload(data, userId); diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index 134e3e66256..24d565805d3 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -13,6 +13,7 @@ import { getUniqueDealId, getNextDealId, getVidazooSessionId, + webSessionId } from 'modules/vidazooBidAdapter.js'; import * as utils from 'src/utils.js'; import {version} from 'package.json'; @@ -283,6 +284,7 @@ describe('VidazooBidAdapter', function () { uniqueDealId: `${hashUrl}_${Date.now().toString()}`, uqs: getTopWindowQueryParams(), isStorageAllowed: true, + webSessionId: webSessionId, mediaTypes: { video: { api: [2], @@ -350,7 +352,8 @@ describe('VidazooBidAdapter', function () { isStorageAllowed: true, gpid: '1234567890', cat: ['IAB2'], - pagecat: ['IAB2-2'] + pagecat: ['IAB2-2'], + webSessionId: webSessionId } }); }); From 2d31a525ac1659a5d4ccd1aa1d5921e826ba70be Mon Sep 17 00:00:00 2001 From: anthonyjl92 Date: Mon, 6 Feb 2023 09:46:12 -0500 Subject: [PATCH 327/367] pass referer to ortb request (#9475) Co-authored-by: Anthony Lin --- modules/33acrossBidAdapter.js | 17 +++-- test/spec/modules/33acrossBidAdapter_spec.js | 69 +++++++++++++++----- 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/modules/33acrossBidAdapter.js b/modules/33acrossBidAdapter.js index d9524a281f8..e9901794ff9 100644 --- a/modules/33acrossBidAdapter.js +++ b/modules/33acrossBidAdapter.js @@ -167,7 +167,8 @@ function buildRequests(bidRequests, bidderRequest) { ttxSettings, gdprConsent, uspConsent, - pageUrl + pageUrl, + referer } = _buildRequestParams(bidRequests, bidderRequest); const groupedRequests = _buildRequestGroups(ttxSettings, bidRequests); @@ -181,6 +182,7 @@ function buildRequests(bidRequests, bidderRequest) { gdprConsent, uspConsent, pageUrl, + referer, ttxSettings }) ) @@ -199,7 +201,9 @@ function _buildRequestParams(bidRequests, bidderRequest) { const uspConsent = bidderRequest && bidderRequest.uspConsent; - const pageUrl = bidderRequest?.refererInfo?.page + const pageUrl = bidderRequest?.refererInfo?.page; + + const referer = bidderRequest?.refererInfo?.ref; adapterState.uniqueSiteIds = bidRequests.map(req => req.params.siteId).filter(uniques); @@ -207,7 +211,8 @@ function _buildRequestParams(bidRequests, bidderRequest) { ttxSettings, gdprConsent, uspConsent, - pageUrl + pageUrl, + referer } } @@ -241,7 +246,7 @@ function _getMRAKey(bidRequest) { } // Infer the necessary data from valid bid for a minimal ttxRequest and create HTTP request -function _createServerRequest({ bidRequests, gdprConsent = {}, uspConsent, pageUrl, ttxSettings }) { +function _createServerRequest({ bidRequests, gdprConsent = {}, uspConsent, pageUrl, referer, ttxSettings }) { const ttxRequest = {}; const firstBidRequest = bidRequests[0]; const { siteId, test } = firstBidRequest.params; @@ -262,6 +267,10 @@ function _createServerRequest({ bidRequests, gdprConsent = {}, uspConsent, pageU ttxRequest.site.page = pageUrl; } + if (referer) { + ttxRequest.site.ref = referer; + } + ttxRequest.id = firstBidRequest.auctionId; if (gdprConsent.consentString) { diff --git a/test/spec/modules/33acrossBidAdapter_spec.js b/test/spec/modules/33acrossBidAdapter_spec.js index 2680544d00b..3b3c05660df 100644 --- a/test/spec/modules/33acrossBidAdapter_spec.js +++ b/test/spec/modules/33acrossBidAdapter_spec.js @@ -218,6 +218,14 @@ describe('33acrossBidAdapter:', function () { return this; }; + this.withReferer = referer => { + Object.assign(ttxRequest.site, { + ref: referer + }); + + return this; + }; + this.withSchain = schain => { Object.assign(ttxRequest, { source: { @@ -1187,26 +1195,51 @@ describe('33acrossBidAdapter:', function () { }); }); - context('when referer value is available', function() { - it('returns corresponding server requests with site.page set', function() { - const bidderRequest = { - refererInfo: { - page: 'http://foo.com/bar' - } - }; + context('when refererInfo values are available', function() { + context('when refererInfo.page is defined', function() { + it('returns corresponding server requests with site.page set', function() { + const bidderRequest = { + refererInfo: { + page: 'http://foo.com/bar' + } + }; - const ttxRequest = new TtxRequestBuilder() - .withBanner() - .withProduct() - .withPageUrl('http://foo.com/bar') - .build(); - const serverRequest = new ServerRequestBuilder() - .withData(ttxRequest) - .build(); + const ttxRequest = new TtxRequestBuilder() + .withBanner() + .withProduct() + .withPageUrl('http://foo.com/bar') + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); - const [ builtServerRequest ] = spec.buildRequests(bidRequests, bidderRequest); + const [ builtServerRequest ] = spec.buildRequests(bidRequests, bidderRequest); - validateBuiltServerRequest(builtServerRequest, serverRequest); + validateBuiltServerRequest(builtServerRequest, serverRequest); + }); + }); + + context('when refererInfo.ref is defined', function() { + it('returns corresponding server requests with site.ref set', function() { + const bidderRequest = { + refererInfo: { + ref: 'google.com' + } + }; + + const ttxRequest = new TtxRequestBuilder() + .withBanner() + .withProduct() + .withReferer('google.com') + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + + const [ builtServerRequest ] = spec.buildRequests(bidRequests, bidderRequest); + + validateBuiltServerRequest(builtServerRequest, serverRequest); + }); }); }); @@ -1246,7 +1279,7 @@ describe('33acrossBidAdapter:', function () { }); context('when referer value is not available', function() { - it('returns corresponding server requests without site.page set', function() { + it('returns corresponding server requests without site.page and site.ref set', function() { const bidderRequest = { refererInfo: {} }; From e5d1c92259d6af59d8b756cbd03312f3d14df245 Mon Sep 17 00:00:00 2001 From: Scott Floam Date: Mon, 6 Feb 2023 11:46:45 -0500 Subject: [PATCH 328/367] Freewheel SSP Bid Adapter: bugfix for schain (#9492) * freewheel-sspBidAdapter: Bug Fix for schain (#9471) * Fixed schain logic to parse schain as string * Updated schain test to check schain string * Update freewheel-sspBidAdapter.js * kickoff tests --------- Co-authored-by: Scott Floam Co-authored-by: Patrick McCann Co-authored-by: Chris Huie --- modules/freewheel-sspBidAdapter.js | 6 +++++- test/spec/modules/freewheel-sspBidAdapter_spec.js | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/freewheel-sspBidAdapter.js b/modules/freewheel-sspBidAdapter.js index 764e3d6e6c0..b4d8f69d1b4 100644 --- a/modules/freewheel-sspBidAdapter.js +++ b/modules/freewheel-sspBidAdapter.js @@ -348,7 +348,11 @@ export const spec = { // Add schain object var schain = currentBidRequest.schain; if (schain) { - requestParams.schain = schain; + try { + requestParams.schain = JSON.stringify(schain); + } catch (error) { + logWarn('PREBID - ' + BIDDER_CODE + ': Unable to stringify the schain: ' + error); + } } var vastParams = currentBidRequest.params.vastUrlParams; diff --git a/test/spec/modules/freewheel-sspBidAdapter_spec.js b/test/spec/modules/freewheel-sspBidAdapter_spec.js index 7ef576fc7ec..d1e0b055239 100644 --- a/test/spec/modules/freewheel-sspBidAdapter_spec.js +++ b/test/spec/modules/freewheel-sspBidAdapter_spec.js @@ -128,7 +128,7 @@ describe('freewheelSSP BidAdapter Test', () => { it('should return a properly formatted request with schain defined', function () { const request = spec.buildRequests(bidRequests); const payload = request[0].data; - expect(payload.schain).to.deep.equal(bidRequests[0].schain) + expect(payload.schain).to.deep.equal('{\"ver\":\"1.0\",\"complete\":1,\"nodes\":[{\"asi\":\"example.com\",\"sid\":\"0\",\"hp\":1,\"rid\":\"bidrequestid\",\"domain\":\"example.com\"}]}'); }); it('sends bid request to ENDPOINT via GET', () => { From d984cd865906fdfbdebdbfa7ff7ebbe9a215c486 Mon Sep 17 00:00:00 2001 From: Muki Seiler Date: Tue, 7 Feb 2023 15:25:43 +0100 Subject: [PATCH 329/367] Add GVLID to smartx (#9512) --- modules/smartxBidAdapter.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/smartxBidAdapter.js b/modules/smartxBidAdapter.js index bfc664180a3..d91b62729bc 100644 --- a/modules/smartxBidAdapter.js +++ b/modules/smartxBidAdapter.js @@ -10,8 +10,10 @@ import { } from '../src/mediaTypes.js'; const BIDDER_CODE = 'smartx'; const URL = 'https://bid.sxp.smartclip.net/bid/1000'; +const GVLID = 115; export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: [VIDEO], /** * Determines whether or not the given bid request is valid. From 58d79e5291ded734b36d106d2bfb14a0db685d82 Mon Sep 17 00:00:00 2001 From: Tomasz Kogut Date: Tue, 7 Feb 2023 17:46:43 +0100 Subject: [PATCH 330/367] Scattered Bid Adapter: New Adapter (#9295) * Scattered module skeleton * Review fixes * Remove netRevenue check * Fix test * Review fixes --- modules/scatteredBidAdapter.js | 72 ++++++ modules/scatteredBidAdapter.md | 36 +++ test/spec/modules/scatteredBidAdapter_spec.js | 210 ++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 modules/scatteredBidAdapter.js create mode 100644 modules/scatteredBidAdapter.md create mode 100644 test/spec/modules/scatteredBidAdapter_spec.js diff --git a/modules/scatteredBidAdapter.js b/modules/scatteredBidAdapter.js new file mode 100644 index 00000000000..47dc09cd1b2 --- /dev/null +++ b/modules/scatteredBidAdapter.js @@ -0,0 +1,72 @@ +// jshint esversion: 6, es3: false, node: true +'use strict'; + +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { deepAccess, logInfo } from '../src/utils.js'; +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; + +const BIDDER_CODE = 'scattered'; +const GVLID = 1179; +export const converter = ortbConverter({ + context: { + mediaType: BANNER, + ttl: 360, + netRevenue: true + } +}) + +export const spec = { + code: BIDDER_CODE, + gvlid: GVLID, + supportedMediaTypes: [BANNER], + + // 1. + isBidRequestValid: function (bid) { + const bidderDomain = deepAccess(bid, 'params.bidderDomain') + if (bidderDomain === undefined || bidderDomain === '') { + return false + } + + const sizes = deepAccess(bid, 'mediaTypes.banner.sizes') + if (sizes === undefined || sizes.length < 1) { + return false + } + + return true + }, + + // 2. + buildRequests: function (bidRequests, bidderRequest) { + return { + method: 'POST', + url: 'https://' + getKeyOnAny(bidRequests, 'params.bidderDomain'), + data: converter.toORTB({ bidderRequest, bidRequests }), + options: { + contentType: 'application/json' + }, + }; + }, + + // 3. + interpretResponse: function (response, request) { + if (!response.body) return; + return converter.fromORTB({ response: response.body, request: request.data }).bids; + }, + + // 4 + onBidWon: function (bid) { + logInfo('onBidWon', bid) + } +} + +function getKeyOnAny(collection, key) { + for (let i = 0; i < collection.length; i++) { + const result = deepAccess(collection[i], key); + if (result) { + return result; + } + } +} + +registerBidder(spec); diff --git a/modules/scatteredBidAdapter.md b/modules/scatteredBidAdapter.md new file mode 100644 index 00000000000..031d953e32b --- /dev/null +++ b/modules/scatteredBidAdapter.md @@ -0,0 +1,36 @@ +# Overview + +``` +Module Name: Scattered Adapter +Module Type: Bidder Adapter +Maintainer: office@scattered.pl +``` + +# Description + +Module that connects to Scattered's demand sources. +It uses OpenRTB standard to communicate between the adapter and bidding servers. + +# Test Parameters + +```javascript + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[300, 250]], // a display size + } + }, + bids: [ + { + bidder: "scattered", + params: { + bidderDomain: "prebid-test.scattered.eu/bid", + test: 0 + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/test/spec/modules/scatteredBidAdapter_spec.js b/test/spec/modules/scatteredBidAdapter_spec.js new file mode 100644 index 00000000000..609a570f579 --- /dev/null +++ b/test/spec/modules/scatteredBidAdapter_spec.js @@ -0,0 +1,210 @@ +import { spec, converter } from 'modules/scatteredBidAdapter.js'; +import { assert } from 'chai'; +import { config } from 'src/config.js'; +import { deepClone, mergeDeep } from '../../../src/utils'; +describe('Scattered adapter', function () { + describe('isBidRequestValid', function () { + // A valid bid + let validBid = { + bidder: 'scattered', + mediaTypes: { + banner: { + sizes: [[300, 250], [760, 400]] + } + }, + params: { + bidderDomain: 'https://prebid.scattered.eu', + test: 0 + } + }; + + // Because this valid bid is modified to create invalid bids in following tests we first check it. + // We must be sure it is a valid one, not to get false negatives. + it('should accept a valid bid', function () { + assert.isTrue(spec.isBidRequestValid(validBid)); + }); + + it('should skip if bidderDomain info is missing', function () { + let bid = deepClone(validBid); + + delete bid.params.bidderDomain; + assert.isFalse(spec.isBidRequestValid(bid)); + }); + + it('should expect at least one banner size', function () { + let bid = deepClone(validBid); + + delete bid.mediaTypes.banner; + assert.isFalse(spec.isBidRequestValid(bid)); + + // empty sizes array + bid.mediaTypes = { + banner: { + sizes: [] + } + }; + assert.isFalse(spec.isBidRequestValid(bid)); + }); + }); + + describe('buildRequests', function () { + let arrayOfValidBidRequests, validBidderRequest; + + beforeEach(function () { + arrayOfValidBidRequests = [{ + bidder: 'scattered', + params: { + bidderDomain: 'https://prebid.scattered.eu', + test: 0 + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [760, 400]] + }, + adUnitCode: 'test-div', + transactionId: '32d09c47-c6b8-40b0-9605-2e251a472ea4', + bidId: '21adc5d8765aa1', + bidderRequestId: '130728f7662afc', + auctionId: 'b4a45a23-8371-4d87-9308-39146b29ca32', + }, + }]; + + validBidderRequest = { + bidderCode: 'scattered', + auctionId: 'b4a45a23-8371-4d87-9308-39146b29ca32', + gdprConsent: { consentString: 'BOtmiBKOtmiBKABABAENAFAAAAACeAAA', gdprApplies: true }, + refererInfo: { + domain: 'localhost', + page: 'http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true', + }, + ortb2: { + site: { + publisher: { + name: 'publisher1 INC.' + } + } + } + }; + }); + + it('should validate request format', function () { + let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); + assert.equal(request.method, 'POST'); + assert.deepEqual(request.options, { contentType: 'application/json' }); + assert.ok(request.data); + }); + + it('has the right fields filled', function () { + let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); + const bidderRequest = request.data; + assert.equal(bidderRequest.id, validBidderRequest.auctionId); + assert.ok(bidderRequest.site); + assert.ok(bidderRequest.device); + assert.ok(bidderRequest.source); + assert.lengthOf(bidderRequest.imp, 1); + }); + + it('should configure the site object', function () { + let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); + const site = request.data.site; + assert.equal(site.domain, 'localhost'); + assert.equal(site.page, 'http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true'); + }); + + it('should configure site with ortb2', function () { + mergeDeep(validBidderRequest.ortb2.site, { + id: '876', + publisher: { + domain: 'publisher1.eu' + } + }); + + let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); + const site = request.data.site; + assert.deepEqual(site, { + domain: 'localhost', + id: '876', + page: 'http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true', + publisher: { + domain: 'publisher1.eu', + name: 'publisher1 INC.' + } + }); + }); + + it('should send device info', function () { + it('should send info about device', function () { + config.setConfig({ + device: { w: 375, h: 273 } + }); + + let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); + + assert.equal(request.device.ua, navigator.userAgent); + assert.equal(request.device.w, 375); + assert.equal(request.device.h, 273); + }); + }) + }) +}) + +describe('interpretResponse', function () { + const serverResponse = { + body: { + id: 'b4a45a23-8371-4d87-9308-39146b29ca32', + bidid: '11111111-2222-2222-2222-333333333333', + cur: 'PLN', + seatbid: [{ + bid: [ + { + id: '234234-234234-234234', // bidder generated + impid: '123', + price: '34.2', + nurl: 'https://scattered.eu/nurl', + adm: '
', + cpm: '34.2', + creativeId: '2345-2345-23', + currency: 'PLN', + height: 456, + width: 345, + mediaType: 'banner', + requestId: '123', + ttl: 360, + }; + expect(results.length).to.equal(1); + sinon.assert.match(results[0], expected); + }); +}); From 324764f91072ef65e77b15f88e05252f4a7b08f9 Mon Sep 17 00:00:00 2001 From: Nick Jacob Date: Tue, 7 Feb 2023 13:38:04 -0500 Subject: [PATCH 331/367] update amxIdSystem (#9508) --- modules/amxIdSystem.md | 12 ++---------- modules/aolBidAdapter.js | 2 +- modules/userId/eids.js | 2 +- modules/yahoosspBidAdapter.js | 2 +- test/spec/modules/aolBidAdapter_spec.js | 4 ++-- test/spec/modules/eids_spec.js | 2 +- test/spec/modules/tripleliftBidAdapter_spec.js | 4 ++-- test/spec/modules/userId_spec.js | 2 +- test/spec/modules/yahoosspBidAdapter_spec.js | 2 +- 9 files changed, 12 insertions(+), 20 deletions(-) diff --git a/modules/amxIdSystem.md b/modules/amxIdSystem.md index 9de93c761a1..f67fefe261e 100644 --- a/modules/amxIdSystem.md +++ b/modules/amxIdSystem.md @@ -1,6 +1,6 @@ -# AMX RTB ID +# AMX ID -For help adding this module, please contact [prebid@amxrtb.com](prebid@amxrtb.com). +For help adding this module, please contact [info@amxdt.net](info@amxdt.net). ### Prebid Configuration @@ -41,11 +41,3 @@ The following settings are available for the `storage` property in the `userSync | name | Required | String | Where the ID will be stored | `"amxId"` | | type | Required | String | This must be `"html5"` | `"html5"` | | expires | Required | Number <= 30 | number of days until the stored ID expires. **Must be less than or equal to 30** | `14` | - -### Params - -The following options are available in the `params` property in `userSync.userIds[]`: - -| Param under `params` | Scope | Type | Description | Example | -| -------------------- | -------- | ------ | ------------------------------------------------------------------------- | ---------------- | -| tagId | Optional | String | Your AMX tagId (optional) | `cHJlYmlkLm9yZw` | diff --git a/modules/aolBidAdapter.js b/modules/aolBidAdapter.js index 6b471ac6de2..d15a5434e0c 100644 --- a/modules/aolBidAdapter.js +++ b/modules/aolBidAdapter.js @@ -35,7 +35,7 @@ const SUPPORTED_USER_ID_SOURCES = [ 'adserver.org', 'adtelligent.com', 'akamai.com', - 'amxrtb.com', + 'amxdt.net', 'audigent.com', 'britepool.com', 'criteo.com', diff --git a/modules/userId/eids.js b/modules/userId/eids.js index bae5071e4b2..199168e12bb 100644 --- a/modules/userId/eids.js +++ b/modules/userId/eids.js @@ -282,7 +282,7 @@ export const USER_IDS_CONFIG = { }, amxId: { - source: 'amxrtb.com', + source: 'amxdt.net', atype: 1, }, diff --git a/modules/yahoosspBidAdapter.js b/modules/yahoosspBidAdapter.js index 9dd635a990f..40677f90064 100644 --- a/modules/yahoosspBidAdapter.js +++ b/modules/yahoosspBidAdapter.js @@ -24,7 +24,7 @@ const SUPPORTED_USER_ID_SOURCES = [ 'adserver.org', 'adtelligent.com', 'akamai.com', - 'amxrtb.com', + 'amxdt.net', 'audigent.com', 'britepool.com', 'criteo.com', diff --git a/test/spec/modules/aolBidAdapter_spec.js b/test/spec/modules/aolBidAdapter_spec.js index 471c76f55cf..92246f76c7a 100644 --- a/test/spec/modules/aolBidAdapter_spec.js +++ b/test/spec/modules/aolBidAdapter_spec.js @@ -84,7 +84,7 @@ describe('AolAdapter', function () { 'admixer.net': '100', 'adserver.org': '200', 'adtelligent.com': '300', - 'amxrtb.com': '500', + 'amxdt.net': '500', 'audigent.com': '600', 'britepool.com': '700', 'criteo.com': '800', @@ -110,7 +110,7 @@ describe('AolAdapter', function () { const USER_ID_DATA = { admixerId: SUPPORTED_USER_ID_SOURCES['admixer.net'], adtelligentId: SUPPORTED_USER_ID_SOURCES['adtelligent.com'], - amxId: SUPPORTED_USER_ID_SOURCES['amxrtb.com'], + amxId: SUPPORTED_USER_ID_SOURCES['amxdt.net'], britepoolid: SUPPORTED_USER_ID_SOURCES['britepool.com'], criteoId: SUPPORTED_USER_ID_SOURCES['criteo.com'], connectid: SUPPORTED_USER_ID_SOURCES['verizonmedia.com'], diff --git a/test/spec/modules/eids_spec.js b/test/spec/modules/eids_spec.js index 78c8f2b3148..13f89b054bd 100644 --- a/test/spec/modules/eids_spec.js +++ b/test/spec/modules/eids_spec.js @@ -392,7 +392,7 @@ describe('eids array generation for known sub-modules', function() { const [eid] = createEidsArray(userId); expect(eid).to.deep.equal({ - source: 'amxrtb.com', + source: 'amxdt.net', uids: [{ atype: 1, id, diff --git a/test/spec/modules/tripleliftBidAdapter_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js index 0447cb4d5d6..a20719d89e5 100644 --- a/test/spec/modules/tripleliftBidAdapter_spec.js +++ b/test/spec/modules/tripleliftBidAdapter_spec.js @@ -725,11 +725,11 @@ describe('triplelift adapter', function () { it('should add amxRtbId to the payload if included', function () { const id = 'Ok9JQkBM-UFlAXEZQ-UUNBQlZOQzgrUFhW-UUNBQkRQTUBPQVpVWVxNXlZUUF9AUFhAUF9PXFY/'; - bidRequests[0].userIdAsEids = [{ source: 'amxrtb.com', uids: [{ id }] }]; + bidRequests[0].userIdAsEids = [{ source: 'amxdt.net', uids: [{ id }] }]; const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); const payload = request.data; expect(payload).to.exist; - expect(payload.user).to.deep.equal({ext: {eids: [{source: 'amxrtb.com', uids: [{id, ext: {rtiPartner: 'amxrtb.com'}}]}]}}); + expect(payload.user).to.deep.equal({ext: {eids: [{source: 'amxdt.net', uids: [{id, ext: {rtiPartner: 'amxdt.net'}}]}]}}); }); it('should add tdid, idl_env and criteoId to the payload if both are included', function () { diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index 5403d842e02..bf27ef0ff81 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -1298,7 +1298,7 @@ describe('User ID', function () { expect(bid).to.have.deep.nested.property('userId.amxId'); expect(bid.userId.amxId).to.equal('test_amxid_id'); expect(bid.userIdAsEids[0]).to.deep.equal({ - source: 'amxrtb.com', + source: 'amxdt.net', uids: [{ id: 'test_amxid_id', atype: 1, diff --git a/test/spec/modules/yahoosspBidAdapter_spec.js b/test/spec/modules/yahoosspBidAdapter_spec.js index 01583ac30dc..a326b22ecb4 100644 --- a/test/spec/modules/yahoosspBidAdapter_spec.js +++ b/test/spec/modules/yahoosspBidAdapter_spec.js @@ -872,7 +872,7 @@ describe('YahooSSP Bid Adapter:', () => { expect(data.user.ext.eids).to.deep.equal([ {source: 'admixer.net', uids: [{id: 'admixerId_FROM_USER_ID_MODULE', atype: 3}]}, {source: 'adtelligent.com', uids: [{id: 'adtelligentId_FROM_USER_ID_MODULE', atype: 3}]}, - {source: 'amxrtb.com', uids: [{id: 'amxId_FROM_USER_ID_MODULE', atype: 1}]}, + {source: 'amxdt.net', uids: [{id: 'amxId_FROM_USER_ID_MODULE', atype: 1}]}, {source: 'britepool.com', uids: [{id: 'britepoolid_FROM_USER_ID_MODULE', atype: 3}]}, {source: 'deepintent.com', uids: [{id: 'deepintentId_FROM_USER_ID_MODULE', atype: 3}]}, {source: 'epsilon.com', uids: [{id: 'publinkId_FROM_USER_ID_MODULE', atype: 3}]}, From ec182d0e974c6b745855b259e9655fb23a7be044 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 7 Feb 2023 12:34:19 -0700 Subject: [PATCH 332/367] Scattered bid adapter: fix tests (#9514) --- test/spec/modules/scatteredBidAdapter_spec.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/spec/modules/scatteredBidAdapter_spec.js b/test/spec/modules/scatteredBidAdapter_spec.js index 609a570f579..7f0b13bc07b 100644 --- a/test/spec/modules/scatteredBidAdapter_spec.js +++ b/test/spec/modules/scatteredBidAdapter_spec.js @@ -99,7 +99,6 @@ describe('Scattered adapter', function () { const bidderRequest = request.data; assert.equal(bidderRequest.id, validBidderRequest.auctionId); assert.ok(bidderRequest.site); - assert.ok(bidderRequest.device); assert.ok(bidderRequest.source); assert.lengthOf(bidderRequest.imp, 1); }); @@ -107,24 +106,25 @@ describe('Scattered adapter', function () { it('should configure the site object', function () { let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); const site = request.data.site; - assert.equal(site.domain, 'localhost'); - assert.equal(site.page, 'http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true'); + assert.equal(site.publisher.name, validBidderRequest.ortb2.site.publisher.name) }); it('should configure site with ortb2', function () { - mergeDeep(validBidderRequest.ortb2.site, { - id: '876', - publisher: { - domain: 'publisher1.eu' + const req = mergeDeep({}, validBidderRequest, { + ortb2: { + site: { + id: '876', + publisher: { + domain: 'publisher1.eu' + } + } } }); - let request = spec.buildRequests(arrayOfValidBidRequests, validBidderRequest); + let request = spec.buildRequests(arrayOfValidBidRequests, req); const site = request.data.site; assert.deepEqual(site, { - domain: 'localhost', id: '876', - page: 'http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true', publisher: { domain: 'publisher1.eu', name: 'publisher1 INC.' From 723560d7b1e9d59f6c5458d16decc3ece1a3d568 Mon Sep 17 00:00:00 2001 From: moquity <33487117+moquity@users.noreply.github.com> Date: Tue, 7 Feb 2023 22:20:27 +0200 Subject: [PATCH 333/367] Neuwo RTD Module : initial release (#9385) * added neuwoRtdProvider.js (implementation), integration test spec, initial description document (neuwoRtdProvider.md) * neuwoRtdProvider finish: added _example.html using https://docs.prebid.org/dev-docs/examples/basic-example.html improved neuwoRtdProvider logging and error handling improved neuwoRtdProvider.md testing steps * neuwoRtdProvider.js -> updated to convert response using IAB to Tax ID conversion dictionary +tests, finished "no response" test * neuwoRtdProvider.js: added BILLABLE_EVENTs: 'auction' on getBidRequestData, 'request' on successful parse of neuwo request, 'general' on if global data actually extended using topics * review reflections: added injection into site.cattax, site.pagecat for "IAB 2.2", clarified conversion code conversion dictionary comment to include IAB 2+ - added tests to further ensure endpoint response malformation handling robustness * neuwoRtdProvider.js -> updated segtax code to compatible non-deprecated version (2.0 -> to 2.2, used conversion table is the same) * neuwoRtdProvider.js -> reduced: - amount and mutability of variables (const) - responsibility of injectTopics, callback lifted into callbacks of the ajax call - amount of billable events, on api call success only (expects marketing_categories) --- .../gpt/neuwoRtdProvider_example.html | 190 ++++++++++++++++++ modules/neuwoRtdProvider.js | 171 ++++++++++++++++ modules/neuwoRtdProvider.md | 40 ++++ test/spec/modules/neuwoRtdProvider_spec.js | 123 ++++++++++++ 4 files changed, 524 insertions(+) create mode 100644 integrationExamples/gpt/neuwoRtdProvider_example.html create mode 100644 modules/neuwoRtdProvider.js create mode 100644 modules/neuwoRtdProvider.md create mode 100644 test/spec/modules/neuwoRtdProvider_spec.js diff --git a/integrationExamples/gpt/neuwoRtdProvider_example.html b/integrationExamples/gpt/neuwoRtdProvider_example.html new file mode 100644 index 00000000000..f33b9f94c67 --- /dev/null +++ b/integrationExamples/gpt/neuwoRtdProvider_example.html @@ -0,0 +1,190 @@ + + + + + + + + + + +

Basic Prebid.js Example using neuwoRtdProvider

+
+ Looks like you're not following the testing environment setup, try accessing http://localhost:9999/integrationExamples/gpt/neuwoRtdProvider_example.html + after running commands in the prebid.js source folder that includes libraries/modules/neuwoRtdProvider.js + + npm ci + npm i -g gulp-cli + gulp serve --modules=rtdModule,neuwoRtdProvider,appnexusBidAdapter + +
+
+

Add token and url to use for Neuwo extension configuration

+ + + +
+ +
Div-1
+
+ Ad spot div-1: This content will be replaced by prebid.js and/or related components once you click "Update" +
+ +
+ +
Div-2
+
+ Ad spot div-2: Replaces this text as well, if everything goes to plan + + +
+ + + \ No newline at end of file diff --git a/modules/neuwoRtdProvider.js b/modules/neuwoRtdProvider.js new file mode 100644 index 00000000000..a2549a243d1 --- /dev/null +++ b/modules/neuwoRtdProvider.js @@ -0,0 +1,171 @@ +import { deepAccess, deepSetValue, generateUUID, logError, logInfo, mergeDeep } from '../src/utils.js'; +import { getRefererInfo } from '../src/refererDetection.js'; +import { ajax } from '../src/ajax.js'; +import { submodule } from '../src/hook.js'; +import * as events from '../src/events.js'; +import CONSTANTS from '../src/constants.json'; + +export const DATA_PROVIDER = 'neuwo.ai'; +const SEGTAX_IAB = 6 // IAB - Content Taxonomy version 2 +const CATTAX_IAB = 6 // IAB Tech Lab Content Taxonomy 2.2 +const RESPONSE_IAB_TIER_1 = 'marketing_categories.iab_tier_1' +const RESPONSE_IAB_TIER_2 = 'marketing_categories.iab_tier_2' + +function init(config = {}, userConsent = '') { + config.params = config.params || {} + // ignore module if publicToken is missing (module setup failure) + if (!config.params.publicToken) { + logError('publicToken missing', 'NeuwoRTDModule', 'config.params.publicToken') + return false; + } + return true; +} + +export function getBidRequestData(reqBidsConfigObj, callback, config, userConsent) { + config.params = config.params || {}; + logInfo('NeuwoRTDModule', 'starting getBidRequestData') + + const wrappedArgUrl = encodeURIComponent(config.params.argUrl || getRefererInfo().page); + const url = 'https://m1apidev.neuwo.ai/edge/GetAiTopics?' + [ + 'token=' + config.params.publicToken, + 'lang=en', + 'url=' + wrappedArgUrl + ].join('&') + const billingId = generateUUID(); + + const success = (responseContent) => { + logInfo('NeuwoRTDModule', 'GetAiTopics: response', responseContent) + try { + const jsonContent = JSON.parse(responseContent); + if (jsonContent.marketing_categories) { + events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { type: 'request', billingId, vendor: neuwoRtdModule.name }) + } + injectTopics(jsonContent, reqBidsConfigObj, billingId) + } catch (ex) { + logError('NeuwoRTDModule', 'Response to JSON parse error', ex) + } + callback() + } + + const error = (err) => { + logError('xhr error', null, err); + callback() + } + + ajax(url, {success, error}, null, { + // could assume Origin header is set, or + // customHeaders: { 'Origin': 'Origin' } + }) +} + +export function addFragment(base, path, addition) { + const container = {} + deepSetValue(container, path, addition) + mergeDeep(base, container) +} + +/** + * Concatenate a base array and an array within an object + * non-array bases will be arrays, non-arrays at object key will be discarded + * @param {array} base base array to add to + * @param {object} source object to get an array from + * @param {string} key dot-notated path to array within object + * @returns base + source[key] if that's an array + */ +function combineArray(base, source, key) { + if (Array.isArray(base) === false) base = [] + const addition = deepAccess(source, key, []) + if (Array.isArray(addition)) return base.concat(addition) + else return base +} + +export function injectTopics(topics, bidsConfig) { + topics = topics || {} + + // join arrays of IAB category details to single array + const combinedTiers = combineArray( + combineArray([], topics, RESPONSE_IAB_TIER_1), + topics, RESPONSE_IAB_TIER_2) + + const segment = pickSegments(combinedTiers) + // effectively gets topics.marketing_categories.iab_tier_1, topics.marketing_categories.iab_tier_2 + // used as FPD segments content + + const IABSegments = { + name: DATA_PROVIDER, + ext: { segtax: SEGTAX_IAB }, + segment + } + + addFragment(bidsConfig.ortb2Fragments.global, 'site.content.data', [IABSegments]) + + // upgrade category taxonomy to IAB 2.2, inject result to page categories + if (segment.length > 0) { + addFragment(bidsConfig.ortb2Fragments.global, 'site.cattax', CATTAX_IAB) + addFragment(bidsConfig.ortb2Fragments.global, 'site.pagecat', segment.map(s => s.id)) + } + + logInfo('NeuwoRTDModule', 'injectTopics: post-injection bidsConfig', bidsConfig) +} + +/* eslint-disable object-property-newline */ +const D_IAB_ID = { // Content Taxonomy version 2.0 final release November 2017 [sic] (Taxonomy ID Mapping, IAB versions 2.0 - 2.2) + 'IAB19-1': '603', 'IAB6-1': '193', 'IAB5-2': '133', 'IAB20-1': '665', 'IAB20-2': '656', 'IAB23-2': '454', 'IAB3-2': '102', 'IAB20-3': '672', 'IAB8-5': '211', + 'IAB8-18': '211', 'IAB7-4': '288', 'IAB7-5': '233', 'IAB17-12': '484', 'IAB19-3': '608', 'IAB21-1': '442', 'IAB9-2': '248', 'IAB15-1': '456', 'IAB9-17': '265', 'IAB20-4': '658', + 'IAB2-3': '30', 'IAB2-1': '32', 'IAB17-1': '518', 'IAB2-2': '34', 'IAB2': '1', 'IAB8-2': '215', 'IAB17-2': '545', 'IAB17-26': '547', 'IAB9-3': '249', 'IAB18-1': '553', 'IAB20-5': '674', + 'IAB15-2': '465', 'IAB3-3': '119', 'IAB16-2': '423', 'IAB9-4': '259', 'IAB9-5': '270', 'IAB18-2': '574', 'IAB17-4': '549', 'IAB7-33': '312', 'IAB1-1': '42', 'IAB17-5': '485', 'IAB23-3': '458', + 'IAB20-6': '675', 'IAB3': '53', 'IAB20-7': '676', 'IAB19-5': '633', 'IAB20-9': '677', 'IAB9-6': '250', 'IAB17-6': '499', 'IAB2-4': '25', 'IAB9-7': '271', 'IAB4-11': '125', 'IAB4-1': '126', + 'IAB4': '123', 'IAB16-3': '424', 'IAB2-5': '18', 'IAB17-7': '486', 'IAB15-3': '466', 'IAB23-5': '459', 'IAB9-9': '260', 'IAB2-22': '19', 'IAB17-8': '500', 'IAB9-10': '261', 'IAB5-5': '137', + 'IAB9-11': '262', 'IAB2-21': '3', 'IAB19-2': '610', 'IAB19-8': '600', 'IAB19-9': '601', 'IAB3-5': '121', 'IAB9-15': '264', 'IAB2-6': '8', 'IAB2-7': '9', 'IAB22-2': '474', 'IAB17-9': '491', + 'IAB2-8': '10', 'IAB20-12': '678', 'IAB17-3': '492', 'IAB19-12': '611', 'IAB14-1': '188', 'IAB6-3': '194', 'IAB7-17': '316', 'IAB19-13': '612', 'IAB8-8': '217', 'IAB9-1': '205', 'IAB19-22': '613', + 'IAB8-9': '218', 'IAB14-2': '189', 'IAB16-4': '425', 'IAB9-12': '251', 'IAB5': '132', 'IAB6-9': '190', 'IAB19-15': '623', 'IAB17-17': '496', 'IAB20-14': '659', 'IAB6': '186', 'IAB20-26': '666', + 'IAB17-10': '510', 'IAB13-4': '396', 'IAB1-3': '201', 'IAB16-1': '426', 'IAB17-11': '511', 'IAB17-13': '511', 'IAB17-32': '511', 'IAB7-1': '225', 'IAB8': '210', 'IAB8-10': '219', 'IAB9-13': '266', + 'IAB10-4': '275', 'IAB9-14': '273', 'IAB15-8': '469', 'IAB15-4': '470', 'IAB17-15': '512', 'IAB3-7': '77', 'IAB19-16': '614', 'IAB3-8': '78', 'IAB2-10': '22', 'IAB2-12': '22', 'IAB2-11': '11', + 'IAB8-12': '221', 'IAB7-35': '223', 'IAB7-38': '223', 'IAB7-24': '296', 'IAB13-5': '411', 'IAB7-25': '234', 'IAB23-6': '460', 'IAB9': '239', 'IAB7-26': '235', 'IAB10': '274', 'IAB10-1': '278', + 'IAB10-2': '279', 'IAB19-17': '634', 'IAB10-5': '280', 'IAB5-10': '145', 'IAB5-11': '146', 'IAB20-17': '667', 'IAB17-16': '497', 'IAB20-18': '668', 'IAB3-9': '55', 'IAB1-4': '440', 'IAB17-18': '514', + 'IAB17-27': '515', 'IAB10-3': '282', 'IAB19-25': '618', 'IAB17-19': '516', 'IAB13-6': '398', 'IAB10-7': '283', 'IAB12-1': '382', 'IAB19-24': '624', 'IAB6-4': '195', 'IAB23-7': '461', 'IAB9-19': '252', + 'IAB4-4': '128', 'IAB4-5': '127', 'IAB23-8': '462', 'IAB10-8': '284', 'IAB5-8': '147', 'IAB16-5': '427', 'IAB11-2': '383', 'IAB12-3': '384', 'IAB3-10': '57', 'IAB2-13': '23', 'IAB9-20': '241', + 'IAB3-1': '58', 'IAB3-11': '58', 'IAB14-4': '191', 'IAB17-20': '520', 'IAB7-31': '228', 'IAB7-37': '301', 'IAB3-12': '107', 'IAB2-14': '13', 'IAB17-25': '519', 'IAB2-15': '27', 'IAB1-5': '324', + 'IAB1-6': '338', 'IAB9-16': '243', 'IAB13-8': '412', 'IAB12-2': '385', 'IAB9-21': '253', 'IAB8-6': '222', 'IAB7-32': '229', 'IAB2-16': '14', 'IAB17-23': '521', 'IAB13-9': '413', 'IAB17-24': '501', + 'IAB9-22': '254', 'IAB15-5': '244', 'IAB6-2': '196', 'IAB6-5': '197', 'IAB6-6': '198', 'IAB2-17': '24', 'IAB13-2': '405', 'IAB13': '391', 'IAB13-7': '410', 'IAB13-12': '415', 'IAB16': '422', + 'IAB9-23': '255', 'IAB7-36': '236', 'IAB15-6': '471', 'IAB2-18': '15', 'IAB11-4': '386', 'IAB1-2': '432', 'IAB5-9': '139', 'IAB6-7': '305', 'IAB5-12': '149', 'IAB5-13': '134', 'IAB19-4': '631', + 'IAB19-19': '631', 'IAB19-20': '631', 'IAB19-32': '631', 'IAB9-24': '245', 'IAB21': '441', 'IAB21-3': '451', 'IAB23': '453', 'IAB10-9': '276', 'IAB4-9': '130', 'IAB16-6': '429', 'IAB4-6': '129', + 'IAB13-10': '416', 'IAB2-19': '28', 'IAB17-28': '525', 'IAB9-25': '272', 'IAB17-29': '527', 'IAB17-30': '227', 'IAB17-31': '530', 'IAB22-1': '481', 'IAB15': '464', 'IAB9-26': '246', 'IAB9-27': '256', + 'IAB9-28': '267', 'IAB17-33': '502', 'IAB19-35': '627', 'IAB2-20': '4', 'IAB7-39': '307', 'IAB19-30': '605', 'IAB22': '473', 'IAB17-34': '503', 'IAB17-35': '531', 'IAB7-19': '309', 'IAB7-40': '310', + 'IAB19-6': '635', 'IAB7-41': '237', 'IAB17-36': '504', 'IAB17-44': '533', 'IAB20-23': '662', 'IAB15-7': '472', 'IAB20-24': '671', 'IAB5-14': '136', 'IAB6-8': '199', 'IAB17': '483', 'IAB9-29': '263', + 'IAB2-23': '5', 'IAB13-11': '414', 'IAB4-3': '395', 'IAB18': '552', 'IAB7-42': '311', 'IAB17-37': '505', 'IAB17-38': '537', 'IAB17-39': '538', 'IAB19-26': '636', 'IAB19': '596', 'IAB1-7': '640', + 'IAB17-40': '539', 'IAB7-43': '293', 'IAB20': '653', 'IAB8-16': '212', 'IAB8-17': '213', 'IAB16-7': '430', 'IAB9-30': '680', 'IAB17-41': '541', 'IAB17-42': '542', 'IAB17-43': '506', 'IAB15-10': '390', + 'IAB19-23': '607', 'IAB19-34': '629', 'IAB14-7': '165', 'IAB7-44': '231', 'IAB7-45': '238', 'IAB9-31': '257', 'IAB5-1': '135', 'IAB7-2': '301', 'IAB18-6': '580', 'IAB7-3': '297', 'IAB23-1': '453', + 'IAB8-1': '214', 'IAB7-6': '312', 'IAB7-7': '300', 'IAB7-8': '301', 'IAB13-1': '410', 'IAB7-9': '301', 'IAB15-9': '465', 'IAB7-10': '313', 'IAB3-4': '602', 'IAB20-8': '660', 'IAB8-3': '214', + 'IAB20-10': '660', 'IAB7-11': '314', 'IAB20-11': '660', 'IAB23-4': '459', 'IAB9-8': '270', 'IAB8-4': '214', 'IAB7-12': '306', 'IAB7-13': '313', 'IAB7-14': '287', 'IAB18-5': '575', 'IAB7-15': '315', + 'IAB8-7': '214', 'IAB19-11': '616', 'IAB7-16': '289', 'IAB7-18': '301', 'IAB7-20': '290', 'IAB20-13': '659', 'IAB7-21': '313', 'IAB18-3': '579', 'IAB13-3': '52', 'IAB20-15': '659', 'IAB8-11': '214', + 'IAB7-22': '318', 'IAB20-16': '659', 'IAB7-23': '313', 'IAB7': '223', 'IAB10-6': '634', 'IAB7-27': '318', 'IAB11-1': '388', 'IAB7-29': '318', 'IAB7-30': '304', 'IAB19-18': '619', 'IAB8-13': '214', + 'IAB20-19': '659', 'IAB20-20': '657', 'IAB8-14': '214', 'IAB18-4': '565', 'IAB23-9': '459', 'IAB11': '379', 'IAB8-15': '214', 'IAB20-21': '662', 'IAB17-21': '492', 'IAB17-22': '518', 'IAB12': '379', + 'IAB23-10': '453', 'IAB7-34': '301', 'IAB4-8': '395', 'IAB26-3': '608', 'IAB20-25': '151', 'IAB20-27': '659' +} + +export function convertSegment(segment) { + if (!segment) return {} + return { + id: D_IAB_ID[segment.id || segment.ID] + } +} + +/** + * map array of objects to segments + * @param {Array[{ID: string}]} normalizable + * @returns array of IAB "segments" + */ +export function pickSegments(normalizable) { + if (Array.isArray(normalizable) === false) return [] + return normalizable.map(convertSegment) + .filter(t => t.id) +} + +export const neuwoRtdModule = { + name: 'NeuwoRTDModule', + init, + getBidRequestData +} + +submodule('realTimeData', neuwoRtdModule) diff --git a/modules/neuwoRtdProvider.md b/modules/neuwoRtdProvider.md new file mode 100644 index 00000000000..3552a018563 --- /dev/null +++ b/modules/neuwoRtdProvider.md @@ -0,0 +1,40 @@ +# Overview + +Module Name: Neuwo Rtd Provider +Module Type: Rtd Provider +Maintainer: neuwo.ai + +# Description + +Real-time data provider for Neuwo AI. Contact neuwo.ai [https://neuwo.ai/contact-us] for more information. + +# Configuration + +```javascript + +const neuwoDataProvider = { + name: 'NeuwoRTDModule', + params: { + publicToken: '' + } +} +pbjs.setConfig({realTimeData: { dataProviders: [ neuwoDataProvider ]}}) + +``` + +# Testing + +## Add development tools if necessary + +- Install node for npm +- run in prebid.js source folder: +`npm ci` +`npm i -g gulp-cli` + +## Serve + +`gulp serve --modules=rtdModule,neuwoRtdProvider,appnexusBidAdapter` + +- in your browser, navigate to: + +`http://localhost:9999/integrationExamples/gpt/neuwoRtdProvider_example.html` diff --git a/test/spec/modules/neuwoRtdProvider_spec.js b/test/spec/modules/neuwoRtdProvider_spec.js new file mode 100644 index 00000000000..7f47fba072b --- /dev/null +++ b/test/spec/modules/neuwoRtdProvider_spec.js @@ -0,0 +1,123 @@ +import { server } from 'test/mocks/xhr.js'; +import * as neuwo from 'modules/neuwoRtdProvider'; + +const PUBLIC_TOKEN = 'public_key_0000'; +const config = () => ({ + params: { + publicToken: PUBLIC_TOKEN + } +}) + +const apiReturns = () => ({ + somethingExtra: { object: true }, + marketing_categories: { + iab_tier_1: [ + { ID: 'IAB21', label: 'Real Estate', relevance: '0.45699' } + ] + } +}) + +const TAX_ID = '441' + +/** + * Object generator, like above, written using alternative techniques + * @returns object with predefined (expected) bidsConfig fields + */ +function bidsConfiglike() { + return Object.assign({}, { + ortb2Fragments: { global: {} } + }) +} + +describe('neuwoRtdProvider', function () { + describe('neuwoRtdModule', function () { + it('initializes', function () { + expect(neuwo.neuwoRtdModule.init(config())).to.be.true; + }) + it('init needs that public token', function () { + expect(neuwo.neuwoRtdModule.init()).to.be.false; + }) + + describe('segment picking', function () { + it('handles bad inputs', function () { + expect(neuwo.pickSegments()).to.be.an('array').that.is.empty; + expect(neuwo.pickSegments('technically also an array')).to.be.an('array').that.is.empty; + expect(neuwo.pickSegments({ bad_object: 'bad' })).to.be.an('array').that.is.empty; + }) + it('handles malformations', function () { + let result = neuwo.pickSegments([{something_wrong: true}, null, { ID: 'IAB19-20' }, { id: 'IAB3-1', ID: 'IAB9-20' }]) + expect(result[0].id).to.equal('631') + expect(result[1].id).to.equal('58') + expect(result.length).to.equal(2) + }) + }) + + describe('topic injection', function () { + it('mutates bidsConfig', function () { + let topics = apiReturns() + let bidsConfig = bidsConfiglike() + neuwo.injectTopics(topics, bidsConfig, () => { }) + expect(bidsConfig.ortb2Fragments.global.site.content.data[0].name, 'name of first content data object').to.equal(neuwo.DATA_PROVIDER) + expect(bidsConfig.ortb2Fragments.global.site.content.data[0].segment[0].id, 'id of first segment in content.data').to.equal(TAX_ID) + expect(bidsConfig.ortb2Fragments.global.site.cattax, 'category taxonomy code for pagecat').to.equal(6) // CATTAX_IAB + expect(bidsConfig.ortb2Fragments.global.site.pagecat[0], 'category taxonomy code for pagecat').to.equal(TAX_ID) + }) + + it('handles malformed responses', function () { + let topics = { message: 'Forbidden' } + let bidsConfig = bidsConfiglike() + neuwo.injectTopics(topics, bidsConfig, () => { }) + expect(bidsConfig.ortb2Fragments.global.site.content.data[0].name, 'name of first content data object').to.equal(neuwo.DATA_PROVIDER) + expect(bidsConfig.ortb2Fragments.global.site.content.data[0].segment, 'length of segment(s) in content.data').to.be.an('array').that.is.empty; + + topics = '404 wouldn\'t really even show up for injection' + let bdsConfig = bidsConfiglike() + neuwo.injectTopics(topics, bdsConfig, () => { }) + expect(bdsConfig.ortb2Fragments.global.site.content.data[0].name, 'name of first content data object').to.equal(neuwo.DATA_PROVIDER) + expect(bdsConfig.ortb2Fragments.global.site.content.data[0].segment, 'length of segment(s) in content.data').to.be.an('array').that.is.empty; + + topics = undefined + let bdsConfigE = bidsConfiglike() + neuwo.injectTopics(topics, bdsConfigE, () => { }) + expect(bdsConfigE.ortb2Fragments.global.site.content.data[0].name, 'name of first content data object').to.equal(neuwo.DATA_PROVIDER) + expect(bdsConfigE.ortb2Fragments.global.site.content.data[0].segment, 'length of segment(s) in content.data').to.be.an('array').that.is.empty; + }) + }) + + describe('fragment addition', function () { + it('mutates input objects', function () { + let alphabet = { a: { b: { c: {} } } } + neuwo.addFragment(alphabet.a.b.c, 'd.e.f', { g: 'h' }) + expect(alphabet.a.b.c.d.e.f.g).to.equal('h') + }) + }) + + describe('getBidRequestData', function () { + it('forms requests properly and mutates input bidsConfig', function () { + let bids = bidsConfiglike() + let conf = config() + // control xhr api request target for testing + conf.params.argUrl = 'https://publisher.works/article.php?get=horrible_url_for_testing&id=5' + + neuwo.getBidRequestData(bids, () => { }, conf, 'any consent data works, clearly') + + let request = server.requests[0]; + expect(request.url).to.be.a('string').that.includes(conf.params.publicToken) + expect(request.url).to.include(encodeURIComponent(conf.params.argUrl)) + request.respond(200, { 'Content-Type': 'application/json; encoding=UTF-8' }, JSON.stringify(apiReturns())); + + expect(bids.ortb2Fragments.global.site.content.data[0].name, 'name of first content data object').to.equal(neuwo.DATA_PROVIDER) + expect(bids.ortb2Fragments.global.site.content.data[0].segment[0].id, 'id of first segment in content.data').to.equal(TAX_ID) + }) + + it('accepts detail not available result', function () { + let bidsConfig = bidsConfiglike() + let comparison = bidsConfiglike() + neuwo.getBidRequestData(bidsConfig, () => { }, config(), 'consensually') + let request = server.requests[0]; + request.respond(404, { 'Content-Type': 'application/json; encoding=UTF-8' }, JSON.stringify({ detail: 'Basically first time seeing this' })); + expect(bidsConfig).to.deep.equal(comparison) + }) + }) + }) +}) From 1e91c1c6704de9dbef194441e4266dcf5b0249de Mon Sep 17 00:00:00 2001 From: nouchy <33549554+nouchy@users.noreply.github.com> Date: Wed, 8 Feb 2023 13:24:27 +0100 Subject: [PATCH 334/367] SirData RTD Module: Change (add Seller Defined Audience (SDA) support) (#9448) * sirdataRtdProvider.js update (SDA support) Add support for Seller Defined Audience. Various improvement and support for new bidders. * update Sirdata RTD module linting issues fixed * New tests Add new tests to reach 80%+ test coverage * Update sirdataRtdProvider_spec.js * Update sirdataRtdProvider_spec.js --- modules/sirdataRtdProvider.js | 546 +++++++++---------- test/spec/modules/sirdataRtdProvider_spec.js | 138 ++++- 2 files changed, 378 insertions(+), 306 deletions(-) diff --git a/modules/sirdataRtdProvider.js b/modules/sirdataRtdProvider.js index 369276e7638..40ee3d8b973 100644 --- a/modules/sirdataRtdProvider.js +++ b/modules/sirdataRtdProvider.js @@ -1,12 +1,13 @@ /** * This module adds Sirdata provider to the real time data module + * and now supports Seller Defined Audience * The {@link module:modules/realTimeData} module is required * The module will fetch segments (user-centric) and categories (page-centric) from Sirdata server * The module will automatically handle user's privacy and choice in California (IAB TL CCPA Framework) and in Europe (IAB EU TCF FOR GDPR) * @module modules/sirdataRtdProvider * @requires module:modules/realTimeData */ -import {deepAccess, deepEqual, deepSetValue, isEmpty, logError, mergeDeep} from '../src/utils.js'; +import {deepAccess, deepSetValue, isEmpty, logError, mergeDeep} from '../src/utils.js'; import {submodule} from '../src/hook.js'; import {ajax} from '../src/ajax.js'; import {findIndex} from '../src/polyfill.js'; @@ -16,6 +17,52 @@ import {config} from '../src/config.js'; /** @type {string} */ const MODULE_NAME = 'realTimeData'; const SUBMODULE_NAME = 'SirdataRTDModule'; +const ORTB2_NAME = 'sirdata.com'; + +const partnerIds = { + 'criteo': 27443, + 'openx': 30342, + 'pubmatic': 30345, + 'smaato': 27520, + 'triplelift': 27518, + 'yahoossp': 30339, + 'rubicon': 27452, + 'appnexus': 27446, + 'appnexusAst': 27446, + 'brealtime': 27446, + 'emxdigital': 27446, + 'pagescience': 27446, + 'gourmetads': 33394, + 'matomy': 27446, + 'featureforward': 27446, + 'oftmedia': 27446, + 'districtm': 27446, + 'adasta': 27446, + 'beintoo': 27446, + 'gravity': 27446, + 'msq_classic': 27878, + 'msq_max': 27878, + '366_apx': 27878, + 'mediasquare': 27878, + 'smartadserver': 27440, + 'smart': 27440, + 'proxistore': 27484, + 'ix': 27248, + 'sdRtdForGpt': 27449, + 'smilewanted': 28690, + 'taboola': 33379, + 'ttd': 33382, + 'zeta_global': 33385, + 'teads': 33388, + 'conversant': 33391, + 'improvedigital': 33397, + 'invibes': 33400, + 'sublime': 33403, + 'rtbhouse': 33406, + 'zeta_global_ssp': 33385, +}; + +let CONTEXT_ONLY = true; export function getSegmentsAndCategories(reqBidsConfigObj, onDone, moduleConfig, userConsent) { moduleConfig.params = moduleConfig.params || {}; @@ -46,9 +93,10 @@ export function getSegmentsAndCategories(reqBidsConfigObj, onDone, moduleConfig, if (!sirdataDomain || !gdprApplies || (deepAccess(userConsent, 'gdpr.vendorData.vendor.consents') && userConsent.gdpr.vendorData.vendor.consents[53] && userConsent.gdpr.vendorData.purpose.consents[1] && userConsent.gdpr.vendorData.purpose.consents[4])) { sirdataDomain = 'sddan.com'; sendWithCredentials = true; + CONTEXT_ONLY = false; } - // TODO: is 'page' the right value here? - var actualUrl = moduleConfig.params.actualUrl || getRefererInfo().page; + + var actualUrl = moduleConfig.params.actualUrl || getRefererInfo().stack.pop() || getRefererInfo().page; const url = 'https://kvt.' + sirdataDomain + '/api/v1/public/p/' + moduleConfig.params.partnerId + '/d/' + moduleConfig.params.key + '/s?callback=&gdpr=' + gdprApplies + '&gdpr_consent=' + tcString + (actualUrl ? '&url=' + encodeURIComponent(actualUrl) : ''); @@ -86,39 +134,74 @@ export function getSegmentsAndCategories(reqBidsConfigObj, onDone, moduleConfig, }); } -export function setGlobalOrtb2(ortb2, segments, categories) { +export function setGlobalOrtb2Sda(ortb2Fragments, data, segtaxid, cattaxid) { try { - let addOrtb2 = {}; - let testGlobal = ortb2 || {} - if (!deepAccess(testGlobal, 'user.ext.data.sd_rtd') || !deepEqual(testGlobal.user.ext.data.sd_rtd, segments)) { - deepSetValue(addOrtb2, 'user.ext.data.sd_rtd', segments || {}); + if (!isEmpty(data.segments)) { + applyGlobalOrtb2Sda(ortb2Fragments, 'user', data.segments, segtaxid); } - if (!deepAccess(testGlobal, 'site.ext.data.sd_rtd') || !deepEqual(testGlobal.site.ext.data.sd_rtd, categories)) { - deepSetValue(addOrtb2, 'site.ext.data.sd_rtd', categories || {}); - } - if (!isEmpty(addOrtb2)) { - mergeDeep(ortb2, addOrtb2); + if (!isEmpty(data.categories)) { + applyGlobalOrtb2Sda(ortb2Fragments, 'site', data.categories, cattaxid); } } catch (e) { logError(e) } + return true; +} +export function applyGlobalOrtb2Sda(ortb2Fragments, type, segments, segtaxValue) { + try { + let ortb2Data = [{ + name: ORTB2_NAME, + segment: segments.map((segmentId) => ({ id: segmentId })), + }]; + if (segtaxValue) { + ortb2Data[0].ext = { segtax: segtaxValue }; + } + let ortb2Conf = (type == 'site' ? {site: {content: {data: ortb2Data}}} : {user: {data: ortb2Data}}); + mergeDeep(ortb2Fragments, ortb2Conf); + } catch (e) { + logError(e) + } return true; } -export function setBidderOrtb2(bidderOrtb2, bidder, segments, categories) { +export function setBidderOrtb2Sda(ortb2Fragments, bidder, data, segtaxid, cattaxid) { try { - let addOrtb2 = {}; - let testBidder = bidderOrtb2[bidder]; - if (!deepAccess(testBidder, 'user.ext.data.sd_rtd') || !deepEqual(testBidder.user.ext.data.sd_rtd, segments)) { - deepSetValue(addOrtb2, 'user.ext.data.sd_rtd', segments || {}); + if (!isEmpty(data.segments)) { + applyBidderOrtb2Sda(ortb2Fragments, bidder, 'user', data.segments, segtaxid); } - if (!deepAccess(testBidder, 'site.ext.data.sd_rtd') || !deepEqual(testBidder.site.ext.data.sd_rtd, categories)) { - deepSetValue(addOrtb2, 'site.ext.data.sd_rtd', categories || {}); + if (!isEmpty(data.categories)) { + applyBidderOrtb2Sda(ortb2Fragments, bidder, 'site', data.categories, cattaxid); } - if (!isEmpty(addOrtb2)) { - mergeDeep(bidderOrtb2[bidder], addOrtb2) + } catch (e) { + logError(e) + } + return true; +} + +export function applyBidderOrtb2Sda(ortb2Fragments, bidder, type, segments, segtaxValue) { + try { + let ortb2Data = [{ + name: ORTB2_NAME, + segment: segments.map((segmentId) => ({ id: segmentId })), + }]; + if (segtaxValue) { + ortb2Data[0].ext = { segtax: segtaxValue }; } + let ortb2Conf = (type == 'site' ? {site: {content: {data: ortb2Data}}} : {user: {data: ortb2Data}}); + mergeDeep(ortb2Fragments, {[bidder]: ortb2Conf}); + } catch (e) { + logError(e) + } + return true; +} + +export function setBidderOrtb2(bidderOrtb2Fragments, bidder, path, segments) { + try { + if (isEmpty(segments)) { return; } + let ortb2Conf = {}; + deepSetValue(ortb2Conf, path, segments || {}); + mergeDeep(bidderOrtb2Fragments, {[bidder]: ortb2Conf}); } catch (e) { logError(e) } @@ -137,16 +220,16 @@ export function loadCustomFunction(todo, adUnit, list, data, bid) { return true; } -export function getSegAndCatsArray(data, minScore) { - var sirdataData = {'segments': [], 'categories': []}; +export function getSegAndCatsArray(data, minScore, pid) { + let sirdataData = {'segments': [], 'categories': []}; minScore = minScore && typeof minScore == 'number' ? minScore : 30; try { if (data && data.contextual_categories) { for (let catId in data.contextual_categories) { - if (data.contextual_categories.hasOwnProperty(catId)) { + if (data.contextual_categories.hasOwnProperty(catId) && data.contextual_categories[catId]) { let value = data.contextual_categories[catId]; if (value >= minScore && sirdataData.categories.indexOf(catId) === -1) { - sirdataData.categories.push(catId.toString()); + sirdataData.categories.push((pid ? pid.toString() + 'cc' : '') + catId.toString()); } } } @@ -157,8 +240,11 @@ export function getSegAndCatsArray(data, minScore) { try { if (data && data.segments) { for (let segId in data.segments) { - if (data.segments.hasOwnProperty(segId)) { - sirdataData.segments.push(data.segments[segId].toString()); + if (data.segments.hasOwnProperty(segId) && data.segments[segId]) { + sirdataData.segments.push((pid ? pid.toString() + 'us' : '') + data.segments[segId].toString()); + if (pid && CONTEXT_ONLY) { + sirdataData.categories.push(pid.toString() + 'uc' + data.segments[segId].toString()); + } } } } @@ -168,34 +254,77 @@ export function getSegAndCatsArray(data, minScore) { return sirdataData; } +export function applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit) { + // only share SDA data if whitelisted + if (!biddersParamsExist || indexFound) { + // SDA Publisher + let sirdataDataForSDA = getSegAndCatsArray(data, minScore, moduleConfig.params.partnerId); + setBidderOrtb2Sda(reqBids.ortb2Fragments?.bidder, bid.bidder, sirdataDataForSDA, data.segtaxid, data.cattaxid); + } + + // always share SDA for curation + let curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : (partnerIds[bid.bidder] ? partnerIds[bid.bidder] : null)); + if (curationId) { + // seller defined audience & bidder specific data + if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { + // Get Bidder Specific Data + let curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore, null); + sirdataList = sirdataList.concat(curationData.segments).concat(curationData.categories); + + // SDA Partners + let curationDataForSDA = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore, curationId); + setBidderOrtb2Sda(reqBids.ortb2Fragments?.bidder, bid.bidder, curationDataForSDA, data.shared_taxonomy[curationId].segtaxid, data.shared_taxonomy[curationId].cattaxid); + } + } + + // Apply custom function or return Bidder Specific Data if publisher is ok + if (sirdataList && sirdataList.length > 0 && (!biddersParamsExist || indexFound)) { + if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { + return loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataList, data, bid); + } else { + return sirdataList; + } + } +} + +export function applySdaAndDefaultSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit) { + let specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + if (specificData && specificData.length > 0) { + setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, 'user.ext.data', {sd_rtd: specificData}); + } +} + export function addSegmentData(reqBids, data, moduleConfig, onDone) { const adUnits = reqBids.adUnits; moduleConfig = moduleConfig || {}; moduleConfig.params = moduleConfig.params || {}; const globalMinScore = moduleConfig.params.hasOwnProperty('contextualMinRelevancyScore') ? moduleConfig.params.contextualMinRelevancyScore : 30; - var sirdataData = getSegAndCatsArray(data, globalMinScore); + var sirdataData = getSegAndCatsArray(data, globalMinScore, null); const sirdataList = sirdataData.segments.concat(sirdataData.categories); - var sirdataMergedList = []; - var curationData = {'segments': [], 'categories': []}; - var curationId = '1'; const biddersParamsExist = (!!(moduleConfig.params && moduleConfig.params.bidders)); - // Global ortb2 - if (!biddersParamsExist) { - setGlobalOrtb2(reqBids.ortb2Fragments?.global, sirdataData.segments, sirdataData.categories); + // Global ortb2 SDA + if (data.global_taxonomy && !isEmpty(data.global_taxonomy)) { + let globalData = {'segments': [], 'categories': []}; + for (let i in data.global_taxonomy) { + if (!isEmpty(data.global_taxonomy[i])) { + globalData = getSegAndCatsArray(data.global_taxonomy[i], globalMinScore, null); + setGlobalOrtb2Sda(reqBids.ortb2Fragments?.global, globalData, data.global_taxonomy[i].segtaxid, data.global_taxonomy[i].cattaxid); + } + } } // Google targeting if (typeof window.googletag !== 'undefined' && (moduleConfig.params.setGptKeyValues || !moduleConfig.params.hasOwnProperty('setGptKeyValues'))) { try { - // For curation Google is pid 27449 - curationId = (moduleConfig.params.gptCurationId ? moduleConfig.params.gptCurationId : '27449'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], globalMinScore); + let gptCurationId = (moduleConfig.params.gptCurationId ? moduleConfig.params.gptCurationId : (partnerIds['sdRtdForGpt'] ? partnerIds['sdRtdForGpt'] : null)); + let sirdataMergedList = sirdataList; + if (gptCurationId && data.shared_taxonomy && data.shared_taxonomy[gptCurationId]) { + let gamCurationData = getSegAndCatsArray(data.shared_taxonomy[gptCurationId], globalMinScore, null); + sirdataMergedList = sirdataMergedList.concat(gamCurationData.segments).concat(gamCurationData.categories); } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); window.googletag.pubads().getSlots().forEach(function (n) { if (typeof n.setTargeting !== 'undefined' && sirdataMergedList && sirdataMergedList.length > 0) { n.setTargeting('sd_rtd', sirdataMergedList); @@ -221,259 +350,108 @@ export function addSegmentData(reqBids, data, moduleConfig, onDone) { }) : false); indexFound = (!!(typeof bidderIndex == 'number' && bidderIndex >= 0)); try { - curationData = {'segments': [], 'categories': []}; - sirdataMergedList = []; - let minScore = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('contextualMinRelevancyScore') ? moduleConfig.params.bidders[bidderIndex].contextualMinRelevancyScore : globalMinScore); + let specificData = null; + + switch (bid.bidder) { + case 'appnexus': + case 'appnexusAst': + case 'brealtime': + case 'emxdigital': + case 'pagescience': + case 'gourmetads': + case 'matomy': + case 'featureforward': + case 'oftmedia': + case 'districtm': + case 'adasta': + case 'beintoo': + case 'gravity': + case 'msq_classic': + case 'msq_max': + case '366_apx': + specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + if (specificData && specificData.length > 0) { + deepSetValue(bid, 'params.keywords.sd_rtd', specificData); + } + break; - if (!biddersParamsExist || (indexFound && (!moduleConfig.params.bidders[bidderIndex].hasOwnProperty('adUnitCodes') || moduleConfig.params.bidders[bidderIndex].adUnitCodes.indexOf(adUnit.code) !== -1))) { - switch (bid.bidder) { - case 'appnexus': - case 'appnexusAst': - case 'brealtime': - case 'emxdigital': - case 'pagescience': - case 'gourmetads': - case 'matomy': - case 'featureforward': - case 'oftmedia': - case 'districtm': - case 'adasta': - case 'beintoo': - case 'gravity': - case 'msq_classic': - case 'msq_max': - case '366_apx': - // For curation Xandr is pid 27446 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27446'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - deepSetValue(bid, 'params.keywords.sd_rtd', sirdataMergedList); - } - } - break; - - case 'smartadserver': - case 'smart': + case 'smartadserver': + case 'smart': + specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + if (specificData && specificData.length > 0) { var target = []; if (bid.hasOwnProperty('params') && bid.params.hasOwnProperty('target')) { target.push(bid.params.target); } - // For curation Smart is pid 27440 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27440'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - sirdataMergedList.forEach(function (entry) { - if (target.indexOf('sd_rtd=' + entry) === -1) { - target.push('sd_rtd=' + entry); - } - }); - deepSetValue(bid, 'params.target', target.join(';')); - } - } - break; - - case 'rubicon': - // For curation Magnite is pid 27518 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27452'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'ix': - var ixConfig = config.getConfig('ix.firstPartyData.sd_rtd'); - if (!ixConfig) { - // For curation index is pid 27248 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27248'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - var cappIxCategories = []; - var ixLength = 0; - var ixLimit = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('sizeLimit') ? moduleConfig.params.bidders[bidderIndex].sizeLimit : 1000); - // Push ids For publisher use and for curation if exists but limit size because the bidder uses GET parameters - sirdataMergedList.forEach(function (entry) { - if (ixLength < ixLimit) { - cappIxCategories.push(entry); - ixLength += entry.toString().length; - } - }); - config.setConfig({ix: {firstPartyData: {sd_rtd: cappIxCategories}}}); - } - } - } - break; - - case 'proxistore': - // For curation Proxistore is pid 27484 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27484'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } else { - data.shared_taxonomy[curationId] = {contextual_categories: {}}; - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - deepSetValue(bid, 'ortb2.user.ext.data', { - segments: sirdataData.segments.concat(curationData.segments), - contextual_categories: {...data.contextual_categories, ...data.shared_taxonomy[curationId].contextual_categories} - }); - } - } - break; - - case 'criteo': - // For curation Smart is pid 27443 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27443'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'triplelift': - // For curation Triplelift is pid 27518 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27518'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'avct': - case 'avocet': - // For curation Avocet is pid 27522 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27522'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'smaato': - // For curation Smaato is pid 27520 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '27520'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'yahoossp': - // For curation Yahoo is pid 30339 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '30339'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - case 'openx': - // For curation OpenX is pid 30342 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '30342'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); + specificData.forEach(function (entry) { + if (target.indexOf('sd_rtd=' + entry) === -1) { + target.push('sd_rtd=' + entry); } - } - break; - - case 'pubmatic': - // For curation Pubmatic is pid 30345 - curationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : '30345'); - if (data.shared_taxonomy && data.shared_taxonomy[curationId]) { - curationData = getSegAndCatsArray(data.shared_taxonomy[curationId], minScore); - } - sirdataMergedList = sirdataList.concat(curationData.segments).concat(curationData.categories); - if (sirdataMergedList && sirdataMergedList.length > 0) { - if (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('customFunction')) { - loadCustomFunction(moduleConfig.params.bidders[bidderIndex].customFunction, adUnit, sirdataMergedList, data, bid); - } else { - setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, data.segments.concat(curationData.segments), sirdataMergedList); - } - } - break; - - default: - if (!biddersParamsExist || indexFound) { - if (!deepAccess(bid, 'ortb2.site.ext.data.sd_rtd')) { - deepSetValue(bid, 'ortb2.site.ext.data.sd_rtd', sirdataData.categories); - } - if (!deepAccess(bid, 'ortb2.user.ext.data.sd_rtd')) { - deepSetValue(bid, 'ortb2.user.ext.data.sd_rtd', sirdataData.segments); + }); + deepSetValue(bid, 'params.target', target.join(';')); + } + break; + + case 'ix': + specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + let ixConfig = config.getConfig('ix.firstPartyData.sd_rtd'); + if (!ixConfig && specificData && specificData.length > 0) { + let cappIxCategories = []; + let ixLength = 0; + let ixLimit = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('sizeLimit') ? moduleConfig.params.bidders[bidderIndex].sizeLimit : 1000); + // Push ids For publisher use and for curation if exists but limit size because the bidder uses GET parameters + specificData.forEach(function (entry) { + if (ixLength < ixLimit) { + cappIxCategories.push(entry); + ixLength += entry.toString().length; } + }); + config.setConfig({ix: {firstPartyData: {sd_rtd: cappIxCategories}}}); + } + break; + + case 'proxistore': + specificData = applySdaGetSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + if (specificData && specificData.length > 0) { + let psCurationId = (indexFound && moduleConfig.params.bidders[bidderIndex].hasOwnProperty('curationId') ? moduleConfig.params.bidders[bidderIndex].curationId : (partnerIds[bid.bidder] ? partnerIds[bid.bidder] : null)); + if (!data.shared_taxonomy || !data.shared_taxonomy[psCurationId]) { + data.shared_taxonomy[psCurationId] = {segments: [], contextual_categories: {}, segtaxid: null, cattaxid: null}; } - } + let psCurationData = getSegAndCatsArray(data.shared_taxonomy[psCurationId], minScore, null); + setBidderOrtb2(reqBids.ortb2Fragments?.bidder, bid.bidder, 'user.ext.data', { + segments: sirdataData.segments.concat(psCurationData.segments), + contextual_categories: {...data.contextual_categories, ...data.shared_taxonomy[psCurationId].contextual_categories} + }); + } + break; + + case 'rubicon': + case 'criteo': + case 'triplelift': + case 'smaato': + case 'yahoossp': + case 'openx': + case 'pubmatic': + case 'smilewanted': + case 'taboola': + case 'ttd': + case 'zeta_global': + case 'zeta_global_ssp': + case 'teads': + case 'conversant': + case 'improvedigital': + case 'invibes': + case 'sublime': + case 'rtbhouse': + case 'mediasquare': + applySdaAndDefaultSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + break; + + default: + if (!biddersParamsExist || (indexFound && (!moduleConfig.params.bidders[bidderIndex].hasOwnProperty('adUnitCodes') || moduleConfig.params.bidders[bidderIndex].adUnitCodes.indexOf(adUnit.code) !== -1))) { + applySdaAndDefaultSpecificData(data, sirdataList, biddersParamsExist, minScore, reqBids, bid, moduleConfig, indexFound, bidderIndex, adUnit); + } } } catch (e) { logError(e); diff --git a/test/spec/modules/sirdataRtdProvider_spec.js b/test/spec/modules/sirdataRtdProvider_spec.js index 9cf392ebd62..eccc4777906 100644 --- a/test/spec/modules/sirdataRtdProvider_spec.js +++ b/test/spec/modules/sirdataRtdProvider_spec.js @@ -1,17 +1,17 @@ -import { addSegmentData, getSegmentsAndCategories, sirdataSubmodule } from 'modules/sirdataRtdProvider.js'; -import { server } from 'test/mocks/xhr.js'; +import {addSegmentData, getSegmentsAndCategories, sirdataSubmodule} from 'modules/sirdataRtdProvider.js'; +import {server} from 'test/mocks/xhr.js'; const responseHeader = {'Content-Type': 'application/json'}; -describe('sirdataRtdProvider', function() { - describe('sirdataSubmodule', function() { +describe('sirdataRtdProvider', function () { + describe('sirdataSubmodule', function () { it('successfully instantiates', function () { - expect(sirdataSubmodule.init()).to.equal(true); + expect(sirdataSubmodule.init()).to.equal(true); }); }); - describe('Add Segment Data', function() { - it('adds segment data', function() { + describe('Add Segment Data', function () { + it('adds segment data', function () { const config = { params: { setGptKeyValues: false, @@ -42,23 +42,34 @@ describe('sirdataRtdProvider', function() { contextual_categories: {'333333': 100} }; - addSegmentData({adUnits}, data, config, () => {}); + addSegmentData({adUnits}, data, config, () => { + }); expect(adUnits[0].bids[0].params.keywords).to.have.deep.property('sd_rtd', ['111111', '222222', '333333']); - expect(adUnits[0].bids[1].ortb2.site.ext.data).to.have.deep.property('sd_rtd', ['333333']); - expect(adUnits[0].bids[1].ortb2.user.ext.data).to.have.deep.property('sd_rtd', ['111111', '222222']); }); }); - describe('Get Segments And Categories', function() { - it('gets data from async request and adds segment data', function() { + describe('Get Segments And Categories', function () { + it('gets data from async request and adds segment data', function () { + const overrideAppnexus = function (adUnit, list, data, bid) { + deepSetValue(bid, 'params.keywords.custom', list); + } + const config = { params: { setGptKeyValues: false, contextualMinRelevancyScore: 50, bidders: [{ - bidder: 'appnexus' + bidder: 'appnexus', + customFunction: overrideAppnexus }, { - bidder: 'other' + bidder: 'smartadserver' + }, { + bidder: 'ix', + sizeLimit: 1200, + }, { + bidder: 'rubicon', + }, { + bidder: 'proxistore', }] } }; @@ -71,24 +82,107 @@ describe('sirdataRtdProvider', function() { placementId: 13144370 } }, { - bidder: 'other' + bidder: 'smartadserver', + params: { + siteId: 207435, + pageId: 896536, + formatId: 62913 + } + }, { + bidder: 'proxistore', + params: {website: 'demo.sirdata.com', language: 'fr'}, + adUnitCode: 'HALFPAGE_CENTER_LOADER', + transactionId: '92ac333a-a569-4827-abf1-01fc9d19278a', + sizes: [[300, 600]], + mediaTypes: { + banner: { + filteredSizeConfig: [ + {minViewPort: [1600, 0], sizes: [[300, 600]]}, + ], + sizeConfig: [ + {minViewPort: [0, 0], sizes: [[300, 600]]}, + {minViewPort: [768, 0], sizes: [[300, 600]]}, + {minViewPort: [1200, 0], sizes: [[300, 600]]}, + {minViewPort: [1600, 0], sizes: [[300, 600]]}, + ], + sizes: [[300, 600]], + }, + }, + bidId: '190bab495bc5f6e', + bidderRequestId: '18c0b0f0c91cd88', + auctionId: '9bdd917b-908d-4d9f-8f2f-d443277a62fc', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + }, { + bidder: 'ix', + params: { + siteId: '12345', + size: [300, 600] + } + }, { + bidder: 'rubicon', + params: { + accountId: 14062, + siteId: 70608, + zoneId: 498816 + } }] - }] + }], + ortb2Fragments: { + global: {} + } }; let data = { - segments: [111111, 222222], - contextual_categories: {'333333': 100} + 'segments': [111111, 222222], + 'segtaxid': null, + 'cattaxid': null, + 'contextual_categories': {'333333': 100}, + 'shared_taxonomy': { + '27440': { + 'segments': [444444, 555555], + 'segtaxid': 552, + 'cattaxid': 553, + 'contextual_categories': {'666666': 100} + } + }, + 'global_taxonomy': { + '9998': { + 'segments': [123, 234], + 'segtaxid': 4, + 'cattaxid': 7, + 'contextual_categories': {'345': 100, '456': 100} + } + } }; - getSegmentsAndCategories(reqBidsConfigObj, () => {}, config, {}); + getSegmentsAndCategories(reqBidsConfigObj, () => { + }, config, {}); let request = server.requests[0]; request.respond(200, responseHeader, JSON.stringify(data)); - expect(reqBidsConfigObj.adUnits[0].bids[0].params.keywords).to.have.deep.property('sd_rtd', ['111111', '222222', '333333']); - expect(reqBidsConfigObj.adUnits[0].bids[1].ortb2.site.ext.data).to.have.deep.property('sd_rtd', ['333333']); - expect(reqBidsConfigObj.adUnits[0].bids[1].ortb2.user.ext.data).to.have.deep.property('sd_rtd', ['111111', '222222']); + expect(reqBidsConfigObj.adUnits[0].bids[1].params).to.have.deep.property('target', 'sd_rtd=111111;sd_rtd=222222;sd_rtd=333333;sd_rtd=444444;sd_rtd=555555;sd_rtd=666666'); + + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].name).to.equal( + 'sirdata.com' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].segment).to.eql([ + {id: '345'}, + {id: '456'} + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.site.content.data[0].ext.segtax).to.equal(7); + + expect(reqBidsConfigObj.ortb2Fragments.global.user.data[0].name).to.equal( + 'sirdata.com' + ); + expect(reqBidsConfigObj.ortb2Fragments.global.user.data[0].segment).to.eql([ + {id: '123'}, + {id: '234'} + ]); + expect(reqBidsConfigObj.ortb2Fragments.global.user.data[0].ext.segtax).to.equal(4); }); }); }); From 045eb801bb6891eb3a1dedf8430e7e2ac592fe18 Mon Sep 17 00:00:00 2001 From: Gabriel Chicoye Date: Wed, 8 Feb 2023 15:12:06 +0100 Subject: [PATCH 335/367] Nexx360 Bid Adapter: League-m alias added (#9518) * bidderCode fix * League-m added as alias --- modules/nexx360BidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nexx360BidAdapter.js b/modules/nexx360BidAdapter.js index 6ead44175e9..397196ee7a9 100644 --- a/modules/nexx360BidAdapter.js +++ b/modules/nexx360BidAdapter.js @@ -23,13 +23,13 @@ export const spec = { { code: 'revenuemaker' }, { code: 'first-id', gvlid: 1178 }, { code: 'adwebone' }, + { code: 'league-m', gvlid: 965 } ], supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid, buildRequests, interpretResponse, getUserSyncs, - // onBidWon, }; registerBidder(spec); From e88c872c691387554151e589ed75fde7ddf3aa42 Mon Sep 17 00:00:00 2001 From: couchcrew-thomas Date: Wed, 8 Feb 2023 15:44:06 +0100 Subject: [PATCH 336/367] Feedad Bid Adapter: updated user-sync handling (#9519) * added file scaffold * added isBidRequestValid implementation * added local prototype of ad integration * added implementation for placement ID validation * fixed video context filter * applied lint to feedad bid adapter * added unit test for bid request validation * added buildRequest unit test * added unit tests for timeout and bid won callbacks * updated bid request to FeedAd API * added parsing of feedad api bid response * added transmisison of tracking events to FeedAd Api * code cleanup * updated feedad unit tests for buildRequest method * added unit tests for event tracking implementation * added unit test for interpretResponse method * added adapter documentation * added dedicated feedad example page * updated feedad adapter to use live system * updated FeedAd adapter placement ID regex * removed groups from FeedAd adapter placement ID regex * removed dedicated feedad example page * updated imports in FeedAd adapter file to use relative paths * updated FeedAd adapter unit test to use sinon.useFakeXMLHttpRequest() * added GDPR fields to the FeedAd bid request * removed video from supported media types of the FeedAd adapter * increased version code of FeedAd adapter to 1.0.2 * removed unnecessary check of bidder request * fixed unit test testing for old FeedAd version * removed video media type example from documentation file * added gvlid to FeedAd adapter * added decoration parameter to adapter documentation * added pass through of additional bid parameters * added user syncs to FeedAd bid adapter * increased FeedAd bid adapter version * lint pass over FeedAd bid adapter * fixed parsing of user syncs from server response * increased FeedAd bid adapter version * fixed version code in test file * added adapter and prebid version to bid request parameters * removed TODO item * added missing test case for user syncs * increased adapter version to 1.0.5 * updated from upstream * updated from upstream * updated user sync to accept multiple server responses * increased FeedAd bid adapter version code * fixed test case * fixed lint errors --- modules/feedadBidAdapter.js | 50 ++++++--- test/spec/modules/feedadBidAdapter_spec.js | 124 ++++++++------------- 2 files changed, 82 insertions(+), 92 deletions(-) diff --git a/modules/feedadBidAdapter.js b/modules/feedadBidAdapter.js index 7b684efab3c..34e14cd674a 100644 --- a/modules/feedadBidAdapter.js +++ b/modules/feedadBidAdapter.js @@ -7,7 +7,23 @@ import {ajax} from '../src/ajax.js'; * Version of the FeedAd bid adapter * @type {string} */ -const VERSION = '1.0.5'; +const VERSION = '1.0.6'; + +/** + * @typedef {object} FeedAdUserSync + * @inner + * + * @property {string} type + * @property {string} url + */ + +/** + * @typedef {object} FeedAdBidExtension + * @inner + * + * @property {FeedAdUserSync[]} pixels + * @property {FeedAdUserSync[]} iframes + */ /** * @typedef {object} FeedAdApiBidRequest @@ -41,7 +57,7 @@ const VERSION = '1.0.5'; * @property {string} requestId - bids[].bidId * @property {number} ttl - Time to live for this ad * @property {number} width - Width of creative returned in [].ad - * @property {object} [ext] - an extension object + * @property {FeedAdBidExtension} [ext] - an extension object */ /** @@ -63,6 +79,14 @@ const VERSION = '1.0.5'; * @property [device_platform] {1|2|3} 1 - Android | 2 - iOS | 3 - Windows */ +/** + * @typedef {object} FeedAdServerResponse + * @extends ServerResponse + * @inner + * + * @property {FeedAdApiBidResponse[]} body - the body of a FeedAd server response + */ + /** * The IAB TCF 2.0 vendor ID for the FeedAd GmbH */ @@ -228,7 +252,7 @@ function buildRequests(validBidRequests, bidderRequest) { /** * Adapts the FeedAd server response to Prebid format - * @param {ServerResponse} serverResponse - the FeedAd server response + * @param {FeedAdServerResponse} serverResponse - the FeedAd server response * @param {BidRequest} request - the initial bid request * @returns {Bid[]} the FeedAd bids */ @@ -296,24 +320,20 @@ function trackingHandlerFactory(klass) { /** * Reads the user syncs off the server responses and converts them into Prebid.JS format * @param {SyncOptions} syncOptions - * @param {ServerResponse[]} serverResponses + * @param {FeedAdServerResponse[]} serverResponses * @param gdprConsent * @param uspConsent */ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { - return serverResponses.map(response => { - // validate response format - const ext = deepAccess(response, 'body.ext', []); - if (ext == null) { - return null; - } - return ext; + return serverResponses.flatMap(response => { + // merge all response bodies into one + const body = response.body; + return isArray(body) ? body : []; }) - .filter(ext => ext != null) - .flatMap(extension => { + .flatMap(/** @param {FeedAdApiBidResponse} bidResponse */ bidResponse => { // extract user syncs from extension - const pixels = syncOptions.pixelEnabled && extension.pixels ? extension.pixels : []; - const iframes = syncOptions.iframeEnabled && extension.iframes ? extension.iframes : []; + const pixels = (syncOptions.pixelEnabled && bidResponse?.ext?.pixels) ? bidResponse.ext.pixels : []; + const iframes = (syncOptions.iframeEnabled && bidResponse?.ext?.iframes) ? bidResponse.ext.iframes : []; return pixels.concat(...iframes); }) .reduce((syncs, sync) => { diff --git a/test/spec/modules/feedadBidAdapter_spec.js b/test/spec/modules/feedadBidAdapter_spec.js index 8cbd6907890..5789361d2a1 100644 --- a/test/spec/modules/feedadBidAdapter_spec.js +++ b/test/spec/modules/feedadBidAdapter_spec.js @@ -4,7 +4,7 @@ import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes.js'; import {server} from 'test/mocks/xhr.js'; const CODE = 'feedad'; -const EXPECTED_ADAPTER_VERSION = '1.0.5'; +const EXPECTED_ADAPTER_VERSION = '1.0.6'; describe('FeedAdAdapter', function () { describe('Public API', function () { @@ -373,81 +373,67 @@ describe('FeedAdAdapter', function () { const pixelSync2 = {type: 'image', url: 'the pixel url 2'}; const iFrameSync1 = {type: 'iframe', url: 'the iFrame url 1'}; const iFrameSync2 = {type: 'iframe', url: 'the iFrame url 2'}; - const mockServerResponse = (content) => { - if (!(content instanceof Array)) { - content = [content]; - } - return content.map(it => ({body: it})); - }; - - it('should pass through the syncs out of the extension fields of the server response', function () { - const serverResponse = mockServerResponse([{ + const response1 = { + body: [{ ext: { pixels: [pixelSync1, pixelSync2], - iframes: [iFrameSync1, iFrameSync2], + iframes: [iFrameSync1] + }, + }] + }; + const response2 = { + body: [{ + ext: { + pixels: [pixelSync1], + iframes: [iFrameSync1], } - }]); - const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse) + }, { + ext: { + pixels: [pixelSync2], + iframes: [iFrameSync2], + } + }] + }; + it('should pass through the syncs out of the extension fields of the server response', function () { + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [response1]) expect(result).to.deep.equal([ pixelSync1, pixelSync2, iFrameSync1, - iFrameSync2, ]); }); it('should concat the syncs of all responses', function () { - const serverResponse = mockServerResponse([{ - ext: { - pixels: [pixelSync1], - iframes: [iFrameSync2], - }, - ad: 'ad html', - cpm: 100 - }, { - ext: { - iframes: [iFrameSync1], - } - }, { - ext: { - pixels: [pixelSync2], - } - }]); - const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse); + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [response1, response2]); expect(result).to.deep.equal([ pixelSync1, + pixelSync2, + iFrameSync1, iFrameSync2, + ]); + }); + + it('should concat the syncs of all bids', function () { + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [response2]); + expect(result).to.deep.equal([ + pixelSync1, iFrameSync1, pixelSync2, + iFrameSync2, ]); }); it('should filter out duplicates', function () { - const serverResponse = mockServerResponse([{ - ext: { - pixels: [pixelSync1, pixelSync1], - iframes: [iFrameSync2, iFrameSync2], - } - }, { - ext: { - iframes: [iFrameSync2, iFrameSync2], - } - }]); - const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse); + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [response1, response1]); expect(result).to.deep.equal([ pixelSync1, - iFrameSync2, + pixelSync2, + iFrameSync1, ]); }); it('should not include iFrame syncs if the option is disabled', function () { - const serverResponse = mockServerResponse([{ - ext: { - pixels: [pixelSync1, pixelSync2], - iframes: [iFrameSync1, iFrameSync2], - } - }]); - const result = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, serverResponse); + const result = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [response1]); expect(result).to.deep.equal([ pixelSync1, pixelSync2, @@ -455,52 +441,36 @@ describe('FeedAdAdapter', function () { }); it('should not include pixel syncs if the option is disabled', function () { - const serverResponse = mockServerResponse([{ - ext: { - pixels: [pixelSync1, pixelSync2], - iframes: [iFrameSync1, iFrameSync2], - } - }]); - const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, serverResponse); + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, [response1]); expect(result).to.deep.equal([ iFrameSync1, - iFrameSync2, ]); }); it('should not include any syncs if the sync options are disabled or missing', function () { - const serverResponse = mockServerResponse([{ - ext: { - pixels: [pixelSync1, pixelSync2], - iframes: [iFrameSync1, iFrameSync2], - } - }]); - const result = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false}, serverResponse); + const result = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false}, [response1]); expect(result).to.deep.equal([]); }); it('should handle empty responses', function () { - const serverResponse = mockServerResponse([]); - const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse) + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, []) expect(result).to.deep.equal([]); }); it('should not throw if the server response is weird', function () { const responses = [ - mockServerResponse(null), - mockServerResponse('null'), - mockServerResponse(1234), - mockServerResponse({}), - mockServerResponse([{}, 123]), + {body: null}, + {body: 'null'}, + {body: 1234}, + {body: {}}, + {body: [{}, 123]}, ]; - responses.forEach(it => { - expect(() => spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, it)).not.to.throw; - }); + expect(() => spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, responses)).to.not.throw(); }); it('should return empty array if the body extension is null', function () { - const response = mockServerResponse({ext: null}); - const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, response); + const response = {body: [{ext: null}]}; + const result = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [response]); expect(result).to.deep.equal([]); }); }); From 7e41def99c556b88b12fb6857ff28dc4ac6fbebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20DEYM=C3=88S?= <47388595+MaxSmileWanted@users.noreply.github.com> Date: Wed, 8 Feb 2023 15:45:32 +0100 Subject: [PATCH 337/367] Adding support of eids for smilewanted (#9440) --- modules/smilewantedBidAdapter.js | 5 ++ .../modules/smilewantedBidAdapter_spec.js | 57 ++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/modules/smilewantedBidAdapter.js b/modules/smilewantedBidAdapter.js index f82e7c9258f..fe14c57d641 100644 --- a/modules/smilewantedBidAdapter.js +++ b/modules/smilewantedBidAdapter.js @@ -63,6 +63,11 @@ export const spec = { payload.gdpr_consent = bidderRequest.gdprConsent.consentString; payload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side } + + if (bid && bid.userIdAsEids) { + payload.eids = bid.userIdAsEids; + } + var payloadString = JSON.stringify(payload); return { method: 'POST', diff --git a/test/spec/modules/smilewantedBidAdapter_spec.js b/test/spec/modules/smilewantedBidAdapter_spec.js index b9a816cf3d5..44d2c7c6507 100644 --- a/test/spec/modules/smilewantedBidAdapter_spec.js +++ b/test/spec/modules/smilewantedBidAdapter_spec.js @@ -1,9 +1,6 @@ import { expect } from 'chai'; 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', @@ -20,6 +17,37 @@ const DISPLAY_REQUEST = [{ transactionId: 'trans_abcd1234' }]; +const DISPLAY_REQUEST_WITH_EIDS = [{ + adUnitCode: 'sw_300x250', + bidId: '12345', + sizes: [ + [300, 250], + [300, 200] + ], + bidder: 'smilewanted', + params: { + zoneId: 1 + }, + requestId: 'request_abcd1234', + transactionId: 'trans_abcd1234', + 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' + } + }] + }] +}]; + const DISPLAY_REQUEST_WITH_POSITION_TYPE = [{ adUnitCode: 'sw_300x250', bidId: '12345', @@ -170,6 +198,29 @@ describe('smilewantedBidAdapterTests', function () { expect(requestContent).to.have.property('pageDomain').and.to.equal('https://localhost/Prebid.js/integrationExamples/gpt/hello_world.html'); }); + it('Verify external ids in request and ids found', function () { + config.setConfig({ + 'currency': { + 'adServerCurrency': 'EUR' + } + }); + const request = spec.buildRequests(DISPLAY_REQUEST_WITH_EIDS, {}); + 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('gdpr tests', function () { afterEach(function () { config.resetConfig(); From cd829a5f03e30288681c0903ce137bf7a5f2dcdc Mon Sep 17 00:00:00 2001 From: ccorbo Date: Wed, 8 Feb 2023 09:51:33 -0500 Subject: [PATCH 338/367] IX Bid Adapter - Add support for IMUID (#9500) * feat: add imuid to pbjs adapter [PB-1434] * chore: add unit test [PB-1434] --------- Co-authored-by: Chris Corbo --- modules/ixBidAdapter.js | 3 ++- test/spec/modules/ixBidAdapter_spec.js | 17 +++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index bd598cf2d04..29cda657f5b 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -76,7 +76,8 @@ const SOURCE_RTI_MAPPING = { 'epsilon.com': '', // Publisher Link, publinkId 'audigent.com': '', // Hadron ID from Audigent, hadronId 'pubcid.org': '', // SharedID, pubcid - 'trustpid.com': '' // Trustpid + 'trustpid.com': '', // Trustpid + 'intimatemerger.com': '' }; const PROVIDERS = [ 'britepoolid', diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 2327376d9ac..f681e7786ae 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -750,7 +750,8 @@ describe('IndexexchangeAdapter', function () { // so structured because when calling createEidsArray, UID2's getValue func takes .id to set in uids uid2: { id: 'testuid2' }, // UID 2.0 // similar to uid2, but id5's getValue takes .uid - id5id: { uid: 'testid5id' } // ID5 + id5id: { uid: 'testid5id' }, // ID5 + imuid: 'testimuid' }; const DEFAULT_USERIDASEIDS_DATA = createEidsArray(DEFAULT_USERID_DATA); @@ -801,6 +802,11 @@ describe('IndexexchangeAdapter', function () { uids: [{ id: DEFAULT_USERID_DATA.id5id.uid }] + }, { + source: 'intimatemerger.com', + uids: [{ + id: DEFAULT_USERID_DATA.imuid, + }] } ]; @@ -1193,7 +1199,7 @@ describe('IndexexchangeAdapter', function () { const payload = extractPayload(request[0]); expect(request).to.be.an('array'); expect(request).to.have.lengthOf.above(0); // should be 1 or more - expect(payload.user.eids).to.have.lengthOf(6); + expect(payload.user.eids).to.have.lengthOf(7); expect(payload.user.eids).to.deep.include(DEFAULT_USERID_PAYLOAD[0]); }); }); @@ -1381,8 +1387,7 @@ describe('IndexexchangeAdapter', function () { cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA); const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; const payload = extractPayload(request); - - expect(payload.user.eids).to.have.lengthOf(6); + expect(payload.user.eids).to.have.lengthOf(7); expect(payload.user.eids).to.have.deep.members(DEFAULT_USERID_PAYLOAD); }); @@ -1515,7 +1520,7 @@ describe('IndexexchangeAdapter', function () { }) expect(payload.user).to.exist; - expect(payload.user.eids).to.have.lengthOf(8); + expect(payload.user.eids).to.have.lengthOf(9); expect(payload.user.eids).to.have.deep.members(validUserIdPayload); }); @@ -1557,7 +1562,7 @@ describe('IndexexchangeAdapter', function () { }); const payload = extractPayload(request); - expect(payload.user.eids).to.have.lengthOf(7); + expect(payload.user.eids).to.have.lengthOf(8); expect(payload.user.eids).to.have.deep.members(validUserIdPayload); }); }); From c5f62215e7ea69fdbd6549792abd3150218ea985 Mon Sep 17 00:00:00 2001 From: Krzysztof Desput Date: Wed, 8 Feb 2023 16:03:03 +0100 Subject: [PATCH 339/367] Admaru Bid Adapter: Add user sync (#9444) * AdmaruBidAdapter: add user sync * AdmaruBidAdapter: Use https in user sync --- modules/admaruBidAdapter.js | 20 ++++++++- test/spec/modules/admaruBidAdapter_spec.js | 48 ++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/modules/admaruBidAdapter.js b/modules/admaruBidAdapter.js index 65f62c77e26..f681a9a4191 100644 --- a/modules/admaruBidAdapter.js +++ b/modules/admaruBidAdapter.js @@ -5,6 +5,7 @@ const ADMARU_ENDPOINT = 'https://p1.admaru.net/AdCall'; const BIDDER_CODE = 'admaru'; const DEFAULT_BID_TTL = 360; +const SYNC_URL = 'https://p2.admaru.net/UserSync/sync' function parseBid(rawBid, currency) { const bid = {}; @@ -75,7 +76,24 @@ export const spec = { } return bidResponses; - } + }, + + getUserSyncs: function (syncOptions, responses) { + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: SYNC_URL + }]; + } + if (syncOptions.pixelEnabled) { + return [{ + type: 'image', + url: SYNC_URL + }]; + } + + return []; + }, } registerBidder(spec); diff --git a/test/spec/modules/admaruBidAdapter_spec.js b/test/spec/modules/admaruBidAdapter_spec.js index a45ddae108f..813a4ed8b29 100644 --- a/test/spec/modules/admaruBidAdapter_spec.js +++ b/test/spec/modules/admaruBidAdapter_spec.js @@ -121,4 +121,52 @@ describe('Admaru Adapter', function () { expect(result.length).to.equal(0); }); }); + + describe('getUserSyncs()', () => { + it('should return iframe user sync if iframe sync is enabled', () => { + const syncs = spec.getUserSyncs( + { + pixelEnabled: true, + iframeEnabled: true, + }, + null + ); + + expect(syncs).to.deep.equal([ + { + type: 'iframe', + url: 'https://p2.admaru.net/UserSync/sync', + }, + ]); + }); + + it('should return image syncs if they are enabled and iframe is disabled', () => { + const syncs = spec.getUserSyncs( + { + pixelEnabled: true, + iframeEnabled: false, + }, + null + ); + + expect(syncs).to.deep.equal([ + { + type: 'image', + url: 'https://p2.admaru.net/UserSync/sync', + }, + ]); + }); + + it('should not return user syncs if syncs are disabled', () => { + const syncs = spec.getUserSyncs( + { + pixelEnabled: false, + iframeEnabled: false, + }, + null + ); + + expect(syncs).to.deep.equal([]); + }); + }); }); From 0442955a6f3e965c38040232415206063a8a70cb Mon Sep 17 00:00:00 2001 From: Alexander Pykhteyev Date: Wed, 8 Feb 2023 22:15:30 +0700 Subject: [PATCH 340/367] Limelight Digital Bid Adapter: added new custom fields for targeting (#9436) * Added new custom fields (#2) * Fixed integration * Fixes after review * Fixes after review --------- Co-authored-by: RuzannaAvetisyan <44729750+RuzannaAvetisyan@users.noreply.github.com> Co-authored-by: apykhteyev --- modules/limelightDigitalBidAdapter.js | 7 +++- modules/limelightDigitalBidAdapter.md | 14 ++++++- .../limelightDigitalBidAdapter_spec.js | 40 ++++++++++++++++--- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/modules/limelightDigitalBidAdapter.js b/modules/limelightDigitalBidAdapter.js index 87cf6e4fe21..601d78578b3 100644 --- a/modules/limelightDigitalBidAdapter.js +++ b/modules/limelightDigitalBidAdapter.js @@ -158,7 +158,12 @@ function buildPlacement(bidRequest) { type: bidRequest.params.adUnitType.toUpperCase(), publisherId: bidRequest.params.publisherId, userIdAsEids: bidRequest.userIdAsEids, - supplyChain: bidRequest.schain + supplyChain: bidRequest.schain, + custom1: bidRequest.params.custom1, + custom2: bidRequest.params.custom2, + custom3: bidRequest.params.custom3, + custom4: bidRequest.params.custom4, + custom5: bidRequest.params.custom5 } } } diff --git a/modules/limelightDigitalBidAdapter.md b/modules/limelightDigitalBidAdapter.md index a4abb6f1411..2c773859a7f 100644 --- a/modules/limelightDigitalBidAdapter.md +++ b/modules/limelightDigitalBidAdapter.md @@ -24,7 +24,12 @@ var adUnits = [{ params: { host: 'exchange-9qao.ortb.net', adUnitId: 0, - adUnitType: 'banner' + adUnitType: 'banner', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' } }] }]; @@ -40,7 +45,12 @@ var videoAdUnit = [{ params: { host: 'exchange-9qao.ortb.net', adUnitId: 0, - adUnitType: 'video' + adUnitType: 'video', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' } }] }]; diff --git a/test/spec/modules/limelightDigitalBidAdapter_spec.js b/test/spec/modules/limelightDigitalBidAdapter_spec.js index 4efb4f4e84d..5a92110abb4 100644 --- a/test/spec/modules/limelightDigitalBidAdapter_spec.js +++ b/test/spec/modules/limelightDigitalBidAdapter_spec.js @@ -10,7 +10,12 @@ describe('limelightDigitalAdapter', function () { host: 'exchange.ortb.net', adUnitId: 123, adUnitType: 'banner', - publisherId: 'perfectPublisher' + publisherId: 'perfectPublisher', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' }, placementCode: 'placement_0', auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', @@ -49,7 +54,12 @@ describe('limelightDigitalAdapter', function () { params: { host: 'ads.project-limelight.com', adUnitId: 456, - adUnitType: 'banner' + adUnitType: 'banner', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' }, placementCode: 'placement_1', auctionId: '482f88de-29ab-45c8-981a-d25e39454a34', @@ -90,7 +100,12 @@ describe('limelightDigitalAdapter', function () { host: 'exchange.ortb.net', adUnitId: 789, adUnitType: 'video', - publisherId: 'secondPerfectPublisher' + publisherId: 'secondPerfectPublisher', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' }, placementCode: 'placement_2', auctionId: 'e4771143-6aa7-41ec-8824-ced4342c96c8', @@ -128,7 +143,12 @@ describe('limelightDigitalAdapter', function () { params: { host: 'exchange.ortb.net', adUnitId: 789, - adUnitType: 'video' + adUnitType: 'video', + custom1: 'custom1', + custom2: 'custom2', + custom3: 'custom3', + custom4: 'custom4', + custom5: 'custom5' }, placementCode: 'placement_2', auctionId: 'e4771143-6aa7-41ec-8824-ced4342c96c8', @@ -196,7 +216,12 @@ describe('limelightDigitalAdapter', function () { 'transactionId', 'publisherId', 'userIdAsEids', - 'supplyChain' + 'supplyChain', + 'custom1', + 'custom2', + 'custom3', + 'custom4', + 'custom5' ); expect(adUnit.id).to.be.a('number'); expect(adUnit.bidId).to.be.a('string'); @@ -205,6 +230,11 @@ describe('limelightDigitalAdapter', function () { expect(adUnit.sizes).to.be.an('array'); expect(adUnit.userIdAsEids).to.be.an('array'); expect(adUnit.supplyChain).to.be.an('object'); + expect(adUnit.custom1).to.be.a('string'); + expect(adUnit.custom2).to.be.a('string'); + expect(adUnit.custom3).to.be.a('string'); + expect(adUnit.custom4).to.be.a('string'); + expect(adUnit.custom5).to.be.a('string'); }) }) }) From 9bda8871c780fc6b4b23e24c3c1511210f64a3b2 Mon Sep 17 00:00:00 2001 From: jsnellbaker <31102355+jsnellbaker@users.noreply.github.com> Date: Wed, 8 Feb 2023 10:20:27 -0500 Subject: [PATCH 341/367] Appnexus Bid Adapter : support alternate format for bid.params properties (#9503) * appnexus bid adapter - support alternate format for params * fix lint error --- modules/appnexusBidAdapter.js | 58 ++++++---- test/spec/modules/appnexusBidAdapter_spec.js | 109 ++++++++++++++++--- 2 files changed, 128 insertions(+), 39 deletions(-) diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index b64334b0d77..5d233756522 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -44,7 +44,7 @@ const URL_SIMPLE = 'https://ib.adnxs-simple.com/ut/v3/prebid'; const VIDEO_TARGETING = ['id', 'minduration', 'maxduration', 'skippable', 'playback_method', 'frameworks', 'context', 'skipoffset']; const VIDEO_RTB_TARGETING = ['minduration', 'maxduration', 'skip', 'skipafter', 'playbackmethod', 'api', 'startdelay']; -const USER_PARAMS = ['age', 'externalUid', 'segments', 'gender', 'dnt', 'language']; +const USER_PARAMS = ['age', 'externalUid', 'external_uid', 'segments', 'gender', 'dnt', 'language']; const APP_DEVICE_PARAMS = ['geo', 'device_id']; // appid is collected separately const DEBUG_PARAMS = ['enabled', 'dongle', 'member_id', 'debug_timeout']; const DEBUG_QUERY_PARAM_MAP = { @@ -120,7 +120,9 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function (bid) { - return !!(bid.params.placementId || (bid.params.member && bid.params.invCode)); + return !!( + (bid.params.placementId || bid.params.placement_id) || + (bid.params.member && (bid.params.invCode || bid.params.inv_code))); }, /** @@ -484,9 +486,6 @@ export const spec = { }, params); if (isOpenRtb) { - params.use_pmt_rule = (typeof params.usePaymentRule === 'boolean') ? params.usePaymentRule : false; - if (params.usePaymentRule) { delete params.usePaymentRule; } - if (isPopulatedArray(params.keywords)) { params.keywords.forEach(deleteValues); } @@ -498,6 +497,9 @@ export const spec = { delete params[paramKey]; } }); + + params.use_pmt_rule = (typeof params.use_payment_rule === 'boolean') ? params.use_payment_rule : false; + if (params.use_payment_rule) { delete params.use_payment_rule; } } return params; @@ -771,17 +773,25 @@ function newBid(serverBid, rtbBid, bidderRequest) { function bidToTag(bid) { const tag = {}; + Object.keys(bid.params).forEach(paramKey => { + let convertedKey = convertCamelToUnderscore(paramKey); + if (convertedKey !== paramKey) { + bid.params[convertedKey] = bid.params[paramKey]; + delete bid.params[paramKey]; + } + }); tag.sizes = transformSizes(bid.sizes); tag.primary_size = tag.sizes[0]; tag.ad_types = []; tag.uuid = bid.bidId; - if (bid.params.placementId) { - tag.id = parseInt(bid.params.placementId, 10); + if (bid.params.placement_id) { + tag.id = parseInt(bid.params.placement_id, 10); } else { - tag.code = bid.params.invCode; + tag.code = bid.params.inv_code; } - tag.allow_smaller_sizes = bid.params.allowSmallerSizes || false; - tag.use_pmt_rule = bid.params.usePaymentRule || false; + tag.allow_smaller_sizes = bid.params.allow_smaller_sizes || false; + tag.use_pmt_rule = (typeof bid.params.use_payment_rule === 'boolean') ? bid.params.use_payment_rule + : (typeof bid.params.use_pmt_rule === 'boolean') ? bid.params.use_pmt_rule : false; tag.prebid = true; tag.disable_psa = true; let bidFloor = getBidFloor(bid); @@ -798,26 +808,26 @@ function bidToTag(bid) { tag.position = (mediaTypePos === 3) ? 2 : mediaTypePos; } } - if (bid.params.trafficSourceCode) { - tag.traffic_source_code = bid.params.trafficSourceCode; + if (bid.params.traffic_source_code) { + tag.traffic_source_code = bid.params.traffic_source_code; } - if (bid.params.privateSizes) { - tag.private_sizes = transformSizes(bid.params.privateSizes); + if (bid.params.private_sizes) { + tag.private_sizes = transformSizes(bid.params.private_sizes); } - if (bid.params.supplyType) { - tag.supply_type = bid.params.supplyType; + if (bid.params.supply_type) { + tag.supply_type = bid.params.supply_type; } - if (bid.params.pubClick) { - tag.pubclick = bid.params.pubClick; + if (bid.params.pub_click) { + tag.pubclick = bid.params.pub_click; } - if (bid.params.extInvCode) { - tag.ext_inv_code = bid.params.extInvCode; + if (bid.params.ext_inv_code) { + tag.ext_inv_code = bid.params.ext_inv_code; } - if (bid.params.publisherId) { - tag.publisher_id = parseInt(bid.params.publisherId, 10); + if (bid.params.publisher_id) { + tag.publisher_id = parseInt(bid.params.publisher_id, 10); } - if (bid.params.externalImpId) { - tag.external_imp_id = bid.params.externalImpId; + if (bid.params.external_imp_id) { + tag.external_imp_id = bid.params.external_imp_id; } let ortb2ImpKwStr = deepAccess(bid, 'ortb2Imp.ext.data.keywords'); diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index a5bd9a3592e..d4644039885 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -36,14 +36,31 @@ describe('AppNexusAdapter', function () { }); it('should return true when required params found', function () { - let bid = Object.assign({}, bid); - delete bid.params; - bid.params = { + let bid1 = deepClone(bid); + bid1.params = { + 'placement_id': 123423 + } + expect(spec.isBidRequestValid(bid1)).to.equal(true); + }); + + it('should return true when required params found', function () { + let bid1 = deepClone(bid); + bid1.params = { 'member': '1234', 'invCode': 'ABCD' }; - expect(spec.isBidRequestValid(bid)).to.equal(true); + expect(spec.isBidRequestValid(bid1)).to.equal(true); + }); + + it('should return true when required params found', function () { + let bid1 = deepClone(bid); + bid1.params = { + 'member': '1234', + 'inv_code': 'ABCD' + }; + + expect(spec.isBidRequestValid(bid1)).to.equal(true); }); it('should return false when required params are not passed', function () { @@ -54,6 +71,15 @@ describe('AppNexusAdapter', function () { }; expect(spec.isBidRequestValid(bid)).to.equal(false); }); + + it('should return false when required params are not passed', function () { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + 'placement_id': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); }); describe('buildRequests', function () { @@ -101,6 +127,24 @@ describe('AppNexusAdapter', function () { expect(payload.tags[0].private_sizes).to.deep.equal([{ width: 300, height: 250 }]); }); + it('should parse out private sizes', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placementId: '10433394', + private_sizes: [300, 250] + } + } + ); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].private_sizes).to.exist; + expect(payload.tags[0].private_sizes).to.deep.equal([{ width: 300, height: 250 }]); + }); + it('should add position in request', function () { // set from bid.params let bidRequest = deepClone(bidRequests[0]); @@ -168,6 +212,24 @@ describe('AppNexusAdapter', function () { expect(payload.publisher_id).to.deep.equal(1231234); }); + it('should add publisher_id in request', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placement_id: '10433394', + publisher_id: '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); @@ -189,7 +251,7 @@ describe('AppNexusAdapter', function () { bids: [{ bidder: 'appnexus', params: { - placementId: '10433394' + placement_id: '10433394' } }], transactionId: '04f2659e-c005-4eb1-a57c-fa93145e3843' @@ -351,7 +413,7 @@ describe('AppNexusAdapter', function () { bidRequests[0], { params: { - placementId: '10433394', + placement_id: '10433394', user: { externalUid: '123', segments: [123, { id: 987, value: 876 }], @@ -407,7 +469,7 @@ describe('AppNexusAdapter', function () { // 2 -> reserve is defined, getFloor not defined > reserve is used bidRequest.params = { - 'placementId': '10433394', + 'placement_id': '10433394', 'reserve': 0.5 }; request = spec.buildRequests([bidRequest]); @@ -428,7 +490,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -461,7 +523,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -484,7 +546,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -526,7 +588,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -557,7 +619,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -585,7 +647,7 @@ describe('AppNexusAdapter', function () { let bidRequest = Object.assign({}, bidRequests[0], { - params: { placementId: '14542875' } + params: { placement_id: '14542875' } }, { mediaTypes: { @@ -610,7 +672,7 @@ describe('AppNexusAdapter', function () { mediaType: 'banner', params: { sizes: [[300, 250], [300, 600]], - placementId: 13144370 + placement_id: 13144370 } } ); @@ -786,7 +848,7 @@ describe('AppNexusAdapter', function () { bidRequests[0], { params: { - placementId: '10433394', + placement_id: '10433394', keywords: { single: 'val', singleArr: ['val'], @@ -931,6 +993,23 @@ describe('AppNexusAdapter', function () { expect(payload.tags[0].use_pmt_rule).to.equal(true); }); + it('should add payment rules to the request', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placement_id: '10433394', + use_payment_rule: true + } + } + ); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].use_pmt_rule).to.equal(true); + }); + it('should add gpid to the request', function () { let testGpid = '/12345/my-gpt-tag-0'; let bidRequest = deepClone(bidRequests[0]); From 79436ef83878c5bef8dc7613bbd7d0104b5b6610 Mon Sep 17 00:00:00 2001 From: jsnellbaker <31102355+jsnellbaker@users.noreply.github.com> Date: Wed, 8 Feb 2023 10:31:42 -0500 Subject: [PATCH 342/367] appnexus bid adapter - userid support update (#9507) --- modules/appnexusBidAdapter.js | 35 ++++++-------------- test/spec/modules/appnexusBidAdapter_spec.js | 30 ++++++++++++++++- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index 5d233756522..f354eb053b1 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -345,20 +345,18 @@ export const spec = { if (bidRequests[0].userId) { let eids = []; - - addUserId(eids, deepAccess(bidRequests[0], `userId.criteoId`), 'criteo.com', null); - addUserId(eids, deepAccess(bidRequests[0], `userId.netId`), 'netid.de', null); - addUserId(eids, deepAccess(bidRequests[0], `userId.idl_env`), 'liveramp.com', null); - addUserId(eids, deepAccess(bidRequests[0], `userId.tdid`), 'adserver.org', 'TDID'); - addUserId(eids, deepAccess(bidRequests[0], `userId.uid2.id`), 'uidapi.com', 'UID2'); - if (bidRequests[0].userId.pubProvidedId) { - bidRequests[0].userId.pubProvidedId.forEach(ppId => { - ppId.uids.forEach(uid => { - eids.push({ source: ppId.source, id: uid.id }); - }); + bidRequests[0].userIdAsEids.forEach(eid => { + if (!eid || !eid.uids || eid.uids.length < 1) { return; } + eid.uids.forEach(uid => { + let tmp = {'source': eid.source, 'id': uid.id}; + if (eid.source == 'adserver.org') { + tmp.rti_partner = 'TDID'; + } else if (eid.source == 'uidapi.com') { + tmp.rti_partner = 'UID2'; + } + eids.push(tmp); }); - } - + }); if (eids.length) { payload.eids = eids; } @@ -1228,17 +1226,6 @@ function parseMediaType(rtbBid) { } } -function addUserId(eids, id, source, rti) { - if (id) { - if (rti) { - eids.push({ source, id, rti_partner: rti }); - } else { - eids.push({ source, id }); - } - } - return eids; -} - function getBidFloor(bid) { if (!isFn(bid.getFloor)) { return (bid.params.reserve) ? bid.params.reserve : null; diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index d4644039885..9e88e2875c7 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -1318,9 +1318,33 @@ describe('AppNexusAdapter', function () { source: 'puburl2.com', uids: [{ id: 'pubid2' + }, { + id: 'pubid2-123' }] }] - } + }, + userIdAsEids: [{ + source: 'adserver.org', + uids: [{ id: 'sample-userid' }] + }, { + source: 'criteo.com', + uids: [{ id: 'sample-criteo-userid' }] + }, { + source: 'netid.de', + uids: [{ id: 'sample-netId-userid' }] + }, { + source: 'liveramp.com', + uids: [{ id: 'sample-idl-userid' }] + }, { + source: 'uidapi.com', + uids: [{ id: 'sample-uid2-value' }] + }, { + source: 'puburl.com', + uids: [{ id: 'pubid1' }] + }, { + source: 'puburl2.com', + uids: [{ id: 'pubid2' }, { id: 'pubid2-123' }] + }] }); const request = spec.buildRequests([bidRequest]); @@ -1361,6 +1385,10 @@ describe('AppNexusAdapter', function () { source: 'puburl2.com', id: 'pubid2' }); + expect(payload.eids).to.deep.include({ + source: 'puburl2.com', + id: 'pubid2-123' + }); }); it('should populate iab_support object at the root level if omid support is detected', function () { From 49eaea7ac65bcf95c707451a10c050cbefb8b05c Mon Sep 17 00:00:00 2001 From: shahinrahbariasl <56240400+shahinrahbariasl@users.noreply.github.com> Date: Wed, 8 Feb 2023 11:15:19 -0500 Subject: [PATCH 343/367] IX Bid Adapter: refactor buildRequest method (#9495) * feat: remove request splitting logic [PB-1389] * feat: remove splitting logic behind ft [PB-1389] * feat: remove splitting logic behind ft [PB-1389] * feat: remove splitting logic behind ft [PB-1389] * feat: remove splitting logic behind ft [PB-1389] * feat: remove splitting logic behind ft [PB-1389] * feat: remove splitting logic behind ft [PB-1389] --------- Co-authored-by: shahin.rahbariasl --- modules/ixBidAdapter.js | 490 ++++++++++++++++--------- test/spec/modules/ixBidAdapter_spec.js | 61 +-- 2 files changed, 329 insertions(+), 222 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 29cda657f5b..360a373ba9a 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -152,6 +152,11 @@ const MEDIA_TYPES = { Native: 4 }; +let baseRequestSize = 0; +let currentRequestSize = 0; +let wasAdUnitImpressionsTrimmed = false; +let currentImpressionSize = 0; + /** * Transform valid bid request config object to banner impression object that will be sent to ad server. * @@ -593,34 +598,23 @@ function getEidInfo(allEids) { * */ function buildRequest(validBidRequests, bidderRequest, impressions, version) { + baseRequestSize = 0; + currentRequestSize = 0; + wasAdUnitImpressionsTrimmed = false; + currentImpressionSize = 0; + // Always use secure HTTPS protocol. let baseUrl = SECURE_BID_URL; // Get ids from Prebid User ID Modules let eidInfo = getEidInfo(deepAccess(validBidRequests, '0.userIdAsEids')); let userEids = eidInfo.toSend; - const pageUrl = deepAccess(bidderRequest, 'refererInfo.page'); let MAX_REQUEST_SIZE = 8000; - // Modify request size limit if its FT is enabeld. - if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_32kb_size_limit')) { - MAX_REQUEST_SIZE = 32000 - } // RTI ids will be included in the bid request if the function getIdentityInfo() is loaded // and if the data for the partner exist if (window.headertag && typeof window.headertag.getIdentityInfo === 'function') { - let identityInfo = window.headertag.getIdentityInfo(); - if (identityInfo && typeof identityInfo === 'object') { - for (const partnerName in identityInfo) { - if (identityInfo.hasOwnProperty(partnerName)) { - let response = identityInfo[partnerName]; - if (!response.responsePending && response.data && typeof response.data === 'object' && - Object.keys(response.data).length && !eidInfo.seenSources[response.data.source]) { - userEids.push(response.data); - } - } - } - } + addRTI(userEids, eidInfo); } // If `roundel` alias bidder, only send requests if liveramp ids exist. @@ -628,8 +622,123 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { return []; } + const requests = []; + let r = createRequest(validBidRequests); + + // getting ixdiags for adunits of the video, outstream & multi format (MF) style + let ixdiag = buildIXDiag(validBidRequests); + for (var key in ixdiag) { + r.ext.ixdiag[key] = ixdiag[key]; + } + + r = enrichRequest(r, bidderRequest, impressions, validBidRequests, userEids); + + r = applyRegulations(r, bidderRequest); + + let payload = {}; + createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE); + + let requestSequenceNumber = 0; + const transactionIds = Object.keys(impressions); + let isFpdAdded = false; + + for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { + // buildRequestV2 does not have request spliting logic. + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { + if (currentRequestSize >= MAX_REQUEST_SIZE) { + break; + } + } + if (requests.length >= MAX_REQUEST_LIMIT) { + break; + } + + r = addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE); + currentRequestSize += currentImpressionSize; + + const fpd = deepAccess(bidderRequest, 'ortb2') || {}; + const site = { ...(fpd.site || fpd.context) }; + const user = { ...fpd.user }; + if (!isEmpty(fpd) && !isFpdAdded) { + r = addFPD(bidderRequest, r, fpd, site, user); + + const clonedRObject = deepClone(r); + + clonedRObject.site = mergeDeep({}, clonedRObject.site, site); + clonedRObject.user = mergeDeep({}, clonedRObject.user, user); + + const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; + + if (requestSize < MAX_REQUEST_SIZE) { + r.site = mergeDeep({}, r.site, site); + r.user = mergeDeep({}, r.user, user); + isFpdAdded = true; + const fpdRequestSize = encodeURIComponent(JSON.stringify({ ...site, ...user })).length; + currentRequestSize += fpdRequestSize; + } else { + logError('IX Bid Adapter: FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.PB_FPD_EXCEEDS_MAX_SIZE }); + } + } + + // add identifiers info to ixDiag + r = addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE); + + const isLastAdUnit = adUnitIndex === transactionIds.length - 1; + + if (wasAdUnitImpressionsTrimmed || isLastAdUnit) { + if (!isLastAdUnit || requestSequenceNumber) { + r.ext.ixdiag.sn = requestSequenceNumber; + } + + requestSequenceNumber++; + + requests.push({ + method: 'POST', + url: baseUrl + '?s=' + siteID, + data: deepClone(r), + option: { + contentType: 'text/plain', + }, + validBidRequests + }); + + currentRequestSize = baseRequestSize; + r.imp = []; + isFpdAdded = false; + } + } + + return requests; +} + +/** + * addRTI adds RTI info of the partner to retrieved user IDs from prebid ID module. + * + * @param {array} userEids userEids info retrieved from prebid + * @param {array} eidInfo eidInfo info from prebid + */ +function addRTI(userEids, eidInfo) { + let identityInfo = window.headertag.getIdentityInfo(); + if (identityInfo && typeof identityInfo === 'object') { + for (const partnerName in identityInfo) { + if (identityInfo.hasOwnProperty(partnerName)) { + let response = identityInfo[partnerName]; + if (!response.responsePending && response.data && typeof response.data === 'object' && + Object.keys(response.data).length && !eidInfo.seenSources[response.data.source]) { + userEids.push(response.data); + } + } + } + } +} + +/** + * createRequest creates the base request object + * @param {array} validBidRequests A list of valid bid request config objects. + * @return {object} Object describing the request to the server. + */ +function createRequest(validBidRequests) { const r = {}; - const tmax = deepAccess(bidderRequest, 'timeout'); // Since bidderRequestId are the same for different bid request, just use the first one. r.id = validBidRequests[0].bidderRequestId.toString(); r.site = {}; @@ -639,13 +748,21 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { r.ext.ixdiag.ls = storage.localStorageIsEnabled(); r.imp = []; r.at = 1; + return r +} - // getting ixdiags for adunits of the video, outstream & multi format (MF) style - let ixdiag = buildIXDiag(validBidRequests); - for (var key in ixdiag) { - r.ext.ixdiag[key] = ixdiag[key]; - } - +/** + * enrichRequest adds userSync configs, source, and referer info to request and ixDiag objects. + * + * @param {object} r Base reuqest object. + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @param {array} impressions A list of impressions to be added to the request. + * @param {array} validBidRequests A list of valid bid request config objects. + * @param {array} userEids User ID info retrieved from Prebid ID module. + * @return {object} Enriched object describing the request to the server. + */ +function enrichRequest(r, bidderRequest, impressions, validBidRequests, userEids) { + const tmax = deepAccess(bidderRequest, 'timeout'); if (tmax) { r.ext.ixdiag.tmax = tmax; } @@ -684,6 +801,17 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { r.site.ref = document.referrer; } + return r +} + +/** + * applyRegulations applies regulation info such as GDPR and GPP to the reqeust obejct. + * + * @param {object} r Base reuqest object. + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @return {object} Object enriched with regulation info describing the request to the server. + */ +function applyRegulations(r, bidderRequest) { // Apply GDPR information to the request if GDPR is enabled. if (bidderRequest) { if (bidderRequest.gdprConsent) { @@ -716,6 +844,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { usPrivacy = bidderRequest.uspConsent; } + const pageUrl = deepAccess(bidderRequest, 'refererInfo.page'); if (pageUrl) { r.site.page = pageUrl; } @@ -730,7 +859,21 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { deepSetValue(r, 'regs.coppa', 1); } - const payload = {}; + return r +} + +/** + * createPayload creates the payload to be sent with the request. + * + * @param {array} validBidRequests A list of valid bid request config objects. + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @param {object} r Reuqest object. + * @param {string} baseUrl Base exchagne URL. + * @param {array} requests List of request obejcts. + * @param {object} payload Request payload object. + * @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1). + */ +function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE) { // Use the siteId in the first bid request as the main siteId. siteID = validBidRequests[0].params.siteId; payload.s = siteID; @@ -738,19 +881,16 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { // Parse additional runtime configs. const bidderCode = (bidderRequest && bidderRequest.bidderCode) || 'ix'; const otherIxConfig = config.getConfig(bidderCode); - const requests = []; - let requestSequenceNumber = 0; - const transactionIds = Object.keys(impressions); - const baseRequestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(r) })}`.length; + + baseRequestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(r) })}`.length; if (baseRequestSize > MAX_REQUEST_SIZE) { logError('IX Bid Adapter: Base request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.EXCEEDS_MAX_SIZE }); return requests; } - let currentRequestSize = baseRequestSize; + currentRequestSize = baseRequestSize; let fpdRequestSize = 0; - let isFpdAdded = false; if (otherIxConfig) { // Append firstPartyData to r.site.page if firstPartyData exists. @@ -766,196 +906,198 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { fpdRequestSize = encodeURIComponent(firstPartyString).length; - if (fpdRequestSize < MAX_REQUEST_SIZE) { + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { + if (fpdRequestSize < MAX_REQUEST_SIZE) { + if ('page' in r.site) { + r.site.page += firstPartyString; + } else { + r.site.page = firstPartyString; + } + currentRequestSize += fpdRequestSize; + } else { + logError('IX Bid Adapter: IX config FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.IX_FPD_EXCEEDS_MAX_SIZE }); + } + } else { if ('page' in r.site) { r.site.page += firstPartyString; } else { r.site.page = firstPartyString; } - currentRequestSize += fpdRequestSize; - } else { - logError('IX Bid Adapter: IX config FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.IX_FPD_EXCEEDS_MAX_SIZE }); } } } +} - for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { - if (currentRequestSize >= MAX_REQUEST_SIZE || requests.length >= MAX_REQUEST_LIMIT) { - break; - } +/** + * addImpressions adds impressions to request object + * + * @param {array} impressions List of impressions to be added to the request. + * @param {array} transactionIds List of transaction Ids. + * @param {object} r Reuqest object. + * @param {int} adUnitIndex Index of the current add unit + * @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1). + * @return {object} Reqyest object with added impressions describing the request to the server. + */ +function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE) { + const adUnitImpressions = impressions[transactionIds[adUnitIndex]]; + const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions; - const adUnitImpressions = impressions[transactionIds[adUnitIndex]]; - const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions; - let wasAdUnitImpressionsTrimmed = false; - let remainingRequestSize = MAX_REQUEST_SIZE - currentRequestSize; - const sourceImpressions = { ixImps, missingBannerImpressions }; - const impressionObjects = Object.keys(sourceImpressions) - .map((key) => sourceImpressions[key]) - .filter(item => Array.isArray(item)) - .reduce((acc, curr) => acc.concat(...curr), []); + let remainingRequestSize = MAX_REQUEST_SIZE - currentRequestSize; + const sourceImpressions = { ixImps, missingBannerImpressions }; + const impressionObjects = Object.keys(sourceImpressions) + .map((key) => sourceImpressions[key]) + .filter(item => Array.isArray(item)) + .reduce((acc, curr) => acc.concat(...curr), []); - let currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; + currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { while (impressionObjects.length && currentImpressionSize > remainingRequestSize) { wasAdUnitImpressionsTrimmed = true; impressionObjects.pop(); currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; } + } - const gpid = impressions[transactionIds[adUnitIndex]].gpid; - const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code; - const tid = impressions[transactionIds[adUnitIndex]].tid; - const sid = impressions[transactionIds[adUnitIndex]].sid - - if (impressionObjects.length && BANNER in impressionObjects[0]) { - const { id, banner: { topframe } } = impressionObjects[0]; - const _bannerImpression = { - id, - banner: { - topframe, - format: impressionObjects.map(({ banner: { w, h }, ext }) => ({ w, h, ext })) - }, - }; - - for (let i = 0; i < _bannerImpression.banner.format.length; i++) { - // We add sid in imp.ext.sid therefore, remove from banner.format[].ext - if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) { - delete _bannerImpression.banner.format[i].ext.sid; - } - - // add floor per size - if ('bidfloor' in impressionObjects[i]) { - _bannerImpression.banner.format[i].ext.bidfloor = impressionObjects[i].bidfloor - } - } - - const position = impressions[transactionIds[adUnitIndex]].pos; - if (isInteger(position)) { - _bannerImpression.banner.pos = position; - } + const gpid = impressions[transactionIds[adUnitIndex]].gpid; + const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code; + const tid = impressions[transactionIds[adUnitIndex]].tid; + const sid = impressions[transactionIds[adUnitIndex]].sid - if (dfpAdUnitCode || gpid || tid || sid) { - _bannerImpression.ext = {}; - _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode; - _bannerImpression.ext.gpid = gpid; - _bannerImpression.ext.tid = tid; - _bannerImpression.ext.sid = sid; - } + if (impressionObjects.length && BANNER in impressionObjects[0]) { + const { id, banner: { topframe } } = impressionObjects[0]; + const _bannerImpression = { + id, + banner: { + topframe, + format: impressionObjects.map(({ banner: { w, h }, ext }) => ({ w, h, ext })) + }, + }; - if ('bidfloor' in impressionObjects[0]) { - _bannerImpression.bidfloor = impressionObjects[0].bidfloor; + for (let i = 0; i < _bannerImpression.banner.format.length; i++) { + // We add sid in imp.ext.sid therefore, remove from banner.format[].ext + if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) { + delete _bannerImpression.banner.format[i].ext.sid; } - if ('bidfloorcur' in impressionObjects[0]) { - _bannerImpression.bidfloorcur = impressionObjects[0].bidfloorcur; + // add floor per size + if ('bidfloor' in impressionObjects[i]) { + _bannerImpression.banner.format[i].ext.bidfloor = impressionObjects[i].bidfloor; } - - r.imp.push(_bannerImpression); - } else { - // set imp.ext.gpid to resolved gpid for each imp - impressionObjects.forEach(imp => deepSetValue(imp, 'ext.gpid', gpid)); - r.imp.push(...impressionObjects); } - currentRequestSize += currentImpressionSize; - - const fpd = deepAccess(bidderRequest, 'ortb2') || {}; - if (!isEmpty(fpd) && !isFpdAdded) { - r.ext.ixdiag.fpd = true; + const position = impressions[transactionIds[adUnitIndex]].pos; + if (isInteger(position)) { + _bannerImpression.banner.pos = position; + } - const site = { ...(fpd.site || fpd.context) }; + if (dfpAdUnitCode || gpid || tid || sid) { + _bannerImpression.ext = {}; + _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode; + _bannerImpression.ext.gpid = gpid; + _bannerImpression.ext.tid = tid; + _bannerImpression.ext.sid = sid; + } - Object.keys(site).forEach(key => { - if (FIRST_PARTY_DATA.SITE.indexOf(key) === -1) { - delete site[key]; - } - }); + if ('bidfloor' in impressionObjects[0]) { + _bannerImpression.bidfloor = impressionObjects[0].bidfloor; + } - const user = { ...fpd.user }; + if ('bidfloorcur' in impressionObjects[0]) { + _bannerImpression.bidfloorcur = impressionObjects[0].bidfloorcur; + } - Object.keys(user).forEach(key => { - if (FIRST_PARTY_DATA.USER.indexOf(key) === -1) { - delete user[key]; - } - }); + r.imp.push(_bannerImpression); + } else { + // set imp.ext.gpid to resolved gpid for each imp + impressionObjects.forEach(imp => deepSetValue(imp, 'ext.gpid', gpid)); + r.imp.push(...impressionObjects); + } - if (fpd.device) { - const sua = {...fpd.device.sua}; - if (!isEmpty(sua)) { - deepSetValue(r, 'device.sua', sua); - } - } + return r; +} - if (fpd.hasOwnProperty('regs') && !bidderRequest.gppConsent) { - if (fpd.regs.hasOwnProperty('gpp') && typeof fpd.regs.gpp == 'string') { - deepSetValue(r, 'regs.gpp', fpd.regs.gpp) - } +/** + * addFPD adds ortb2 first party data to request object. + * + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @param {object} r Reuqest object. + * @param {object} fpd ortb2 first party data. + * @param {object} site First party site data. + * @param {object} user First party user data. + * @return {object} Reqyest object with added FPD describing the request to the server. + */ +function addFPD(bidderRequest, r, fpd, site, user) { + r.ext.ixdiag.fpd = true; - if (fpd.regs.hasOwnProperty('gpp_sid') && Array.isArray(fpd.regs.gpp_sid)) { - deepSetValue(r, 'regs.gpp_sid', fpd.regs.gpp_sid) - } - } + Object.keys(site).forEach(key => { + if (FIRST_PARTY_DATA.SITE.indexOf(key) === -1) { + delete site[key]; + } + }); - const clonedRObject = deepClone(r); + Object.keys(user).forEach(key => { + if (FIRST_PARTY_DATA.USER.indexOf(key) === -1) { + delete user[key]; + } + }); - clonedRObject.site = mergeDeep({}, clonedRObject.site, site); - clonedRObject.user = mergeDeep({}, clonedRObject.user, user); + if (fpd.device) { + const sua = {...fpd.device.sua}; + if (!isEmpty(sua)) { + deepSetValue(r, 'device.sua', sua); + } + } - const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; + if (fpd.hasOwnProperty('regs') && !bidderRequest.gppConsent) { + if (fpd.regs.hasOwnProperty('gpp') && typeof fpd.regs.gpp == 'string') { + deepSetValue(r, 'regs.gpp', fpd.regs.gpp) + } - if (requestSize < MAX_REQUEST_SIZE) { - r.site = mergeDeep({}, r.site, site); - r.user = mergeDeep({}, r.user, user); - isFpdAdded = true; - const fpdRequestSize = encodeURIComponent(JSON.stringify({ ...site, ...user })).length; - currentRequestSize += fpdRequestSize; - } else { - logError('IX Bid Adapter: FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.PB_FPD_EXCEEDS_MAX_SIZE }); - } + if (fpd.regs.hasOwnProperty('gpp_sid') && Array.isArray(fpd.regs.gpp_sid)) { + deepSetValue(r, 'regs.gpp_sid', fpd.regs.gpp_sid) } + } - // add identifiers info to ixDiag - const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot; - const tagId = impressions[transactionIds[adUnitIndex]].tagId; - const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode; - const divId = impressions[transactionIds[adUnitIndex]].divId; - if (pbaAdSlot || tagId || adUnitCode || divId) { - const clonedRObject = deepClone(r); - const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; + return r; +} + +/** + * addIdentifiersInfo adds indentifier info to ixDaig. + * + * @param {array} impressions List of impressions to be added to the request. + * @param {object} r Reuqest object. + * @param {array} transactionIds List of transaction Ids. + * @param {int} adUnitIndex Index of the current add unit + * @param {object} payload Request payload object. + * @param {string} baseUrl Base exchagne URL. + * @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1). + * @return {object} Reqyest object with added indentigfier info to ixDiag. + */ +function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE) { + const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot; + const tagId = impressions[transactionIds[adUnitIndex]].tagId; + const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode; + const divId = impressions[transactionIds[adUnitIndex]].divId; + if (pbaAdSlot || tagId || adUnitCode || divId) { + const clonedRObject = deepClone(r); + const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { if (requestSize < MAX_REQUEST_SIZE) { r.ext.ixdiag.pbadslot = pbaAdSlot; r.ext.ixdiag.tagid = tagId; r.ext.ixdiag.adunitcode = adUnitCode; r.ext.ixdiag.divId = divId; } - } - - const isLastAdUnit = adUnitIndex === transactionIds.length - 1; - - if (wasAdUnitImpressionsTrimmed || isLastAdUnit) { - if (!isLastAdUnit || requestSequenceNumber) { - r.ext.ixdiag.sn = requestSequenceNumber; - } - - requestSequenceNumber++; - - requests.push({ - method: 'POST', - url: baseUrl + '?s=' + siteID, - data: deepClone(r), - option: { - contentType: 'text/plain', - }, - validBidRequests - }); - - currentRequestSize = baseRequestSize; - r.imp = []; - isFpdAdded = false; + } else { + r.ext.ixdiag.pbadslot = pbaAdSlot; + r.ext.ixdiag.tagid = tagId; + r.ext.ixdiag.adunitcode = adUnitCode; + r.ext.ixdiag.divId = divId; } } - return requests; + return r; } /** diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index f681e7786ae..5f104dce13f 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -3615,27 +3615,9 @@ describe('IndexexchangeAdapter', function () { expect(FEATURE_TOGGLES.featureToggles).to.deep.equal({}); }); - it('should set request size limit to 32KB when its feature enabled', () => { + it('6 ad units should generate only 1 request if buildRequestV2 FT is enabled', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { - activated: true - }; - FEATURE_TOGGLES.setFeatureToggles(serverResponse); - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.bidderRequestId = Array(10000).join('#'); - - expect(spec.isBidRequestValid(bid)).to.be.true; - spec.buildRequests([bid], {}); - const lsData = JSON.parse(storage.getDataFromLocalStorage(LOCAL_STORAGE_FEATURE_TOGGLES_KEY)); - expect(lsData.features.pbjs_use_32kb_size_limit.activated).to.be.true; - }); - - it('6 ad units should generate only 2 requests if 32kb size limit FT is enabled', function () { - sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { - activated: true - }; - serverResponse.body.ext.features.pbjs_enable_post = { + serverResponse.body.ext.features.pbjs_use_buildRequestV2 = { activated: true }; FEATURE_TOGGLES.setFeatureToggles(serverResponse); @@ -3665,47 +3647,30 @@ describe('IndexexchangeAdapter', function () { const requests = spec.buildRequests([bid1, bid2, bid3, bid4, bid5, bid6], DEFAULT_OPTION); expect(requests).to.be.an('array'); - // 32KB size limit causes only 2 requests to get generated. - expect(requests).to.have.lengthOf(2); + // buildRequestv2 enabled causes only 1 requests to get generated. + expect(requests).to.have.lengthOf(1); for (let request of requests) { expect(request.method).to.equal('POST'); } }); - it('4 ad units should generate only 1 requests if 32kb size limit FT is enabled', function () { + it('1 request with 2 ad units, buildRequestV2 enabled', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { - activated: true - }; - serverResponse.body.ext.features.pbjs_enable_post = { + serverResponse.body.ext.features.pbjs_use_buildRequestV2 = { activated: true }; FEATURE_TOGGLES.setFeatureToggles(serverResponse); - const bid1 = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); - bid1.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; - bid1.params.siteId = '121'; - bid1.adUnitCode = 'div-gpt-1' - bid1.transactionId = 'tr1'; - bid1.bidId = '2f6g5s5e'; - - const bid2 = utils.deepClone(bid1); - bid2.transactionId = 'tr2'; - - const bid3 = utils.deepClone(bid1); - bid3.transactionId = 'tr3'; - - const bid4 = utils.deepClone(bid1); - bid4.transactionId = 'tr4'; - - const requests = spec.buildRequests([bid1, bid2, bid3, bid4], DEFAULT_OPTION); + const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); + bid.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; + bid.params.siteId = '124'; + bid.adUnitCode = 'div-gpt-1' + bid.transactionId = '152e36d1-1241-4242-t35e-y1dv34d12315'; + bid.bidId = '2f6g5s5e'; + const requests = spec.buildRequests([bid, DEFAULT_BANNER_VALID_BID[0]], DEFAULT_OPTION); expect(requests).to.be.an('array'); - // 32KB size limit causes only 1 requests to get generated. expect(requests).to.have.lengthOf(1); - for (let request of requests) { - expect(request.method).to.equal('POST'); - } }); }); From 4689d3b34e074b17129700d316161bd59808410f Mon Sep 17 00:00:00 2001 From: mmoschovas <63253416+mmoschovas@users.noreply.github.com> Date: Thu, 9 Feb 2023 04:36:54 -0500 Subject: [PATCH 344/367] bug fix for grid adapter not applying jw segment data when bidderRequest ortb2.user data doe not exist (#9521) --- modules/gridBidAdapter.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index aa6c0ab668f..ce7fcc680dd 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -288,9 +288,11 @@ export const spec = { return; } + if (request.user) user = request.user; + const ortb2UserData = deepAccess(bidderRequest, 'ortb2.user.data'); if (ortb2UserData && ortb2UserData.length) { - user = request.user || { data: [] }; + if (!user) user = { data: [] }; user = mergeDeep(user, { data: [...ortb2UserData] }); From b56e2ff8bbd3398625e8e207ff58baa359ef2696 Mon Sep 17 00:00:00 2001 From: Taro FURUKAWA <6879289+0tarof@users.noreply.github.com> Date: Thu, 9 Feb 2023 20:20:54 +0900 Subject: [PATCH 345/367] add sua support (#9523) --- modules/ajaBidAdapter.js | 7 ++++++- test/spec/modules/ajaBidAdapter_spec.js | 22 +++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/modules/ajaBidAdapter.js b/modules/ajaBidAdapter.js index 121dc2ef96f..67b448eb484 100644 --- a/modules/ajaBidAdapter.js +++ b/modules/ajaBidAdapter.js @@ -1,4 +1,4 @@ -import { getBidIdParameter, tryAppendQueryString, createTrackPixelHtml, logError, logWarn } from '../src/utils.js'; +import { getBidIdParameter, tryAppendQueryString, createTrackPixelHtml, logError, logWarn, deepAccess } from '../src/utils.js'; import { Renderer } from '../src/Renderer.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { VIDEO, BANNER, NATIVE } from '../src/mediaTypes.js'; @@ -64,6 +64,11 @@ export const spec = { })) } + const sua = deepAccess(bidRequest, 'ortb2.device.sua'); + if (sua) { + queryString = tryAppendQueryString(queryString, 'sua', JSON.stringify(sua)); + } + bidRequests.push({ method: 'GET', url: URL, diff --git a/test/spec/modules/ajaBidAdapter_spec.js b/test/spec/modules/ajaBidAdapter_spec.js index a2095d52857..7cf5698f7d4 100644 --- a/test/spec/modules/ajaBidAdapter_spec.js +++ b/test/spec/modules/ajaBidAdapter_spec.js @@ -45,6 +45,26 @@ describe('AjaAdapter', function () { bidId: '30b31c1838de1e', bidderRequestId: '22edbae2733bf6', auctionId: '1d1a030790a475', + ortb2: { + device: { + sua: { + source: 2, + platform: { + brand: 'Android', + version: ['8', '0', '0'] + }, + browsers: [ + {brand: 'Not_A Brand', version: ['99', '0', '0', '0']}, + {brand: 'Google Chrome', version: ['109', '0', '5414', '119']}, + {brand: 'Chromium', version: ['109', '0', '5414', '119']} + ], + mobile: 1, + model: 'SM-G955U', + bitness: '64', + architecture: '' + } + } + } } ]; @@ -58,7 +78,7 @@ describe('AjaAdapter', 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('asi=123456&skt=5&prebid_id=30b31c1838de1e&prebid_ver=$prebid.version$&page_url=https%3A%2F%2Fhoge.com&'); + expect(requests[0].data).to.equal('asi=123456&skt=5&prebid_id=30b31c1838de1e&prebid_ver=$prebid.version$&page_url=https%3A%2F%2Fhoge.com&sua=%7B%22source%22%3A2%2C%22platform%22%3A%7B%22brand%22%3A%22Android%22%2C%22version%22%3A%5B%228%22%2C%220%22%2C%220%22%5D%7D%2C%22browsers%22%3A%5B%7B%22brand%22%3A%22Not_A%20Brand%22%2C%22version%22%3A%5B%2299%22%2C%220%22%2C%220%22%2C%220%22%5D%7D%2C%7B%22brand%22%3A%22Google%20Chrome%22%2C%22version%22%3A%5B%22109%22%2C%220%22%2C%225414%22%2C%22119%22%5D%7D%2C%7B%22brand%22%3A%22Chromium%22%2C%22version%22%3A%5B%22109%22%2C%220%22%2C%225414%22%2C%22119%22%5D%7D%5D%2C%22mobile%22%3A1%2C%22model%22%3A%22SM-G955U%22%2C%22bitness%22%3A%2264%22%2C%22architecture%22%3A%22%22%7D&'); }); }); From 0880777873248c5358507a118f9c97d84147630b Mon Sep 17 00:00:00 2001 From: kapil-tuptewar <91458408+kapil-tuptewar@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:55:52 +0530 Subject: [PATCH 346/367] Read and pass device.sua object to translator payload (#9526) Co-authored-by: Kapil Tuptewar --- modules/pubmaticBidAdapter.js | 4 ++++ test/spec/modules/pubmaticBidAdapter_spec.js | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 296a4314ac8..d8f5002ebd7 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -1189,6 +1189,10 @@ export const spec = { if (commonFpd.bcat) { blockedIabCategories = blockedIabCategories.concat(commonFpd.bcat); } + // check if fpd ortb2 contains device property with sua object + if (commonFpd.device?.sua) { + payload.device.sua = commonFpd.device?.sua; + } if (commonFpd.ext?.prebid?.bidderparams?.[bidderRequest.bidderCode]?.acat) { const acatParams = commonFpd.ext.prebid.bidderparams[bidderRequest.bidderCode].acat; diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index 6b240cb2d06..fa8f809e8a2 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -2607,6 +2607,21 @@ describe('PubMatic adapter', function () { expect(data.imp[1]['video']['h']).to.equal(multipleMediaRequests[1].mediaTypes.video.playerSize[1]); }); + it('should pass device.sua if present in bidderRequest fpd ortb2 object', function () { + const suaObject = {'source': 2, 'platform': {'brand': 'macOS', 'version': ['12', '4', '0']}, 'browsers': [{'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']}, {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']}, {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}], 'mobile': 0, 'model': '', 'bitness': '64', 'architecture': 'x86'}; + let request = spec.buildRequests(multipleMediaRequests, { + auctionId: 'new-auction-id', + ortb2: { + device: { + sua: suaObject + } + } + }); + let data = JSON.parse(request.data); + expect(data.device.sua).to.exist.and.to.be.an('object'); + expect(data.device.sua).to.deep.equal(suaObject); + }); + it('Request params should have valid native bid request for all valid params', function () { let request = spec.buildRequests(nativeBidRequests, { auctionId: 'new-auction-id' From 53acdd7eaad78516be0e133869ba487eb3cc9e4d Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 9 Feb 2023 13:54:16 +0000 Subject: [PATCH 347/367] Prebid 7.36.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index dca60dbf37e..1e76c5b38a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.36.0-pre", + "version": "7.36.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 7163c732634..bfd92f7cfff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.36.0-pre", + "version": "7.36.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 7fd7b3016bf0bab1dacf59bd305e51dc805dc45a Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 9 Feb 2023 13:54:16 +0000 Subject: [PATCH 348/367] Increment version to 7.37.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1e76c5b38a7..1c6a10e6ac6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.36.0", + "version": "7.37.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index bfd92f7cfff..95ba8e522d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.36.0", + "version": "7.37.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 90b3b400cf0125694de3f3634f109c2254e2d1b7 Mon Sep 17 00:00:00 2001 From: JonGoSonobi Date: Thu, 9 Feb 2023 09:41:08 -0500 Subject: [PATCH 349/367] Sonobi Bid Adapter: remove userid query param (#9496) * Removed the userid param This was causing a 414 error when userid and eids was duplicated * Update Sonobi Unit test for userid param * Remove deepClone import * Restored a userid unit test to ensure that the buildRequests function still works even if the publisher specifies a userid * Reworded the userid unit test and asserted that userid is not being set * Fixed undefined check in unit test --- modules/sonobiBidAdapter.js | 11 +-------- test/spec/modules/sonobiBidAdapter_spec.js | 28 +++------------------- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index f9cc1f3b353..87358705cb5 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -1,5 +1,5 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { parseSizesInput, logError, generateUUID, isEmpty, deepAccess, logWarn, logMessage, deepClone, getGptSlotInfoForAdUnitCode, isFn, isPlainObject } from '../src/utils.js'; +import { parseSizesInput, logError, generateUUID, isEmpty, deepAccess, logWarn, logMessage, getGptSlotInfoForAdUnitCode, isFn, isPlainObject } from '../src/utils.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; @@ -132,15 +132,6 @@ export const spec = { if (validBidRequests[0].schain) { payload.schain = JSON.stringify(validBidRequests[0].schain); } - if (deepAccess(validBidRequests[0], 'userId') && Object.keys(validBidRequests[0].userId).length > 0) { - const userIds = deepClone(validBidRequests[0].userId); - - if (userIds.id5id) { - userIds.id5id = deepAccess(userIds, 'id5id.uid'); - } - - payload.userid = JSON.stringify(userIds); - } const eids = deepAccess(validBidRequests[0], 'userIdAsEids'); if (Array.isArray(eids) && eids.length > 0) { diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js index a9382f092e2..56ed4d5196e 100644 --- a/test/spec/modules/sonobiBidAdapter_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -371,7 +371,7 @@ describe('SonobiBidAdapter', function () { } } }; - const bidRequests = spec.buildRequests(bidRequest, {...bidderRequests, ortb2}); + const bidRequests = spec.buildRequests(bidRequest, { ...bidderRequests, ortb2 }); expect(bidRequests.data.fpd).to.equal(JSON.stringify(ortb2)); }); @@ -540,7 +540,7 @@ describe('SonobiBidAdapter', function () { ]); }); - it('should return a properly formatted request with userid as a JSON-encoded set of User ID results', function () { + it('should return a properly formatted request with the userid value omitted when the userId object is present on the bidRequest. ', function () { bidRequest[0].userId = { 'pubcid': 'abcd-efg-0101', 'tdid': 'td-abcd-efg-0101', 'id5id': { 'uid': 'ID5-ZHMOrVeUVTUKgrZ-a2YGxeh5eS_pLzHCQGYOEAiTBQ', 'ext': { 'linkType': 2 } } }; bidRequest[1].userId = { 'pubcid': 'abcd-efg-0101', 'tdid': 'td-abcd-efg-0101', 'id5id': { 'uid': 'ID5-ZHMOrVeUVTUKgrZ-a2YGxeh5eS_pLzHCQGYOEAiTBQ', 'ext': { 'linkType': 2 } } }; const bidRequests = spec.buildRequests(bidRequest, bidderRequests); @@ -548,29 +548,7 @@ describe('SonobiBidAdapter', function () { expect(bidRequests.method).to.equal('GET'); expect(bidRequests.data.ref).not.to.be.empty; expect(bidRequests.data.s).not.to.be.empty; - expect(JSON.parse(bidRequests.data.userid)).to.eql({ 'pubcid': 'abcd-efg-0101', 'tdid': 'td-abcd-efg-0101', 'id5id': 'ID5-ZHMOrVeUVTUKgrZ-a2YGxeh5eS_pLzHCQGYOEAiTBQ' }); - }); - - it('should return a properly formatted request with userid omitted if there are no userIds', function () { - bidRequest[0].userId = {}; - bidRequest[1].userId = {}; - const bidRequests = spec.buildRequests(bidRequest, bidderRequests); - expect(bidRequests.url).to.equal('https://apex.go.sonobi.com/trinity.json'); - expect(bidRequests.method).to.equal('GET'); - expect(bidRequests.data.ref).not.to.be.empty; - expect(bidRequests.data.s).not.to.be.empty; - expect(bidRequests.data.userid).to.equal(undefined); - }); - - it('should return a properly formatted request with userid omitted', function () { - bidRequest[0].userId = undefined; - bidRequest[1].userId = undefined; - const bidRequests = spec.buildRequests(bidRequest, bidderRequests); - expect(bidRequests.url).to.equal('https://apex.go.sonobi.com/trinity.json'); - expect(bidRequests.method).to.equal('GET'); - expect(bidRequests.data.ref).not.to.be.empty; - expect(bidRequests.data.s).not.to.be.empty; - expect(bidRequests.data.userid).to.equal(undefined); + expect(bidRequests.data.userid).to.be.undefined; }); it('should return a properly formatted request with keywrods included as a csv of strings', function () { From 732b7dcadff3c0a19b6d020413687ff318829200 Mon Sep 17 00:00:00 2001 From: Espen <2290914+espen-j@users.noreply.github.com> Date: Thu, 9 Feb 2023 19:32:26 +0100 Subject: [PATCH 350/367] Update adapter docs (c-wire/prebid#3) (#9528) --- modules/cwireBidAdapter.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/cwireBidAdapter.md b/modules/cwireBidAdapter.md index 026c2943c6b..9804250b906 100644 --- a/modules/cwireBidAdapter.md +++ b/modules/cwireBidAdapter.md @@ -3,7 +3,7 @@ ``` Module Name: C-WIRE Bid Adapter Module Type: Bidder Adapter -Maintainer: devs@cwire.ch +Maintainer: devs@cwire.com ``` ## Description @@ -40,10 +40,16 @@ var adUnits = [ params: { pageId: 1422, // required - number placementId: 2211521, // required - number - cwcreative: '42', // optional - id of creative to force - refgroups: 'test-user', // optional - name of group or coma separated list of groups to force } }] } ]; ``` + +### URL parameters + +For debugging and testing purposes url parameters can be set. + +**Example:** + +`https://www.some-site.com/article.html?cwdebug=true&cwfeatures=feature1,feature2&cwcreative=1234` From 2e8d15978fb40e686dcbabe13694778defe0b8b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udi=20Talias=20=E2=9A=9B=EF=B8=8F?= Date: Fri, 10 Feb 2023 04:57:15 +0200 Subject: [PATCH 351/367] MinuteMediaPlus Bid Adapter: New Bid Adapter (#9430) * MinuteMediaPlus bid adapter * bidder code changed to --- modules/minutemediaplusBidAdapter.js | 291 ++++++++++ modules/minutemediaplusBidAdapter.md | 35 ++ .../modules/minutemediaplusBidAdapter_spec.js | 519 ++++++++++++++++++ 3 files changed, 845 insertions(+) create mode 100644 modules/minutemediaplusBidAdapter.js create mode 100644 modules/minutemediaplusBidAdapter.md create mode 100644 test/spec/modules/minutemediaplusBidAdapter_spec.js diff --git a/modules/minutemediaplusBidAdapter.js b/modules/minutemediaplusBidAdapter.js new file mode 100644 index 00000000000..578db846289 --- /dev/null +++ b/modules/minutemediaplusBidAdapter.js @@ -0,0 +1,291 @@ +import { _each, deepAccess, parseSizesInput, parseUrl, uniques, isFn } 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 = 918; +const DEFAULT_SUB_DOMAIN = 'exchange'; +const BIDDER_CODE = 'mmplus'; +const BIDDER_VERSION = '1.0.0'; +const CURRENCY = 'USD'; +const TTL_SECONDS = 60 * 5; +const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 15; +export const SUPPORTED_ID_SYSTEMS = { + 'britepoolid': 1, + 'criteoId': 1, + 'id5id': 1, + 'idl_env': 1, + 'lipb': 1, + 'netId': 1, + 'parrableId': 1, + 'pubcid': 1, + 'tdid': 1, + 'pubProvidedId': 1 +}; +const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }); + +function getTopWindowQueryParams() { + try { + const parsedUrl = parseUrl(window.top.document.URL, { decodeSearchAsString: true }); + return parsedUrl.search; + } catch (e) { + return ''; + } +} + +export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { + return `https://${subDomain}.minutemedia-prebid.com`; +} + +export function extractCID(params) { + return params.cId || params.CID || params.cID || params.CId || params.cid || params.ciD || params.Cid || params.CiD; +} + +export function extractPID(params) { + return params.pId || params.PID || params.pID || params.PId || params.pid || params.piD || params.Pid || params.PiD; +} + +export function extractSubDomain(params) { + return params.subDomain || params.SubDomain || params.Subdomain || params.subdomain || params.SUBDOMAIN || params.subDOMAIN; +} + +function isBidRequestValid(bid) { + const params = bid.params || {}; + return !!(extractCID(params) && extractPID(params)); +} + +function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { + const { params, bidId, userId, adUnitCode, schain, mediaTypes } = bid; + let { bidFloor, ext } = params; + const hashUrl = hashCode(topWindowUrl); + const uniqueDealId = getUniqueDealId(hashUrl); + const cId = extractCID(params); + const pId = extractPID(params); + const subDomain = extractSubDomain(params); + + if (isFn(bid.getFloor)) { + const floorInfo = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*' + }); + + if (floorInfo.currency === 'USD') { + bidFloor = floorInfo.floor; + } + } + + let data = { + url: encodeURIComponent(topWindowUrl), + uqs: getTopWindowQueryParams(), + cb: Date.now(), + bidFloor: bidFloor, + bidId: bidId, + referrer: bidderRequest.refererInfo.ref, + adUnitCode: adUnitCode, + publisherId: pId, + sizes: sizes, + uniqueDealId: uniqueDealId, + bidderVersion: BIDDER_VERSION, + prebidVersion: '$prebid.version$', + res: `${screen.width}x${screen.height}`, + schain: schain, + mediaTypes: mediaTypes + }; + + 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 + }; + + _each(ext, (value, key) => { + dto.data['ext.' + key] = value; + }); + + return dto; +} + +function appendUserIdsToRequestPayload(payloadRef, userIds) { + let key; + _each(userIds, (userId, idSystemProviderName) => { + if (SUPPORTED_ID_SYSTEMS[idSystemProviderName]) { + key = `uid.${idSystemProviderName}`; + + switch (idSystemProviderName) { + case 'digitrustid': + payloadRef[key] = deepAccess(userId, 'data.id'); + break; + case 'lipb': + payloadRef[key] = userId.lipbid; + break; + case 'parrableId': + payloadRef[key] = userId.eid; + break; + case 'id5id': + payloadRef[key] = userId.uid; + break; + default: + payloadRef[key] = userId; + } + } + }); +} + +function buildRequests(validBidRequests, bidderRequest) { + const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; + const requests = []; + validBidRequests.forEach(validBidRequest => { + const sizes = parseSizesInput(validBidRequest.sizes); + const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest); + requests.push(request); + }); + return requests; +} + +function interpretResponse(serverResponse, request) { + if (!serverResponse || !serverResponse.body) { + return []; + } + const { bidId } = request.data; + const { results } = serverResponse.body; + + let output = []; + + try { + results.forEach(result => { + const { creativeId, ad, price, exp, width, height, currency, advertiserDomains, mediaType = BANNER } = result; + if (!ad || !price) { + return; + } + + const response = { + requestId: bidId, + cpm: price, + width: width, + height: height, + creativeId: creativeId, + currency: currency || CURRENCY, + netRevenue: true, + ttl: exp || TTL_SECONDS, + meta: { + advertiserDomains: advertiserDomains || [] + } + }; + + if (mediaType === BANNER) { + Object.assign(response, { + ad: ad, + }); + } else { + Object.assign(response, { + vastXml: ad, + mediaType: VIDEO + }); + } + output.push(response); + }); + return output; + } catch (e) { + return []; + } +} + +function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '') { + let syncs = []; + const { iframeEnabled, pixelEnabled } = syncOptions; + const { gdprApplies, consentString = '' } = gdprConsent; + + const cidArr = responses.filter(resp => deepAccess(resp, 'body.cid')).map(resp => resp.body.cid).filter(uniques); + const params = `?cid=${encodeURIComponent(cidArr.join(','))}&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}` + if (iframeEnabled) { + syncs.push({ + type: 'iframe', + url: `https://sync.minutemedia-prebid.com/api/sync/iframe/${params}` + }); + } + if (pixelEnabled) { + syncs.push({ + type: 'image', + url: `https://sync.minutemedia-prebid.com/api/sync/image/${params}` + }); + } + return syncs; +} + +export function hashCode(s, prefix = '_') { + const l = s.length; + let h = 0 + let i = 0; + if (l > 0) { + while (i < l) { h = (h << 5) - h + s.charCodeAt(i++) | 0; } + } + return prefix + h; +} + +export function getUniqueDealId(key, expiry = UNIQUE_DEAL_ID_EXPIRY) { + const storageKey = `u_${key}`; + const now = Date.now(); + const data = getStorageItem(storageKey); + let uniqueId; + + if (!data || !data.value || now - data.created > expiry) { + uniqueId = `${key}_${now.toString()}`; + setStorageItem(storageKey, uniqueId); + } else { + uniqueId = data.value; + } + + return uniqueId; +} + +export function getStorageItem(key) { + try { + return tryParseJSON(storage.getDataFromLocalStorage(key)); + } catch (e) { } + + return null; +} + +export function setStorageItem(key, value, timestamp) { + try { + const created = timestamp || Date.now(); + const data = JSON.stringify({ value, created }); + storage.setDataInLocalStorage(key, data); + } catch (e) { } +} + +export function tryParseJSON(value) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } +} + +export const spec = { + code: BIDDER_CODE, + version: BIDDER_VERSION, + gvlid: GVLID, + supportedMediaTypes: [BANNER, VIDEO], + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs +}; + +registerBidder(spec); diff --git a/modules/minutemediaplusBidAdapter.md b/modules/minutemediaplusBidAdapter.md new file mode 100644 index 00000000000..410c00e7017 --- /dev/null +++ b/modules/minutemediaplusBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +**Module Name:** MinuteMediaPlus Bidder Adapter + +**Module Type:** Bidder Adapter + +**Maintainer:** hb@minutemedia.com + +# Description + +Module that connects to MinuteMediaPlus's demand sources. + +# Test Parameters +```js +var adUnits = [ + { + code: 'test-ad', + sizes: [[300, 250]], + bids: [ + { + bidder: 'mmplus', + params: { + cId: '562524b21b1c1f08117fc7f9', + pId: '59ac17c192832d0011283fe3', + bidFloor: 0.0001, + ext: { + param1: 'loremipsum', + param2: 'dolorsitamet' + } + } + } + ] + } +]; +``` diff --git a/test/spec/modules/minutemediaplusBidAdapter_spec.js b/test/spec/modules/minutemediaplusBidAdapter_spec.js new file mode 100644 index 00000000000..de38554f010 --- /dev/null +++ b/test/spec/modules/minutemediaplusBidAdapter_spec.js @@ -0,0 +1,519 @@ +import { expect } from 'chai'; +import { + spec as adapter, + SUPPORTED_ID_SYSTEMS, + createDomain, + hashCode, + extractPID, + extractCID, + extractSubDomain, + getStorageItem, + setStorageItem, + tryParseJSON, + getUniqueDealId, +} from 'modules/minutemediaplusBidAdapter.js'; +import * as utils from 'src/utils.js'; +import { version } from 'package.json'; +import { useFakeTimers } from 'sinon'; +import { BANNER, VIDEO } from '../../../src/mediaTypes'; + +const SUB_DOMAIN = 'exchange'; + +const BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': 'div-gpt-ad-12345-0', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '59db6b3b4ffaa70004f45cdc', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1, + 'ext': { + 'param1': 'loremipsum', + 'param2': 'dolorsitamet' + } + }, + 'placementCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + 'sizes': [[300, 250], [300, 600]], + 'bidderRequestId': '1fdb5ff1b6eaa7', + 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'mediaTypes': [BANNER] +}; + +const VIDEO_BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560', + 'bidderRequestId': '12a8ae9ada9c13', + 'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee', + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '635509f7ff6642d368cb9837', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1 + }, + 'sizes': [[545, 307]], + 'mediaTypes': { + 'video': { + 'playerSize': [[545, 307]], + 'context': 'instream', + 'mimes': [ + 'video/mp4', + 'application/javascript' + ], + 'protocols': [2, 3, 5, 6], + 'maxduration': 60, + 'minduration': 0, + 'startdelay': 0, + 'linearity': 1, + 'api': [2], + 'placement': 1 + } + } +} + +const BIDDER_REQUEST = { + 'gdprConsent': { + 'consentString': 'consent_string', + 'gdprApplies': true + }, + 'uspConsent': 'consent_string', + 'refererInfo': { + 'page': 'https://www.greatsite.com', + 'ref': 'https://www.somereferrer.com' + } +}; + +const SERVER_RESPONSE = { + body: { + cid: 'testcid123', + results: [{ + 'ad': '', + 'price': 0.8, + 'creativeId': '12610997325162499419', + 'exp': 30, + 'width': 300, + 'height': 250, + 'advertiserDomains': ['securepubads.g.doubleclick.net'], + 'cookies': [{ + 'src': 'https://sync.com', + 'type': 'iframe' + }, { + 'src': 'https://sync.com', + 'type': 'img' + }] + }] + } +}; + +const VIDEO_SERVER_RESPONSE = { + body: { + 'cid': '635509f7ff6642d368cb9837', + 'results': [{ + 'ad': '', + 'advertiserDomains': ['minutemedia-prebid.com'], + 'exp': 60, + 'width': 545, + 'height': 307, + 'mediaType': 'video', + 'creativeId': '12610997325162499419', + 'price': 2, + 'cookies': [] + }] + } +}; + +const REQUEST = { + data: { + width: 300, + height: 250, + bidId: '2d52001cabd527' + } +}; + +function getTopWindowQueryParams() { + try { + const parsedUrl = utils.parseUrl(window.top.document.URL, { decodeSearchAsString: true }); + return parsedUrl.search; + } catch (e) { + return ''; + } +} + +describe('MinuteMediaPlus Bid Adapter', function () { + describe('validtae spec', function () { + it('exists and is a function', function () { + expect(adapter.isBidRequestValid).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.buildRequests).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.interpretResponse).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.getUserSyncs).to.exist.and.to.be.a('function'); + }); + + it('exists and is a string', function () { + expect(adapter.code).to.exist.and.to.be.a('string'); + }); + + it('exists and contains media types', function () { + expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2); + expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]); + }); + }); + + describe('validate bid requests', function () { + it('should require cId', function () { + const isValid = adapter.isBidRequestValid({ + params: { + pId: 'pid' + } + }); + expect(isValid).to.be.false; + }); + + it('should require pId', function () { + const isValid = adapter.isBidRequestValid({ + params: { + cId: 'cid' + } + }); + expect(isValid).to.be.false; + }); + + it('should validate correctly', function () { + const isValid = adapter.isBidRequestValid({ + params: { + cId: 'cid', + pId: 'pid' + } + }); + expect(isValid).to.be.true; + }); + }); + + describe('build requests', function () { + let sandbox; + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + mmplus: { + storageAllowed: true + } + }; + sandbox = sinon.sandbox.create(); + sandbox.stub(Date, 'now').returns(1000); + }); + + it('should build video request', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`, + data: { + adUnitCode: '63550ad1ff6642d368cba59dh5884270560', + bidFloor: 0.1, + bidId: '2d52001cabd527', + bidderVersion: adapter.version, + cb: 1000, + gdpr: 1, + gdprConsent: 'consent_string', + usPrivacy: 'consent_string', + prebidVersion: version, + publisherId: '59ac17c192832d0011283fe3', + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + res: `${window.top.screen.width}x${window.top.screen.height}`, + schain: VIDEO_BID.schain, + sizes: ['545x307'], + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + uqs: getTopWindowQueryParams(), + mediaTypes: { + video: { + api: [2], + context: 'instream', + linearity: 1, + maxduration: 60, + mimes: [ + 'video/mp4', + 'application/javascript' + ], + minduration: 0, + placement: 1, + playerSize: [[545, 307]], + protocols: [2, 3, 5, 6], + startdelay: 0 + } + } + } + }); + }); + + it('should build banner request for each size', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + const requests = adapter.buildRequests([BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/59db6b3b4ffaa70004f45cdc`, + data: { + gdprConsent: 'consent_string', + gdpr: 1, + usPrivacy: 'consent_string', + sizes: ['300x250', '300x600'], + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + cb: 1000, + bidFloor: 0.1, + bidId: '2d52001cabd527', + adUnitCode: 'div-gpt-ad-12345-0', + publisherId: '59ac17c192832d0011283fe3', + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + bidderVersion: adapter.version, + prebidVersion: version, + schain: BID.schain, + res: `${window.top.screen.width}x${window.top.screen.height}`, + mediaTypes: [BANNER], + uqs: getTopWindowQueryParams(), + 'ext.param1': 'loremipsum', + 'ext.param2': 'dolorsitamet', + } + }); + }); + + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + sandbox.restore(); + }); + }); + describe('getUserSyncs', function () { + it('should have valid user sync with iframeEnabled', function () { + const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); + + expect(result).to.deep.equal([{ + type: 'iframe', + url: 'https://sync.minutemedia-prebid.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' + }]); + }); + + it('should have valid user sync with cid on response', function () { + const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); + expect(result).to.deep.equal([{ + type: 'iframe', + url: 'https://sync.minutemedia-prebid.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' + }]); + }); + + it('should have valid user sync with pixelEnabled', function () { + const result = adapter.getUserSyncs({ pixelEnabled: true }, [SERVER_RESPONSE]); + + expect(result).to.deep.equal([{ + 'url': 'https://sync.minutemedia-prebid.com/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=', + 'type': 'image' + }]); + }) + }); + + describe('interpret response', function () { + it('should return empty array when there is no response', function () { + const responses = adapter.interpretResponse(null); + expect(responses).to.be.empty; + }); + + it('should return empty array when there is no ad', function () { + const responses = adapter.interpretResponse({ price: 1, ad: '' }); + expect(responses).to.be.empty; + }); + + it('should return empty array when there is no price', function () { + const responses = adapter.interpretResponse({ price: null, ad: 'great ad' }); + expect(responses).to.be.empty; + }); + + it('should return an array of interpreted banner responses', function () { + const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 0.8, + width: 300, + height: 250, + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 30, + ad: '', + meta: { + advertiserDomains: ['securepubads.g.doubleclick.net'] + } + }); + }); + + it('should return an array of interpreted video responses', function () { + const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 2, + width: 545, + height: 307, + mediaType: 'video', + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 60, + vastXml: '', + meta: { + advertiserDomains: ['minutemedia-prebid.com'] + } + }); + }); + + it('should take default TTL', function () { + const serverResponse = utils.deepClone(SERVER_RESPONSE); + delete serverResponse.body.results[0].exp; + const responses = adapter.interpretResponse(serverResponse, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0].ttl).to.equal(300); + }); + }); + + describe('user id system', function () { + Object.keys(SUPPORTED_ID_SYSTEMS).forEach((idSystemProvider) => { + const id = Date.now().toString(); + const bid = utils.deepClone(BID); + + const userId = (function () { + switch (idSystemProvider) { + case 'lipb': + return { lipbid: id }; + case 'parrableId': + return { eid: id }; + case 'id5id': + return { uid: id }; + default: + return id; + } + })(); + + bid.userId = { + [idSystemProvider]: userId + }; + + it(`should include 'uid.${idSystemProvider}' in request params`, function () { + const requests = adapter.buildRequests([bid], BIDDER_REQUEST); + expect(requests[0].data[`uid.${idSystemProvider}`]).to.equal(id); + }); + }); + }); + + describe('alternate param names extractors', function () { + it('should return undefined when param not supported', function () { + const cid = extractCID({ 'c_id': '1' }); + const pid = extractPID({ 'p_id': '1' }); + const subDomain = extractSubDomain({ 'sub_domain': 'prebid' }); + expect(cid).to.be.undefined; + expect(pid).to.be.undefined; + expect(subDomain).to.be.undefined; + }); + + it('should return value when param supported', function () { + const cid = extractCID({ 'cID': '1' }); + const pid = extractPID({ 'Pid': '2' }); + const subDomain = extractSubDomain({ 'subDOMAIN': 'prebid' }); + expect(cid).to.be.equal('1'); + expect(pid).to.be.equal('2'); + expect(subDomain).to.be.equal('prebid'); + }); + }); + + describe('unique deal id', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + mmplus: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + const key = 'myKey'; + let uniqueDealId; + beforeEach(() => { + uniqueDealId = getUniqueDealId(key, 0); + }) + + it('should get current unique deal id', function (done) { + // waiting some time so `now` will become past + setTimeout(() => { + const current = getUniqueDealId(key); + expect(current).to.be.equal(uniqueDealId); + done(); + }, 200); + }); + + it('should get new unique deal id on expiration', function (done) { + setTimeout(() => { + const current = getUniqueDealId(key, 100); + expect(current).to.not.be.equal(uniqueDealId); + done(); + }, 200) + }); + }); + + describe('storage utils', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + mmplus: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + it('should get value from storage with create param', function () { + const now = Date.now(); + const clock = useFakeTimers({ + shouldAdvanceTime: true, + now + }); + setStorageItem('myKey', 2020); + const { value, created } = getStorageItem('myKey'); + expect(created).to.be.equal(now); + expect(value).to.be.equal(2020); + expect(typeof value).to.be.equal('number'); + expect(typeof created).to.be.equal('number'); + clock.restore(); + }); + + it('should get external stored value', function () { + const value = 'superman' + window.localStorage.setItem('myExternalKey', value); + const item = getStorageItem('myExternalKey'); + expect(item).to.be.equal(value); + }); + + it('should parse JSON value', function () { + const data = JSON.stringify({ event: 'send' }); + const { event } = tryParseJSON(data); + expect(event).to.be.equal('send'); + }); + + it('should get original value on parse fail', function () { + const value = 21; + const parsed = tryParseJSON(value); + expect(typeof parsed).to.be.equal('number'); + expect(parsed).to.be.equal(value); + }); + }); +}); From d119d6526594de2eb64fea2df6ac54c67fd5e7f9 Mon Sep 17 00:00:00 2001 From: Prebid-Team Date: Fri, 10 Feb 2023 15:27:12 +0530 Subject: [PATCH 352/367] incrx Bid Adapter : add support for adtype and settings (#9477) * Update incrxBidAdapter.js We have added new keys in the endpoint response (Line 71, 72) due to which we need to update our Adapter with the latest file * fix linting * Update incrxBidAdapter_spec.js We have added new keys in the response * Update incrxBidAdapter.js removed consolelog lines --------- Co-authored-by: Chris Huie --- modules/incrxBidAdapter.js | 2 ++ test/spec/modules/incrxBidAdapter_spec.js | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/modules/incrxBidAdapter.js b/modules/incrxBidAdapter.js index 914ef0b904e..d054309ee40 100644 --- a/modules/incrxBidAdapter.js +++ b/modules/incrxBidAdapter.js @@ -68,6 +68,8 @@ export const spec = { requestId: response.slotBidId, cpm: response.cpm, currency: response.currency || DEFAULT_CURRENCY, + adType: response.adType || '1', + settings: response.settings, width: response.adWidth, height: response.adHeight, ttl: CREATIVE_TTL, diff --git a/test/spec/modules/incrxBidAdapter_spec.js b/test/spec/modules/incrxBidAdapter_spec.js index 8fb95742766..3fb4ffe2cd3 100644 --- a/test/spec/modules/incrxBidAdapter_spec.js +++ b/test/spec/modules/incrxBidAdapter_spec.js @@ -71,6 +71,8 @@ describe('IncrementX', function () { cpm: '0.7', ad: '

Ad from IncrementX

', slotBidId: 'bid-id-123456', + adType: '1', + settings: '1,2', nurl: 'htt://nurl.com', statusText: 'Success' } @@ -80,6 +82,8 @@ describe('IncrementX', function () { requestId: 'bid-id-123456', cpm: '0.7', currency: 'USD', + adType: '1', + settings: '1,2', netRevenue: false, width: '300', height: '250', From 926e4a35c740eece993dbb9f64c3d0a2435914a9 Mon Sep 17 00:00:00 2001 From: Saar Amrani Date: Sun, 12 Feb 2023 16:21:45 +0200 Subject: [PATCH 353/367] KueezRtbBidAdapter - pass gpp and bid data to server. (#9491) --- modules/kueezRtbBidAdapter.js | 74 ++++++++++++----- test/spec/modules/kueezRtbBidAdapter_spec.js | 85 +++++++++++++++----- 2 files changed, 117 insertions(+), 42 deletions(-) diff --git a/modules/kueezRtbBidAdapter.js b/modules/kueezRtbBidAdapter.js index 4b0e5055328..821b3263597 100644 --- a/modules/kueezRtbBidAdapter.js +++ b/modules/kueezRtbBidAdapter.js @@ -1,7 +1,8 @@ -import { _each, deepAccess, parseSizesInput, parseUrl, uniques, isFn } from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER, VIDEO } from '../src/mediaTypes.js'; -import { getStorageManager } from '../src/storageManager.js'; +import {_each, deepAccess, parseSizesInput, parseUrl, uniques, isFn} from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {getStorageManager} from '../src/storageManager.js'; +import { config } from '../src/config.js'; const GVLID = 1165; const DEFAULT_SUB_DOMAIN = 'exchange'; @@ -22,11 +23,11 @@ export const SUPPORTED_ID_SYSTEMS = { 'tdid': 1, 'pubProvidedId': 1 }; -const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }); +const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE}); function getTopWindowQueryParams() { try { - const parsedUrl = parseUrl(window.top.document.URL, { decodeSearchAsString: true }); + const parsedUrl = parseUrl(window.top.document.URL, {decodeSearchAsString: true}); return parsedUrl.search; } catch (e) { return ''; @@ -54,9 +55,22 @@ function isBidRequestValid(bid) { return !!(extractCID(params) && extractPID(params)); } -function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { - const { params, bidId, userId, adUnitCode, schain, mediaTypes } = bid; - let { bidFloor, ext } = params; +function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { + const { + params, + bidId, + userId, + adUnitCode, + schain, + mediaTypes, + auctionId, + transactionId, + bidderRequestId, + bidRequestsCount, + bidderRequestsCount, + bidderWinsCount + } = bid; + let {bidFloor, ext} = params; const hashUrl = hashCode(topWindowUrl); const uniqueDealId = getUniqueDealId(hashUrl); const cId = extractCID(params); @@ -90,7 +104,14 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { prebidVersion: '$prebid.version$', res: `${screen.width}x${screen.height}`, schain: schain, - mediaTypes: mediaTypes + mediaTypes: mediaTypes, + auctionId: auctionId, + transactionId: transactionId, + bidderRequestId: bidderRequestId, + bidRequestsCount: bidRequestsCount, + bidderRequestsCount: bidderRequestsCount, + bidderWinsCount: bidderWinsCount, + bidderTimeout: bidderTimeout }; appendUserIdsToRequestPayload(data, userId); @@ -107,6 +128,14 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { data.usPrivacy = bidderRequest.uspConsent; } + if (bidderRequest.gppConsent) { + data.gppString = bidderRequest.gppConsent.gppString; + data.gppSid = bidderRequest.gppConsent.applicableSections; + } else if (bidderRequest.ortb2?.regs?.gpp) { + data.gppString = bidderRequest.ortb2.regs.gpp; + data.gppSid = bidderRequest.ortb2.regs.gpp_sid; + } + const dto = { method: 'POST', url: `${createDomain(subDomain)}/prebid/multi/${cId}`, @@ -148,10 +177,11 @@ function appendUserIdsToRequestPayload(payloadRef, userIds) { function buildRequests(validBidRequests, bidderRequest) { const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; + const bidderTimeout = config.getConfig('bidderTimeout'); const requests = []; validBidRequests.forEach(validBidRequest => { const sizes = parseSizesInput(validBidRequest.sizes); - const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest); + const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout); requests.push(request); }); return requests; @@ -161,14 +191,14 @@ function interpretResponse(serverResponse, request) { if (!serverResponse || !serverResponse.body) { return []; } - const { bidId } = request.data; - const { results } = serverResponse.body; + const {bidId} = request.data; + const {results} = serverResponse.body; let output = []; try { results.forEach(result => { - const { creativeId, ad, price, exp, width, height, currency, advertiserDomains, mediaType = BANNER } = result; + const {creativeId, ad, price, exp, width, height, currency, advertiserDomains, mediaType = BANNER} = result; if (!ad || !price) { return; } @@ -207,8 +237,8 @@ function interpretResponse(serverResponse, request) { function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '') { let syncs = []; - const { iframeEnabled, pixelEnabled } = syncOptions; - const { gdprApplies, consentString = '' } = gdprConsent; + const {iframeEnabled, pixelEnabled} = syncOptions; + const {gdprApplies, consentString = ''} = gdprConsent; const cidArr = responses.filter(resp => deepAccess(resp, 'body.cid')).map(resp => resp.body.cid).filter(uniques); const params = `?cid=${encodeURIComponent(cidArr.join(','))}&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}` @@ -232,7 +262,9 @@ export function hashCode(s, prefix = '_') { let h = 0 let i = 0; if (l > 0) { - while (i < l) { h = (h << 5) - h + s.charCodeAt(i++) | 0; } + while (i < l) { + h = (h << 5) - h + s.charCodeAt(i++) | 0; + } } return prefix + h; } @@ -256,7 +288,8 @@ export function getUniqueDealId(key, expiry = UNIQUE_DEAL_ID_EXPIRY) { export function getStorageItem(key) { try { return tryParseJSON(storage.getDataFromLocalStorage(key)); - } catch (e) { } + } catch (e) { + } return null; } @@ -264,9 +297,10 @@ export function getStorageItem(key) { export function setStorageItem(key, value, timestamp) { try { const created = timestamp || Date.now(); - const data = JSON.stringify({ value, created }); + const data = JSON.stringify({value, created}); storage.setDataInLocalStorage(key, data); - } catch (e) { } + } catch (e) { + } } export function tryParseJSON(value) { diff --git a/test/spec/modules/kueezRtbBidAdapter_spec.js b/test/spec/modules/kueezRtbBidAdapter_spec.js index 30b2a46cefb..7c0d8e92001 100644 --- a/test/spec/modules/kueezRtbBidAdapter_spec.js +++ b/test/spec/modules/kueezRtbBidAdapter_spec.js @@ -1,4 +1,4 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import { spec as adapter, SUPPORTED_ID_SYSTEMS, @@ -13,9 +13,10 @@ import { getUniqueDealId, } from 'modules/kueezRtbBidAdapter.js'; import * as utils from 'src/utils.js'; -import { version } from 'package.json'; -import { useFakeTimers } from 'sinon'; -import { BANNER, VIDEO } from '../../../src/mediaTypes'; +import {version} from 'package.json'; +import {useFakeTimers} from 'sinon'; +import {BANNER, VIDEO} from '../../../src/mediaTypes'; +import {config} from '../../../src/config'; const SUB_DOMAIN = 'exchange'; @@ -36,6 +37,10 @@ const BID = { 'transactionId': 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', 'sizes': [[300, 250], [300, 600]], 'bidderRequestId': '1fdb5ff1b6eaa7', + 'auctionId': 'auction_id', + 'bidRequestsCount': 4, + 'bidderRequestsCount': 3, + 'bidderWinsCount': 1, 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', 'mediaTypes': [BANNER] @@ -46,6 +51,10 @@ const VIDEO_BID = { 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560', 'bidderRequestId': '12a8ae9ada9c13', 'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee', + 'auctionId': 'auction_id', + 'bidRequestsCount': 4, + 'bidderRequestsCount': 3, + 'bidderWinsCount': 1, 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', 'params': { 'subDomain': SUB_DOMAIN, @@ -78,10 +87,18 @@ const BIDDER_REQUEST = { 'consentString': 'consent_string', 'gdprApplies': true }, + 'gppString': 'gpp_string', + 'gppSid': [7], 'uspConsent': 'consent_string', 'refererInfo': { 'page': 'https://www.greatsite.com', 'ref': 'https://www.somereferrer.com' + }, + 'ortb2': { + 'regs': { + 'gpp': 'gpp_string', + 'gpp_sid': [7] + } } }; @@ -134,7 +151,7 @@ const REQUEST = { function getTopWindowQueryParams() { try { - const parsedUrl = utils.parseUrl(window.top.document.URL, { decodeSearchAsString: true }); + const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true}); return parsedUrl.search; } catch (e) { return ''; @@ -213,6 +230,9 @@ describe('KueezRtbBidAdapter', function () { it('should build video request', function () { const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + config.setConfig({ + bidderTimeout: 3000 + }); const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST); expect(requests).to.have.length(1); expect(requests[0]).to.deep.equal({ @@ -223,11 +243,20 @@ describe('KueezRtbBidAdapter', function () { bidFloor: 0.1, bidId: '2d52001cabd527', bidderVersion: adapter.version, + bidderRequestId: '12a8ae9ada9c13', cb: 1000, gdpr: 1, gdprConsent: 'consent_string', usPrivacy: 'consent_string', + gppString: 'gpp_string', + gppSid: [7], prebidVersion: version, + transactionId: '56e184c6-bde9-497b-b9b9-cf47a61381ee', + auctionId: 'auction_id', + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, publisherId: '59ac17c192832d0011283fe3', url: 'https%3A%2F%2Fwww.greatsite.com', referrer: 'https://www.somereferrer.com', @@ -259,6 +288,9 @@ describe('KueezRtbBidAdapter', function () { it('should build banner request for each size', function () { const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + config.setConfig({ + bidderTimeout: 3000 + }); const requests = adapter.buildRequests([BID], BIDDER_REQUEST); expect(requests).to.have.length(1); expect(requests[0]).to.deep.equal({ @@ -267,7 +299,16 @@ describe('KueezRtbBidAdapter', function () { data: { gdprConsent: 'consent_string', gdpr: 1, + gppString: 'gpp_string', + gppSid: [7], usPrivacy: 'consent_string', + transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + auctionId: 'auction_id', + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, + bidderRequestId: '1fdb5ff1b6eaa7', sizes: ['300x250', '300x600'], url: 'https%3A%2F%2Fwww.greatsite.com', referrer: 'https://www.somereferrer.com', @@ -296,7 +337,7 @@ describe('KueezRtbBidAdapter', function () { }); describe('getUserSyncs', function () { it('should have valid user sync with iframeEnabled', function () { - const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ type: 'iframe', @@ -305,7 +346,7 @@ describe('KueezRtbBidAdapter', function () { }); it('should have valid user sync with cid on response', function () { - const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ type: 'iframe', url: 'https://sync.kueezrtb.com/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' @@ -313,7 +354,7 @@ describe('KueezRtbBidAdapter', function () { }); it('should have valid user sync with pixelEnabled', function () { - const result = adapter.getUserSyncs({ pixelEnabled: true }, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ 'url': 'https://sync.kueezrtb.com/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=', @@ -329,12 +370,12 @@ describe('KueezRtbBidAdapter', function () { }); it('should return empty array when there is no ad', function () { - const responses = adapter.interpretResponse({ price: 1, ad: '' }); + const responses = adapter.interpretResponse({price: 1, ad: ''}); expect(responses).to.be.empty; }); it('should return empty array when there is no price', function () { - const responses = adapter.interpretResponse({ price: null, ad: 'great ad' }); + const responses = adapter.interpretResponse({price: null, ad: 'great ad'}); expect(responses).to.be.empty; }); @@ -394,11 +435,11 @@ describe('KueezRtbBidAdapter', function () { const userId = (function () { switch (idSystemProvider) { case 'lipb': - return { lipbid: id }; + return {lipbid: id}; case 'parrableId': - return { eid: id }; + return {eid: id}; case 'id5id': - return { uid: id }; + return {uid: id}; default: return id; } @@ -417,18 +458,18 @@ describe('KueezRtbBidAdapter', function () { describe('alternate param names extractors', function () { it('should return undefined when param not supported', function () { - const cid = extractCID({ 'c_id': '1' }); - const pid = extractPID({ 'p_id': '1' }); - const subDomain = extractSubDomain({ 'sub_domain': 'prebid' }); + const cid = extractCID({'c_id': '1'}); + const pid = extractPID({'p_id': '1'}); + const subDomain = extractSubDomain({'sub_domain': 'prebid'}); expect(cid).to.be.undefined; expect(pid).to.be.undefined; expect(subDomain).to.be.undefined; }); it('should return value when param supported', function () { - const cid = extractCID({ 'cID': '1' }); - const pid = extractPID({ 'Pid': '2' }); - const subDomain = extractSubDomain({ 'subDOMAIN': 'prebid' }); + const cid = extractCID({'cID': '1'}); + const pid = extractPID({'Pid': '2'}); + const subDomain = extractSubDomain({'subDOMAIN': 'prebid'}); expect(cid).to.be.equal('1'); expect(pid).to.be.equal('2'); expect(subDomain).to.be.equal('prebid'); @@ -488,7 +529,7 @@ describe('KueezRtbBidAdapter', function () { now }); setStorageItem('myKey', 2020); - const { value, created } = getStorageItem('myKey'); + const {value, created} = getStorageItem('myKey'); expect(created).to.be.equal(now); expect(value).to.be.equal(2020); expect(typeof value).to.be.equal('number'); @@ -504,8 +545,8 @@ describe('KueezRtbBidAdapter', function () { }); it('should parse JSON value', function () { - const data = JSON.stringify({ event: 'send' }); - const { event } = tryParseJSON(data); + const data = JSON.stringify({event: 'send'}); + const {event} = tryParseJSON(data); expect(event).to.be.equal('send'); }); From 5ba4e650e94701e81ac5d574c3607b6b80f6e261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9onard=20Labat?= Date: Mon, 13 Feb 2023 15:30:03 +0100 Subject: [PATCH 354/367] Criteo Bid Adapter: Map full user & site objects (#9534) DPP-4310 --- modules/criteoBidAdapter.js | 5 ++--- test/spec/modules/criteoBidAdapter_spec.js | 25 +++++++++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index fb42066a008..48fea78eeb4 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -523,9 +523,8 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { } }; }; - request.user = { - ext: bidderRequest.userExt - }; + request.user = bidderRequest.ortb2?.user || {}; + request.site = bidderRequest.ortb2?.site || {}; if (bidderRequest && bidderRequest.ceh) { request.user.ceh = bidderRequest.ceh; } diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index c54453bd7fc..da1a0ca7f32 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -1156,6 +1156,18 @@ describe('The Criteo bidding adapter', function () { it('should properly build a request with first party data', function () { const siteData = { keywords: ['power tools'], + content: { + data: [{ + name: 'some_provider', + ext: { + segtax: 3 + }, + segment: [ + { 'id': '1001' }, + { 'id': '1002' } + ] + }] + }, ext: { data: { pageType: 'article' @@ -1164,6 +1176,16 @@ describe('The Criteo bidding adapter', function () { }; const userData = { gender: 'M', + data: [{ + name: 'some_provider', + ext: { + segtax: 3 + }, + segment: [ + { 'id': '1001' }, + { 'id': '1002' } + ] + }], ext: { data: { registered: true @@ -1203,7 +1225,8 @@ describe('The Criteo bidding adapter', function () { const request = spec.buildRequests(bidRequests, { ...bidderRequest, ortb2 }); expect(request.data.publisher.ext).to.deep.equal({ data: { pageType: 'article' } }); - expect(request.data.user.ext).to.deep.equal({ data: { registered: true } }); + expect(request.data.user).to.deep.equal(userData); + expect(request.data.site).to.deep.equal(siteData); expect(request.data.slots[0].ext).to.deep.equal({ bidfloor: 0.75, data: { From b378dbae4318c708835e66d6d9ca64d7ae7138ee Mon Sep 17 00:00:00 2001 From: pnh-pubx <73683023+pnh-pubx@users.noreply.github.com> Date: Tue, 14 Feb 2023 18:18:47 +0530 Subject: [PATCH 355/367] Update: Replaced adUnitCount with adUnits array (#9510) --- modules/pubxaiAnalyticsAdapter.js | 4 ++-- test/spec/modules/pubxaiAnalyticsAdapter_spec.js | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/pubxaiAnalyticsAdapter.js b/modules/pubxaiAnalyticsAdapter.js index f7e73dd5fdd..96665c786bf 100644 --- a/modules/pubxaiAnalyticsAdapter.js +++ b/modules/pubxaiAnalyticsAdapter.js @@ -6,7 +6,7 @@ import CONSTANTS from '../src/constants.json'; const emptyUrl = ''; const analyticsType = 'endpoint'; -const pubxaiAnalyticsVersion = 'v1.1.0'; +const pubxaiAnalyticsVersion = 'v1.2.0'; const defaultHost = 'api.pbxai.com'; const auctionPath = '/analytics/auction'; const winningBidPath = '/analytics/bidwon'; @@ -154,7 +154,7 @@ function send(data, status) { search: location.search }); if (typeof data !== 'undefined' && typeof data.auctionInit !== 'undefined') { - data.pageDetail.adUnitCount = data.auctionInit.adUnitCodes ? data.auctionInit.adUnitCodes.length : null; + data.pageDetail.adUnits = data.auctionInit.adUnitCodes; data.initOptions.auctionId = data.auctionInit.auctionId; delete data.auctionInit; diff --git a/test/spec/modules/pubxaiAnalyticsAdapter_spec.js b/test/spec/modules/pubxaiAnalyticsAdapter_spec.js index 1ad23b9a41e..1dce87e4b8e 100644 --- a/test/spec/modules/pubxaiAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubxaiAnalyticsAdapter_spec.js @@ -567,7 +567,9 @@ describe('pubxai analytics adapter', function() { 'host': location.host, 'path': location.pathname, 'search': location.search, - 'adUnitCount': 1 + 'adUnits': [ + '/19968336/header-bid-tag-1' + ] }, 'floorDetail': { 'fetchStatus': 'success', From 3a9d4cafccc1da31fdd34cae4db33a1078ccca20 Mon Sep 17 00:00:00 2001 From: msmeza Date: Tue, 14 Feb 2023 15:13:13 +0100 Subject: [PATCH 356/367] Livewrapped Bid Adapter: added support for Price Floors Module (#9540) * Added support for the Price Floors Module * Use the ad server's currency when getting prices from the floors module * Default to USD if the ad server's currency can't be retrieved * Set the default currency at the right place * Added tests and made a minor change in how device width and height are calculated * Only include flrCur when ad requests contain floors --- modules/livewrappedBidAdapter.js | 44 +-- .../modules/livewrappedBidAdapter_spec.js | 269 +++++++++++++++++- 2 files changed, 295 insertions(+), 18 deletions(-) diff --git a/modules/livewrappedBidAdapter.js b/modules/livewrappedBidAdapter.js index 3839eb80b91..af754ae3ff0 100644 --- a/modules/livewrappedBidAdapter.js +++ b/modules/livewrappedBidAdapter.js @@ -1,4 +1,4 @@ -import {deepAccess, getWindowTop, isSafariBrowser, mergeDeep} from '../src/utils.js'; +import {deepAccess, getWindowTop, isSafariBrowser, mergeDeep, isFn, isPlainObject} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {find} from '../src/polyfill.js'; @@ -68,7 +68,9 @@ export const spec = { bidUrl = bidUrl ? bidUrl.params.bidUrl : URL; url = url ? url.params.url : (getAppDomain() || getTopWindowLocation(bidderRequest)); test = test ? test.params.test : undefined; - var adRequests = bidRequests.map(bidToAdRequest); + const currency = config.getConfig('currency.adServerCurrency') || 'USD'; + var adRequests = bidRequests.map(b => bidToAdRequest(b, currency)); + const adRequestsContainFloors = adRequests.some(r => r.flr !== undefined); if (eids) { ortb2 = mergeDeep(mergeDeep({}, ortb2 || {}), eids); @@ -96,7 +98,8 @@ export const spec = { rcv: getAdblockerRecovered(), adRequests: [...adRequests], rtbData: ortb2, - schain: schain + schain: schain, + flrCur: adRequestsContainFloors ? currency : undefined }; if (config.getConfig().debug) { @@ -223,13 +226,14 @@ function hasPubcid(bid) { return !!bid.crumbs && !!bid.crumbs.pubcid; } -function bidToAdRequest(bid) { +function bidToAdRequest(bid, currency) { var adRequest = { adUnitId: bid.params.adUnitId, callerAdUnitId: bid.params.adUnitName || bid.adUnitCode || bid.placementCode, bidId: bid.bidId, transactionId: bid.transactionId, formats: getSizes(bid).map(sizeToFormat), + flr: getBidFloor(bid, currency), options: bid.params.options }; @@ -264,6 +268,22 @@ function sizeToFormat(size) { } } +function getBidFloor(bid, currency) { + if (!isFn(bid.getFloor)) { + return undefined; + } + + const floor = bid.getFloor({ + currency: currency, + mediaType: '*', + size: '*' + }); + + return isPlainObject(floor) && !isNaN(floor.floor) && floor.currency == currency + ? floor.floor + : undefined; +} + function getAdblockerRecovered() { try { return getWindowTop().I12C && getWindowTop().I12C.Morph === 1; @@ -302,21 +322,13 @@ function getDeviceIfa() { } function getDeviceWidth() { - let device = config.getConfig('device'); - if (typeof device === 'object' && device.width) { - return device.width; - } - - return window.innerWidth; + const device = config.getConfig('device') || {}; + return device.w || window.innerWidth; } function getDeviceHeight() { - let device = config.getConfig('device'); - if (typeof device === 'object' && device.height) { - return device.height; - } - - return window.innerHeight; + const device = config.getConfig('device') || {}; + return device.h || window.innerHeight; } function getCoppa() { diff --git a/test/spec/modules/livewrappedBidAdapter_spec.js b/test/spec/modules/livewrappedBidAdapter_spec.js index a4fee5e3b26..6bbdf6e1705 100644 --- a/test/spec/modules/livewrappedBidAdapter_spec.js +++ b/test/spec/modules/livewrappedBidAdapter_spec.js @@ -13,6 +13,10 @@ describe('Livewrapped adapter tests', function () { window.livewrapped = undefined; + config.setConfig({ + device: { w: 100, h: 100 } + }); + bidderRequest = { bidderCode: 'livewrapped', auctionId: 'c45dd708-a418-42ec-b8a7-b70a6c6fab0a', @@ -43,6 +47,7 @@ describe('Livewrapped adapter tests', function () { afterEach(function () { sandbox.restore(); + config.resetConfig(); }); describe('isBidRequestValid', function() { @@ -351,7 +356,7 @@ describe('Livewrapped adapter tests', function () { expect(data).to.deep.equal(expectedQuery); }); - it('should make a well-formed single request object with ad blocker revovered parameter', function() { + it('should make a well-formed single request object with ad blocker recovered parameter', function() { sandbox.stub(utils, 'getWindowTop').returns({ I12C: { Morph: 1 } }); sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); @@ -489,7 +494,7 @@ describe('Livewrapped adapter tests', function () { return {bundle: 'bundle', domain: 'https://appdomain.com'}; } if (key === 'device') { - return {ifa: 'ifa', width: 300, height: 200}; + return {ifa: 'ifa', w: 300, h: 200}; } return origGetConfig.apply(config, arguments); }); @@ -839,6 +844,266 @@ describe('Livewrapped adapter tests', function () { expect(data).to.deep.equal(expectedQuery); }); + + it('width and height should default to values from window when not set in config', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + config.resetConfig(); + + let testbidRequest = clone(bidderRequest); + let result = spec.buildRequests(testbidRequest.bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: window.innerWidth, + height: window.innerHeight, + cookieSupport: true, + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}] + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + }); + + describe('price floors module', function() { + it('price floors module disabled', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let testbidRequest = clone(bidderRequest); + let result = spec.buildRequests(testbidRequest.bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}] + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + + it('getFloor does not return an object', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let testbidRequest = clone(bidderRequest); + let bids = testbidRequest.bids.map(b => { + b.getFloor = function () { return undefined; } + return b; + }); + let result = spec.buildRequests(bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}] + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + + it('getFloor returns a NaN floor', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let testbidRequest = clone(bidderRequest); + let bids = testbidRequest.bids.map(b => { + b.getFloor = function () { return { floor: undefined }; } + return b; + }); + let result = spec.buildRequests(bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}] + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + + it('getFloor returns unexpected currency', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let testbidRequest = clone(bidderRequest); + let bids = testbidRequest.bids.map(b => { + b.getFloor = function () { return { floor: 10, currency: 'EUR' }; } + return b; + }); + let result = spec.buildRequests(bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}] + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + + it('getFloor returns valid floor - ad server currency', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let origGetConfig = config.getConfig; + sandbox.stub(config, 'getConfig').callsFake(function (key) { + if (key === 'currency.adServerCurrency') { + return 'EUR'; + } + return origGetConfig.apply(config, arguments); + }); + + let testbidRequest = clone(bidderRequest); + let bids = testbidRequest.bids.map(b => { + b.getFloor = function () { return { floor: 10, currency: 'EUR' }; } + return b; + }); + let result = spec.buildRequests(bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + flrCur: 'EUR', + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}], + flr: 10 + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + + it('getFloor returns valid floor - default currency', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + + let testbidRequest = clone(bidderRequest); + let bids = testbidRequest.bids.map(b => { + b.getFloor = function () { return { floor: 10, currency: 'USD' }; } + return b; + }); + let result = spec.buildRequests(bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(result.url).to.equal('https://lwadm.com/ad'); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + userId: 'user id', + url: 'https://www.domain.com', + seats: {'dsp': ['seat 1']}, + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + flrCur: 'USD', + adRequests: [{ + adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37', + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}], + flr: 10 + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); }); it('should make use of user ids if available', function() { From e95769360d6ac5a3cdfe06df1bbd259d62255d1e Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 14 Feb 2023 16:17:47 +0100 Subject: [PATCH 357/367] Proxistore Bid Adapter: migrate to new subdomain (#9537) * Migrate to new subdomain * Upgrade domain in tests as well --- modules/proxistoreBidAdapter.js | 4 ++-- test/spec/modules/proxistoreBidAdapter_spec.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/proxistoreBidAdapter.js b/modules/proxistoreBidAdapter.js index 04d363be7fb..1f113f9c432 100644 --- a/modules/proxistoreBidAdapter.js +++ b/modules/proxistoreBidAdapter.js @@ -3,9 +3,9 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'proxistore'; const PROXISTORE_VENDOR_ID = 418; -const COOKIE_BASE_URL = 'https://abs.proxistore.com/v3/rtb/prebid/multi'; +const COOKIE_BASE_URL = 'https://api.proxistore.com/v3/rtb/prebid/multi'; const COOKIE_LESS_URL = - 'https://abs.cookieless-proxistore.com/v3/rtb/prebid/multi'; + 'https://api.cookieless-proxistore.com/v3/rtb/prebid/multi'; function _createServerRequest(bidRequests, bidderRequest) { var sizeIds = []; diff --git a/test/spec/modules/proxistoreBidAdapter_spec.js b/test/spec/modules/proxistoreBidAdapter_spec.js index 5b9f35c5bcf..bcddb9e8b04 100644 --- a/test/spec/modules/proxistoreBidAdapter_spec.js +++ b/test/spec/modules/proxistoreBidAdapter_spec.js @@ -55,9 +55,9 @@ describe('ProxistoreBidAdapter', function () { }); describe('buildRequests', function () { const url = { - cookieBase: 'https://abs.proxistore.com/v3/rtb/prebid/multi', + cookieBase: 'https://api.proxistore.com/v3/rtb/prebid/multi', cookieLess: - 'https://abs.cookieless-proxistore.com/v3/rtb/prebid/multi', + 'https://api.cookieless-proxistore.com/v3/rtb/prebid/multi', }; let request = spec.buildRequests([bid], bidderRequest); From f7b78cf64df38e98709189db9c45f7c9452e46e6 Mon Sep 17 00:00:00 2001 From: BaronJHYu <254878848@qq.com> Date: Wed, 15 Feb 2023 21:13:23 +0800 Subject: [PATCH 358/367] Mediago / Discovery Bid Adapters : update reporting of eids to server (#9539) * Mediago Bid Adapter:new adapter * remove console * change spec file to fix CircleCI * change spec file to fix CircleCI * change spec file * Update mediagoBidAdapter.js * Update mediagoBidAdapter.js * rerun CurcleCi * update mediagoBidAdapter * update discoveryBidAdapter * Discovery Bid Adapter : parameter updates * Mediago Bid Adapter : parameter updates * Mediago Bid Adapter : code style format * rerun circleci * rerun circleci * rerun circleci * rerun circleci * Update mediagoBidAdapter & discoveryBidAdapter:report eids to server * Update mediagoBidAdapter & discoveryBidAdapter:report eids to server --------- Co-authored-by: BaronYu --- modules/discoveryBidAdapter.js | 34 ++++++++++++++++++----------- modules/mediagoBidAdapter.js | 39 +++++++++++++++++++--------------- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/modules/discoveryBidAdapter.js b/modules/discoveryBidAdapter.js index 0c536892716..8145c9d25e7 100644 --- a/modules/discoveryBidAdapter.js +++ b/modules/discoveryBidAdapter.js @@ -40,7 +40,7 @@ const NATIVERET = { title: { len: 75, }, - } + }, ], plcmttype: 1, privacy: 1, @@ -63,9 +63,9 @@ const getUserID = () => { let idm = storage.getCookie(COOKIE_KEY_MGUID); if (idd && !idm) { - idm = idd + idm = idd; } else if (idm && !idd) { - idd = idm + idd = idm; } else if (!idd && !idm) { const uuid = utils.generateUUID(); storage.setCookie(COOKIE_KEY_MGUID, uuid); @@ -228,7 +228,7 @@ function getItems(validBidRequests, bidderRequest) { let id = '' + (i + 1); if (mediaTypes.native) { - ret = { ...NATIVERET, ...{ id, bidFloor } } + ret = { ...NATIVERET, ...{ id, bidFloor } }; } // banner if (mediaTypes.banner) { @@ -276,6 +276,11 @@ function getItems(validBidRequests, bidderRequest) { */ function getParam(validBidRequests, bidderRequest) { const pubcid = utils.deepAccess(validBidRequests[0], 'crumbs.pubcid'); + const sharedid = + utils.deepAccess(validBidRequests[0], 'userId.sharedid.id') || + utils.deepAccess(validBidRequests[0], 'userId.pubcid'); + const eids = validBidRequests[0].userIdAsEids || validBidRequests[0].userId; + let isMobile = getDevice() ? 1 : 0; // input test status by Publisher. more frequently for test true req let isTest = validBidRequests[0].params.test || 0; @@ -284,7 +289,8 @@ function getParam(validBidRequests, bidderRequest) { const timeout = bidderRequest.timeout || 2000; - const domain = utils.deepAccess(bidderRequest, 'refererInfo.domain') || document.domain; + const domain = + utils.deepAccess(bidderRequest, 'refererInfo.domain') || document.domain; const location = utils.deepAccess(bidderRequest, 'refererInfo.referer'); const page = utils.deepAccess(bidderRequest, 'refererInfo.page'); const referer = utils.deepAccess(bidderRequest, 'refererInfo.ref'); @@ -304,10 +310,14 @@ function getParam(validBidRequests, bidderRequest) { ua: navigator.userAgent, language: /en/.test(navigator.language) ? 'en' : navigator.language, }, + ext: { + eids, + }, user: { buyeruid: getUserID(), - id: pubcid, + id: sharedid || pubcid, }, + eids, tmax: timeout, site: { name: domain, @@ -317,7 +327,7 @@ function getParam(validBidRequests, bidderRequest) { mobile: isMobile, cat: [], // todo publisher: { - id: globals['publisher'] + id: globals['publisher'], // todo // name: xxx }, @@ -401,8 +411,8 @@ export const spec = { nurl: getKv(bid, 'nurl'), ttl: TIME_TO_LIVE, meta: { - advertiserDomains: getKv(bid, 'adomain') || [] - } + advertiserDomains: getKv(bid, 'adomain') || [], + }, }; if (mediaType === 'native') { const adm = getKv(bid, 'adm'); @@ -448,7 +458,7 @@ export const spec = { native.impressionTrackers.push(tracker.url); break; // case 2: - // native.javascriptTrackers = ``; + // native.javascriptTrackers = ``; // break; } }); @@ -484,8 +494,8 @@ export const spec = { */ onBidWon: function (bid) { if (bid['nurl']) { - utils.triggerPixel(bid['nurl']) + utils.triggerPixel(bid['nurl']); } - } + }, }; registerBidder(spec); diff --git a/modules/mediagoBidAdapter.js b/modules/mediagoBidAdapter.js index 16460b195f5..9b1b02e00a2 100644 --- a/modules/mediagoBidAdapter.js +++ b/modules/mediagoBidAdapter.js @@ -148,12 +148,12 @@ function isMobileAndTablet() { */ // function getBidFloor(bid, mediaType, sizes) { // var floor; -// var size = sizes.length === 1 ? sizes[0] : "*"; -// if (typeof bid.getFloor === "function") { -// const floorInfo = bid.getFloor({ currency: "USD", mediaType, size }); +// var size = sizes.length === 1 ? sizes[0] : '*'; +// if (typeof bid.getFloor === 'function') { +// const floorInfo = bid.getFloor({ currency: 'USD', mediaType, size }); // if ( -// typeof floorInfo === "object" && -// floorInfo.currency === "USD" && +// typeof floorInfo === 'object' && +// floorInfo.currency === 'USD' && // !isNaN(parseFloat(floorInfo.floor)) // ) { // floor = parseFloat(floorInfo.floor); @@ -255,7 +255,6 @@ function getItems(validBidRequests, bidderRequest) { // utils.deepAccess(req, 'ortb2Imp.ext.gpid') || // utils.deepAccess(req, 'ortb2Imp.ext.data.pbadslot') || // utils.deepAccess(req, 'params.placementId', 0); - // console.log("wjh getItems:", req, bidFloor, gpid); // if (mediaTypes.native) {} // banner广告类型 @@ -270,7 +269,7 @@ function getItems(validBidRequests, bidderRequest) { pos: 1, }, ext: { - // gpid: gpid, // 加入后无法返回广告 + // gpid: gpid, // 加入后无法返回广告 }, }; itemMaps[id] = { @@ -296,6 +295,8 @@ function getParam(validBidRequests, bidderRequest) { const sharedid = utils.deepAccess(validBidRequests[0], 'userId.sharedid.id') || utils.deepAccess(validBidRequests[0], 'userId.pubcid'); + const eids = validBidRequests[0].userIdAsEids || validBidRequests[0].userId; + let isMobile = isMobileAndTablet() ? 1 : 0; // input test status by Publisher. more frequently for test true req let isTest = validBidRequests[0].params.test || 0; @@ -318,19 +319,23 @@ function getParam(validBidRequests, bidderRequest) { cur: ['USD'], device: { connectiontype: 0, - // ip: '64.188.178.115', + // ip: '98.61.5.0', js: 1, - // language: "en", - // os: "Microsoft Windows", - // ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19043", + // language: 'en', + // os: 'Microsoft Windows', + // ua: 'Mozilla/5.0 (Linux; Android 12; SM-G970U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Mobile Safari/537.36', os: navigator.platform || '', ua: navigator.userAgent, language: /en/.test(navigator.language) ? 'en' : navigator.language, }, - ext: {}, + ext: { + eids, + }, user: { - id: sharedid || pubcid || getUserID(), + buyeruid: getUserID(), + id: sharedid || pubcid, }, + eids, site: { name: domain, domain: domain, @@ -420,12 +425,12 @@ export const spec = { nurl: getProperty(bid, 'nurl'), // adserverTargeting: { // granularityMultiplier: 0.1, - // priceGranularity: "pbHg", - // pbMg: "0.01", + // priceGranularity: 'pbHg', + // pbMg: '0.01', // }, - // pbMg: "0.01", + // pbMg: '0.01', // granularityMultiplier: 0.1, - // priceGranularity: "pbHg", + // priceGranularity: 'pbHg', }; bidResponses.push(bidResponse); } From 16166bde8690569f74e07ecb1d780ea576c09820 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Wed, 15 Feb 2023 11:46:52 -0700 Subject: [PATCH 359/367] Core & PBS adapter: introduce bidder-level `ortb2Imp`; s2s-only `module` bids; PBS bidder-level `imp` params (#9470) * adUnit.bid.ortb2Imp support * Add "module" bids and PBS bidder-level imp params * Merge branch 'master' into bid-ortb2Imp * Update tests --- .../prebidServerBidAdapter/ortbConverter.js | 6 + src/adapterManager.js | 44 ++++-- src/utils.js | 2 +- .../modules/prebidServerBidAdapter_spec.js | 56 +++++++ test/spec/unit/core/adapterManager_spec.js | 147 ++++++++++++++++++ 5 files changed, 240 insertions(+), 15 deletions(-) diff --git a/modules/prebidServerBidAdapter/ortbConverter.js b/modules/prebidServerBidAdapter/ortbConverter.js index e35a3825826..be034b3cfbe 100644 --- a/modules/prebidServerBidAdapter/ortbConverter.js +++ b/modules/prebidServerBidAdapter/ortbConverter.js @@ -32,6 +32,12 @@ const PBS_CONVERTER = ortbConverter({ imp(buildImp, proxyBidRequest, context) { Object.assign(context, proxyBidRequest.pbsData); const imp = buildImp(proxyBidRequest, context); + (proxyBidRequest.bids || []).forEach(bid => { + if (bid.ortb2Imp && Object.keys(bid.ortb2Imp).length > 0) { + // set bidder-level imp attributes; see https://github.com/prebid/prebid-server/issues/2335 + deepSetValue(imp, `ext.prebid.imp.${bid.bidder}`, bid.ortb2Imp); + } + }); if (Object.values(SUPPORTED_MEDIA_TYPES).some(mtype => imp[mtype])) { imp.secure = context.s2sBidRequest.s2sConfig.secure; return imp; diff --git a/src/adapterManager.js b/src/adapterManager.js index f4f9e59fb84..c9715fe0168 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -65,15 +65,21 @@ var _analyticsRegistry = {}; function getBids({bidderCode, auctionId, bidderRequestId, adUnits, src, metrics}) { return adUnits.reduce((result, adUnit) => { - result.push(adUnit.bids.filter(bid => bid.bidder === bidderCode) - .reduce((bids, bid) => { - bid = Object.assign({}, bid, getDefinedParams(adUnit, [ - 'nativeParams', - 'nativeOrtbRequest', - 'ortb2Imp', - 'mediaType', - 'renderer' - ])); + const bids = adUnit.bids.filter(bid => bid.bidder === bidderCode); + if (bidderCode == null && bids.length === 0 && adUnit.s2sBid != null) { + bids.push({bidder: null}); + } + result.push( + bids.reduce((bids, bid) => { + bid = Object.assign({}, bid, + {ortb2Imp: mergeDeep({}, adUnit.ortb2Imp, bid.ortb2Imp)}, + getDefinedParams(adUnit, [ + 'nativeParams', + 'nativeOrtbRequest', + 'mediaType', + 'renderer' + ]) + ); const mediaTypes = bid.mediaTypes == null ? adUnit.mediaTypes : bid.mediaTypes @@ -128,9 +134,18 @@ export const filterBidsForAdUnit = hook('sync', _filterBidsForAdUnit, 'filterBid function getAdUnitCopyForPrebidServer(adUnits, s2sConfig) { let adUnitsCopy = deepClone(adUnits); + let hasModuleBids = false; adUnitsCopy.forEach((adUnit) => { // filter out client side bids + const s2sBids = adUnit.bids.filter((b) => b.module === 'pbsBidAdapter' && b.params?.configName === s2sConfig.configName); + if (s2sBids.length === 1) { + adUnit.s2sBid = s2sBids[0]; + hasModuleBids = true; + adUnit.ortb2Imp = mergeDeep({}, adUnit.s2sBid.ortb2Imp, adUnit.ortb2Imp); + } else if (s2sBids.length > 1) { + logWarn('Multiple "module" bids for the same s2s configuration; all will be ignored', s2sBids); + } adUnit.bids = filterBidsForAdUnit(adUnit.bids, s2sConfig) .map((bid) => { bid.bid_id = getUniqueIdentifierStr(); @@ -140,9 +155,9 @@ function getAdUnitCopyForPrebidServer(adUnits, s2sConfig) { // don't send empty requests adUnitsCopy = adUnitsCopy.filter(adUnit => { - return adUnit.bids.length !== 0; + return adUnit.bids.length !== 0 || adUnit.s2sBid != null; }); - return adUnitsCopy; + return {adUnits: adUnitsCopy, hasModuleBids}; } function getAdUnitCopyForClientAdapters(adUnits) { @@ -244,11 +259,12 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a _s2sConfigs.forEach(s2sConfig => { if (s2sConfig && s2sConfig.enabled) { - let adUnitsS2SCopy = getAdUnitCopyForPrebidServer(adUnits, s2sConfig); + let {adUnits: adUnitsS2SCopy, hasModuleBids} = getAdUnitCopyForPrebidServer(adUnits, s2sConfig); // uniquePbsTid is so we know which server to send which bids to during the callBids function let uniquePbsTid = generateUUID(); - serverBidders.forEach(bidderCode => { + + (serverBidders.length === 0 && hasModuleBids ? [null] : serverBidders).forEach(bidderCode => { const bidderRequestId = getUniqueIdentifierStr(); const metrics = auctionMetrics.fork(); const bidderRequest = addOrtb2({ @@ -279,7 +295,7 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a bidRequests.forEach(request => { if (request.adUnitsS2SCopy === undefined) { - request.adUnitsS2SCopy = adUnitsS2SCopy.filter(adUnitCopy => adUnitCopy.bids.length > 0); + request.adUnitsS2SCopy = adUnitsS2SCopy.filter(au => au.bids.length > 0 || au.s2sBid != null); } }); } diff --git a/src/utils.js b/src/utils.js index 869e1007841..8df45bab9d2 100644 --- a/src/utils.js +++ b/src/utils.js @@ -710,7 +710,7 @@ export function getKeyByValue(obj, value) { export function getBidderCodes(adUnits = $$PREBID_GLOBAL$$.adUnits) { // this could memoize adUnits return adUnits.map(unit => unit.bids.map(bid => bid.bidder) - .reduce(flatten, [])).reduce(flatten, []).filter(uniques); + .reduce(flatten, [])).reduce(flatten, []).filter((bidder) => typeof bidder !== 'undefined').filter(uniques); } export function isGptPubadsDefined() { diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index cffc75f6949..0ce060b9904 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -2660,6 +2660,62 @@ describe('S2S Adapter', function () { }); }); + describe('Bidder-level ortb2Imp', () => { + beforeEach(() => { + config.setConfig({ + s2sConfig: { + ...CONFIG, + bidders: ['A', 'B'] + } + }) + }) + it('should be set on imp.ext.prebid.imp', () => { + const s2sReq = utils.deepClone(REQUEST); + s2sReq.ad_units[0].ortb2Imp = {l0: 'adUnit'}; + s2sReq.ad_units[0].bids = [ + { + bidder: 'A', + bid_id: 1, + ortb2Imp: { + l2: 'A' + } + }, + { + bidder: 'B', + bid_id: 2, + ortb2Imp: { + l2: 'B' + } + } + ]; + const bidderReqs = [ + { + ...BID_REQUESTS[0], + bidderCode: 'A', + bids: [{ + bidId: 1, + bidder: 'A' + }] + }, + { + ...BID_REQUESTS[0], + bidderCode: 'B', + bids: [{ + bidId: 2, + bidder: 'B' + }] + } + ] + adapter.callBids(s2sReq, bidderReqs, addBidResponse, done, ajax); + const req = JSON.parse(server.requests[0].requestBody); + expect(req.imp[0].l0).to.eql('adUnit'); + expect(req.imp[0].ext.prebid.imp).to.eql({ + A: {l2: 'A'}, + B: {l2: 'B'} + }); + }); + }); + describe('ext.prebid config', function () { it('should send \"imp.ext.prebid.storedrequest.id\" if \"ortb2Imp.ext.prebid.storedrequest.id\" is set', function () { const consentConfig = { s2sConfig: CONFIG }; diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js index 3fea8988a95..06366e8cc5c 100644 --- a/test/spec/unit/core/adapterManager_spec.js +++ b/test/spec/unit/core/adapterManager_spec.js @@ -1757,6 +1757,153 @@ describe('adapterManager tests', function () { requests.appnexus.bids.forEach((bid) => expect(bid.ortb2).to.eql(requests.appnexus.ortb2)); }); + it('should merge in bid-level ortb2Imp with adUnit-level ortb2Imp', () => { + const adUnit = { + ...adUnits[1], + ortb2Imp: {oneone: {twoone: 'val'}, onetwo: 'val'} + }; + adUnit.bids[0].ortb2Imp = {oneone: {twotwo: 'val'}, onethree: 'val', onetwo: 'val2'}; + const reqs = Object.fromEntries( + adapterManager.makeBidRequests([adUnit], 123, 'auction-id', 123, [], {}) + .map((req) => [req.bidderCode, req]) + ); + sinon.assert.match(reqs[adUnit.bids[0].bidder].bids[0].ortb2Imp, { + oneone: { + twoone: 'val', + twotwo: 'val', + }, + onetwo: 'val2', + onethree: 'val' + }) + sinon.assert.match(reqs[adUnit.bids[1].bidder].bids[0].ortb2Imp, adUnit.ortb2Imp) + }) + + it('picks ortb2Imp from "module" when only one s2sConfig is set', () => { + config.setConfig({ + s2sConfig: [ + { + enabled: true, + adapter: 'mockS2S1', + } + ] + }); + const adUnit = { + code: 'mockau', + ortb2Imp: { + p1: 'adUnit' + }, + bids: [ + { + module: 'pbsBidAdapter', + ortb2Imp: { + p2: 'module' + } + } + ] + }; + const req = adapterManager.makeBidRequests([adUnit], 123, 'auction-id', 123, [], {})[0]; + [req.adUnitsS2SCopy[0].ortb2Imp, req.bids[0].ortb2Imp].forEach(imp => { + sinon.assert.match(imp, { + p1: 'adUnit', + p2: 'module' + }); + }); + }); + + describe('with named s2s configs', () => { + beforeEach(() => { + config.setConfig({ + s2sConfig: [ + { + enabled: true, + adapter: 'mockS2S1', + configName: 'one', + bidders: ['A'] + }, + { + enabled: true, + adapter: 'mockS2S2', + configName: 'two', + bidders: ['B'] + } + ] + }) + }); + + it('generates requests for "module" bids', () => { + const adUnit = { + code: 'mockau', + ortb2Imp: { + p1: 'adUnit' + }, + bids: [ + { + module: 'pbsBidAdapter', + params: {configName: 'one'}, + ortb2Imp: { + p2: 'one' + } + }, + { + module: 'pbsBidAdapter', + params: {configName: 'two'}, + ortb2Imp: { + p2: 'two' + } + } + ] + }; + const reqs = adapterManager.makeBidRequests([adUnit], 123, 'auction-id', 123, [], {}); + [reqs[0].adUnitsS2SCopy[0].ortb2Imp, reqs[0].bids[0].ortb2Imp].forEach(imp => { + sinon.assert.match(imp, { + p1: 'adUnit', + p2: 'one' + }) + }); + [reqs[1].adUnitsS2SCopy[0].ortb2Imp, reqs[1].bids[0].ortb2Imp].forEach(imp => { + sinon.assert.match(imp, { + p1: 'adUnit', + p2: 'two' + }) + }); + }); + + it('applies module-level ortb2Imp to "normal" s2s requests', () => { + const adUnit = { + code: 'mockau', + ortb2Imp: { + p1: 'adUnit' + }, + bids: [ + { + module: 'pbsBidAdapter', + params: {configName: 'one'}, + ortb2Imp: { + p2: 'one' + } + }, + { + bidder: 'A', + ortb2Imp: { + p3: 'bidderA' + } + } + ] + }; + const reqs = adapterManager.makeBidRequests([adUnit], 123, 'auction-id', 123, [], {}); + expect(reqs.length).to.equal(1); + sinon.assert.match(reqs[0].adUnitsS2SCopy[0].ortb2Imp, { + p1: 'adUnit', + p2: 'one' + }) + sinon.assert.match(reqs[0].bids[0].ortb2Imp, { + p1: 'adUnit', + p2: 'one', + p3: 'bidderA' + }) + }); + }); + describe('when calling the s2s adapter', () => { beforeEach(() => { config.setConfig({ From 7b7389c5abdd05626f71c3df606a93713d1b9f85 Mon Sep 17 00:00:00 2001 From: JacobKlein26 <42449375+JacobKlein26@users.noreply.github.com> Date: Wed, 15 Feb 2023 13:58:36 -0500 Subject: [PATCH 360/367] nextMillennium Bid Adapter: cookie sync URL (#9522) * if no response, use hardcoded URL * lint added a space * net rev true * add test and fix queries (&) --- modules/nextMillenniumBidAdapter.js | 10 +++++++++- test/spec/modules/nextMillenniumBidAdapter_spec.js | 11 +++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/modules/nextMillenniumBidAdapter.js b/modules/nextMillenniumBidAdapter.js index 655f5fc3a35..6abb369522b 100644 --- a/modules/nextMillenniumBidAdapter.js +++ b/modules/nextMillenniumBidAdapter.js @@ -24,6 +24,7 @@ import { getRefererInfo } from '../src/refererDetection.js'; const BIDDER_CODE = 'nextMillennium'; const ENDPOINT = 'https://pbs.nextmillmedia.com/openrtb2/auction'; const TEST_ENDPOINT = 'https://test.pbs.nextmillmedia.com/openrtb2/auction'; +const SYNC_ENDPOINT = 'https://cookies.nextmillmedia.com/sync?'; const REPORT_ENDPOINT = 'https://report2.hb.brainlyads.com/statistics/metric'; const TIME_TO_LIVE = 360; const VIDEO_PARAMS = [ @@ -182,7 +183,7 @@ export const spec = { height: bid.h, creativeId: bid.adid, currency: response.cur, - netRevenue: false, + netRevenue: true, ttl: TIME_TO_LIVE, meta: { advertiserDomains: bid.adomain || [] @@ -231,6 +232,13 @@ export const spec = { }) } + if (!pixels.length) { + let syncUrl = SYNC_ENDPOINT; + if (gdprConsent && gdprConsent.gdprApplies) syncUrl += 'gdpr=1&gdpr_consent=' + gdprConsent.consentString + '&'; + if (uspConsent) syncUrl += 'us_privacy=' + uspConsent + '&'; + if (syncOptions.iframeEnabled) pixels.push({type: 'iframe', url: syncUrl + 'type=iframe'}); + if (syncOptions.pixelEnabled) pixels.push({type: 'image', url: syncUrl + 'type=image'}); + } return pixels; }, diff --git a/test/spec/modules/nextMillenniumBidAdapter_spec.js b/test/spec/modules/nextMillenniumBidAdapter_spec.js index 571bb5fc584..7f40e7d89f8 100644 --- a/test/spec/modules/nextMillenniumBidAdapter_spec.js +++ b/test/spec/modules/nextMillenniumBidAdapter_spec.js @@ -142,6 +142,17 @@ describe('nextMillenniumBidAdapterTests', function() { expect(userSync[0].url).to.equal('urlB'); }); + it('Test getUserSyncs with no response', function () { + const syncOptions = { + 'iframeEnabled': true, + 'pixelEnabled': false + } + let userSync = spec.getUserSyncs(syncOptions, [], bidRequestData[0].gdprConsent, bidRequestData[0].uspConsent); + expect(userSync).to.be.an('array') + expect(userSync[0].type).to.equal('iframe') + expect(userSync[0].url).to.equal('https://cookies.nextmillmedia.com/sync?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---&type=iframe') + }) + it('Test getUserSyncs function if GDPR is undefined', function () { const syncOptions = { 'iframeEnabled': false, From 7b2fdd57c0f4c16db3f58fc90db7f870669235d9 Mon Sep 17 00:00:00 2001 From: Gammelin Guillaume Date: Wed, 15 Feb 2023 20:07:18 +0100 Subject: [PATCH 361/367] Adagio Bid Adapter: update video params validation (#9542) * Adagio Bid Adapter: update video params validation * Adagio: update adapter doc --- modules/adagioBidAdapter.js | 28 +++++++++++----------- modules/adagioBidAdapter.md | 4 +++- test/spec/modules/adagioBidAdapter_spec.js | 4 ++-- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js index 12fd50c6636..adb9744428f 100644 --- a/modules/adagioBidAdapter.js +++ b/modules/adagioBidAdapter.js @@ -15,6 +15,7 @@ import { isFn, isInteger, isNumber, + isArrayOfNums, logError, logInfo, logWarn, @@ -48,33 +49,32 @@ const ADAGIO_PUBKEY = 'AL16XT44Sfp+8SHVF1UdC7hydPSMVLMhsYknKDdwqq+0ToDSJrP0+Qh0k const ADAGIO_PUBKEY_E = 65537; const CURRENCY = 'USD'; -// This provide a whitelist and a basic validation -// of OpenRTB 2.5 options used by the Adagio SSP. -// https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf +// This provide a whitelist and a basic validation of OpenRTB 2.6 options used by the Adagio SSP. +// https://iabtechlab.com/wp-content/uploads/2022/04/OpenRTB-2-6_FINAL.pdf export const ORTB_VIDEO_PARAMS = { 'mimes': (value) => Array.isArray(value) && value.length > 0 && value.every(v => typeof v === 'string'), 'minduration': (value) => isInteger(value), 'maxduration': (value) => isInteger(value), - 'protocols': (value) => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].indexOf(v) !== -1), + 'protocols': (value) => isArrayOfNums(value), 'w': (value) => isInteger(value), 'h': (value) => isInteger(value), 'startdelay': (value) => isInteger(value), - 'placement': (value) => [1, 2, 3, 4, 5].indexOf(value) !== -1, - 'linearity': (value) => [1, 2].indexOf(value) !== -1, - 'skip': (value) => [0, 1].indexOf(value) !== -1, + 'placement': (value) => isInteger(value), + 'linearity': (value) => isInteger(value), + 'skip': (value) => isInteger(value), 'skipmin': (value) => isInteger(value), 'skipafter': (value) => isInteger(value), 'sequence': (value) => isInteger(value), - 'battr': (value) => Array.isArray(value) && value.every(v => Array.from({length: 17}, (_, i) => i + 1).indexOf(v) !== -1), + 'battr': (value) => isArrayOfNums(value), 'maxextended': (value) => isInteger(value), 'minbitrate': (value) => isInteger(value), 'maxbitrate': (value) => isInteger(value), - 'boxingallowed': (value) => [0, 1].indexOf(value) !== -1, - 'playbackmethod': (value) => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6].indexOf(v) !== -1), - 'playbackend': (value) => [1, 2, 3].indexOf(value) !== -1, - 'delivery': (value) => [1, 2, 3].indexOf(value) !== -1, - 'pos': (value) => [0, 1, 2, 3, 4, 5, 6, 7].indexOf(value) !== -1, - 'api': (value) => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6].indexOf(v) !== -1) + 'boxingallowed': (value) => isInteger(value), + 'playbackmethod': (value) => isArrayOfNums(value), + 'playbackend': (value) => isInteger(value), + 'delivery': (value) => isInteger(value), + 'pos': (value) => isInteger(value), + 'api': (value) => isArrayOfNums(value) }; let currentWindow; diff --git a/modules/adagioBidAdapter.md b/modules/adagioBidAdapter.md index b804a72fea9..f10c0a75e4d 100644 --- a/modules/adagioBidAdapter.md +++ b/modules/adagioBidAdapter.md @@ -81,8 +81,10 @@ var adUnits = [ cpm: 3.00 // default to 1.00 }, video: { + api: [2, 7], // Required - Your video player must at least support the value 2 and/or 7. + playbackMethod: [6], // Highly recommended skip: 0 - // OpenRTB 2.5 video options defined here override ones defined in mediaTypes. + // OpenRTB video options defined here override ones defined in mediaTypes. }, native: { // Optional OpenRTB Native 1.2 request object. Only `context`, `plcmttype` fields are supported. diff --git a/test/spec/modules/adagioBidAdapter_spec.js b/test/spec/modules/adagioBidAdapter_spec.js index 8abdc621922..ba1db077488 100644 --- a/test/spec/modules/adagioBidAdapter_spec.js +++ b/test/spec/modules/adagioBidAdapter_spec.js @@ -381,8 +381,8 @@ describe('Adagio bid adapter', () => { context: 'outstream', playerSize: [[300, 250]], mimes: ['video/mp4'], - api: 5, // will be removed because invalid - playbackmethod: [7], // will be removed because invalid + api: 'val', // will be removed because invalid + playbackmethod: ['val'], // will be removed because invalid } }, }).withParams({ From 623b88edcccde6c414f101c80375612c8f39268b Mon Sep 17 00:00:00 2001 From: Patrick Loughrey Date: Wed, 15 Feb 2023 14:21:48 -0500 Subject: [PATCH 362/367] Triplelift Bid Adapter: set networkId in response (#9545) * prioritize topmostlocation * adds test for topmostlocation / referrer * cleanup * delete param after test * TL-32803: Update referrer logic * TL-32803: Update referrer logic * TL-34204: Add support for GPP * TL-34944: Add logic to pass networkId back in the bid response * TL-34944: Add logic to pass networkId back in the bid response * TL-34944: Add logic to pass networkId back in the bid response * few more tests --------- Co-authored-by: Nick Llerandi Co-authored-by: nllerandi3lift <75995508+nllerandi3lift@users.noreply.github.com> --- modules/tripleliftBidAdapter.js | 4 ++++ test/spec/modules/tripleliftBidAdapter_spec.js | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/modules/tripleliftBidAdapter.js b/modules/tripleliftBidAdapter.js index 3ce44d067bf..8012a4a8051 100644 --- a/modules/tripleliftBidAdapter.js +++ b/modules/tripleliftBidAdapter.js @@ -436,6 +436,10 @@ function _buildResponseObject(bidderRequest, bid) { if (bid.tl_source && bid.tl_source == 'tlx') { bidResponse.meta.mediaType = 'native'; } + + if (creativeId) { + bidResponse.meta.networkId = creativeId.slice(0, creativeId.indexOf('_')); + } }; return bidResponse; } diff --git a/test/spec/modules/tripleliftBidAdapter_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js index a20719d89e5..221ffb8371f 100644 --- a/test/spec/modules/tripleliftBidAdapter_spec.js +++ b/test/spec/modules/tripleliftBidAdapter_spec.js @@ -1437,6 +1437,13 @@ describe('triplelift adapter', function () { expect(result[0].meta.advertiserDomains[1]).to.equal('internetalerts.org'); expect(result[1].meta).to.not.have.key('advertiserDomains'); }); + + it('should include networkId in the meta field if available', function () { + let result = tripleliftAdapterSpec.interpretResponse(response, {bidderRequest}); + expect(result[1].meta.networkId).to.equal('10092'); + expect(result[2].meta.networkId).to.equal('5989'); + expect(result[3].meta.networkId).to.equal('5989'); + }); }); describe('getUserSyncs', function() { From 23fe08397668f252c774213a3be14617264a4e8d Mon Sep 17 00:00:00 2001 From: matthieularere-msq <63732822+matthieularere-msq@users.noreply.github.com> Date: Wed, 15 Feb 2023 20:58:26 +0100 Subject: [PATCH 363/367] Oxxion Analytics Adapter : initial adapter release (#9449) * oxxion Analytics Adapter * debug(oxxionRtdProvider): onAuctionInit() * Revert "debug(oxxionRtdProvider): onAuctionInit()" This reverts commit d0894e34119fdbc9a075e35ea3f309774ca6bbbd. --------- Co-authored-by: Anthony Guyot --- modules/oxxionAnalyticsAdapter.js | 210 ++++++++++++ modules/oxxionAnalyticsAdapter.md | 33 ++ .../modules/oxxionAnalyticsAdapter_spec.js | 324 ++++++++++++++++++ 3 files changed, 567 insertions(+) create mode 100644 modules/oxxionAnalyticsAdapter.js create mode 100644 modules/oxxionAnalyticsAdapter.md create mode 100644 test/spec/modules/oxxionAnalyticsAdapter_spec.js diff --git a/modules/oxxionAnalyticsAdapter.js b/modules/oxxionAnalyticsAdapter.js new file mode 100644 index 00000000000..73160b5bebf --- /dev/null +++ b/modules/oxxionAnalyticsAdapter.js @@ -0,0 +1,210 @@ +import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import CONSTANTS from '../src/constants.json'; +import { ajax } from '../src/ajax.js'; + +const analyticsType = 'endpoint'; +const url = 'URL_TO_SERVER_ENDPOINT'; + +const { + EVENTS: { + AUCTION_END, + BID_WON, + BID_RESPONSE, + BID_REQUESTED, + BID_TIMEOUT, + } +} = CONSTANTS; + +let saveEvents = {} +let allEvents = {} +let auctionEnd = {} +let initOptions = {} +let endpoint = 'https://default' +let requestsAttributes = ['adUnitCode', 'auctionId', 'bidder', 'bidderCode', 'bidId', 'cpm', 'creativeId', 'currency', 'width', 'height', 'mediaType', 'netRevenue', 'originalCpm', 'originalCurrency', 'requestId', 'size', 'source', 'status', 'timeToRespond', 'transactionId', 'ttl', 'sizes', 'mediaTypes', 'src', 'params', 'userId', 'labelAny', 'bids', 'adId']; + +function getAdapterNameForAlias(aliasName) { + return adapterManager.aliasRegistry[aliasName] || aliasName; +} + +function filterAttributes(arg, removead) { + let response = {}; + if (typeof arg == 'object') { + if (typeof arg['bidderCode'] == 'string') { + response['originalBidder'] = getAdapterNameForAlias(arg['bidderCode']); + } else if (typeof arg['bidder'] == 'string') { + response['originalBidder'] = getAdapterNameForAlias(arg['bidder']); + } + if (!removead && typeof arg['ad'] != 'undefined') { + response['ad'] = arg['ad']; + } + if (typeof arg['gdprConsent'] != 'undefined') { + response['gdprConsent'] = {}; + if (typeof arg['gdprConsent']['consentString'] != 'undefined') { response['gdprConsent']['consentString'] = arg['gdprConsent']['consentString']; } + } + if (typeof arg['meta'] == 'object' && typeof arg['meta']['advertiserDomains'] != 'undefined') { + response['meta'] = {'advertiserDomains': arg['meta']['advertiserDomains']}; + } + requestsAttributes.forEach((attr) => { + if (typeof arg[attr] != 'undefined') { response[attr] = arg[attr]; } + }); + if (typeof response['creativeId'] == 'number') { response['creativeId'] = response['creativeId'].toString(); } + } + return response; +} + +function cleanAuctionEnd(args) { + let response = {}; + let filteredObj; + let objects = ['bidderRequests', 'bidsReceived', 'noBids', 'adUnits']; + objects.forEach((attr) => { + if (Array.isArray(args[attr])) { + response[attr] = []; + args[attr].forEach((obj) => { + filteredObj = filterAttributes(obj, true); + if (typeof obj['bids'] == 'object') { + filteredObj['bids'] = []; + obj['bids'].forEach((bid) => { + filteredObj['bids'].push(filterAttributes(bid, true)); + }); + } + response[attr].push(filteredObj); + }); + } + }); + return response; +} + +function cleanCreatives(args) { + return filterAttributes(args, false); +} + +function enhanceMediaType(arg) { + saveEvents['bidRequested'].forEach((bidRequested) => { + if (bidRequested['auctionId'] == arg['auctionId'] && Array.isArray(bidRequested['bids'])) { + bidRequested['bids'].forEach((bid) => { + if (bid['transactionId'] == arg['transactionId'] && bid['bidId'] == arg['requestId']) { arg['mediaTypes'] = bid['mediaTypes']; } + }); + } + }); + return arg; +} + +function addBidResponse(args) { + let eventType = BID_RESPONSE; + let argsCleaned = cleanCreatives(JSON.parse(JSON.stringify(args))); ; + if (allEvents[eventType] == undefined) { allEvents[eventType] = [] } + allEvents[eventType].push(argsCleaned); +} + +function addBidRequested(args) { + let eventType = BID_REQUESTED; + let argsCleaned = filterAttributes(args, true); + if (saveEvents[eventType] == undefined) { saveEvents[eventType] = [] } + saveEvents[eventType].push(argsCleaned); +} + +function addTimeout(args) { + let eventType = BID_TIMEOUT; + if (saveEvents[eventType] == undefined) { saveEvents[eventType] = [] } + saveEvents[eventType].push(args); + let argsCleaned = []; + let argsDereferenced = JSON.parse(JSON.stringify(args)); + argsDereferenced.forEach((attr) => { + argsCleaned.push(filterAttributes(JSON.parse(JSON.stringify(attr)), false)); + }); + if (auctionEnd[eventType] == undefined) { auctionEnd[eventType] = [] } + auctionEnd[eventType].push(argsCleaned); +} + +function addAuctionEnd(args) { + let eventType = AUCTION_END; + if (saveEvents[eventType] == undefined) { saveEvents[eventType] = [] } + saveEvents[eventType].push(args); + let argsCleaned = cleanAuctionEnd(JSON.parse(JSON.stringify(args))); + if (auctionEnd[eventType] == undefined) { auctionEnd[eventType] = [] } + auctionEnd[eventType].push(argsCleaned); +} + +function handleBidWon(args) { + args = enhanceMediaType(filterAttributes(JSON.parse(JSON.stringify(args)), true)); + let increment = args['cpm']; + if (typeof saveEvents['auctionEnd'] == 'object') { + saveEvents['auctionEnd'].forEach((auction) => { + if (auction['auctionId'] == args['auctionId'] && typeof auction['bidsReceived'] == 'object') { + auction['bidsReceived'].forEach((bid) => { + if (bid['transactionId'] == args['transactionId'] && bid['adId'] != args['adId']) { + if (args['cpm'] < bid['cpm']) { + increment = 0; + } else if (increment > args['cpm'] - bid['cpm']) { + increment = args['cpm'] - bid['cpm']; + } + } + }); + } + }); + } + args['cpmIncrement'] = increment; + if (typeof saveEvents.bidRequested == 'object' && saveEvents.bidRequested.length > 0 && saveEvents.bidRequested[0].gdprConsent) { args.gdpr = saveEvents.bidRequested[0].gdprConsent; } + ajax(endpoint + '.oxxion.io/analytics/bid_won', null, JSON.stringify(args), {method: 'POST', withCredentials: true}); +} + +function handleAuctionEnd() { + ajax(endpoint + '.oxxion.io/analytics/auctions', function (data) { + let list = JSON.parse(data); + if (Array.isArray(list) && typeof allEvents['bidResponse'] != 'undefined') { + let alreadyCalled = []; + allEvents['bidResponse'].forEach((bidResponse) => { + let tmpId = bidResponse['originalBidder'] + '_' + bidResponse['creativeId']; + if (list.includes(tmpId) && !alreadyCalled.includes(tmpId)) { + alreadyCalled.push(tmpId); + ajax(endpoint + '.oxxion.io/analytics/creatives', null, JSON.stringify(bidResponse), {method: 'POST', withCredentials: true}); + } + }); + } + allEvents = {}; + }, JSON.stringify(auctionEnd), {method: 'POST', withCredentials: true}); + auctionEnd = {}; +} + +let oxxionAnalytics = Object.assign(adapter({url, analyticsType}), { + track({ + eventType, + args + }) { + switch (eventType) { + case AUCTION_END: + addAuctionEnd(args); + handleAuctionEnd(); + break; + case BID_WON: + handleBidWon(args); + break; + case BID_RESPONSE: + addBidResponse(args); + break; + case BID_REQUESTED: + addBidRequested(args); + break; + case BID_TIMEOUT: + addTimeout(args); + break; + } + }}); + +// save the base class function +oxxionAnalytics.originEnableAnalytics = oxxionAnalytics.enableAnalytics; + +// override enableAnalytics so we can get access to the config passed in from the page +oxxionAnalytics.enableAnalytics = function (config) { + oxxionAnalytics.originEnableAnalytics(config); // call the base class function + initOptions = config.options; + if (initOptions.domain) { endpoint = 'https://' + initOptions.domain; } +}; + +adapterManager.registerAnalyticsAdapter({ + adapter: oxxionAnalytics, + code: 'oxxion' +}); + +export default oxxionAnalytics; diff --git a/modules/oxxionAnalyticsAdapter.md b/modules/oxxionAnalyticsAdapter.md new file mode 100644 index 00000000000..506f013eb37 --- /dev/null +++ b/modules/oxxionAnalyticsAdapter.md @@ -0,0 +1,33 @@ +# Overview +Module Name: oxxion Analytics Adapter + +Module Type: Analytics Adapter + +Maintainer: tech@oxxion.io + +# Oxxion Analytics Adapter + +Oxxion helps you to understand how your prebid stack performs. + +# Integration + +Add the oxxion analytics adapter module to your prebid configuration : +``` +pbjs.enableAnalytics( + ... + { + provider: 'oxxion', + options : { + domain: 'test.endpoint' + } + } + ... +) +``` + +# Parameters + +| Name | Type | Description | +|:-------------------------------|:---------|:------------------------------------------------------------------------------------------------------------| +| domain | String | This string identifies yourself in Oxxion's systems and is provided to you by your Oxxion representative. | + diff --git a/test/spec/modules/oxxionAnalyticsAdapter_spec.js b/test/spec/modules/oxxionAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..5f449eb882b --- /dev/null +++ b/test/spec/modules/oxxionAnalyticsAdapter_spec.js @@ -0,0 +1,324 @@ +import oxxionAnalytics from 'modules/oxxionAnalyticsAdapter.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('Oxxion Analytics', function () { + let timestamp = new Date() - 256; + let auctionId = '5018eb39-f900-4370-b71e-3bb5b48d324f'; + let timeout = 1500; + + let bidTimeout = [ + { + 'bidId': '5fe418f2d70364', + 'bidder': 'appnexusAst', + 'adUnitCode': 'tag_200124_banner', + 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b' + } + ]; + + const auctionEnd = { + 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', + 'timestamp': 1647424261187, + 'auctionEnd': 1647424261714, + 'auctionStatus': 'completed', + 'adUnits': [ + { + 'code': 'tag_200124_banner', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 600 + ] + ] + } + }, + 'bids': [ + { + 'bidder': 'appnexus', + 'params': { + 'placementId': 123456 + } + }, + { + 'bidder': 'appnexusAst', + 'params': { + 'placementId': 234567 + } + } + ], + 'sizes': [ + [ + 300, + 600 + ] + ], + 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40' + } + ], + 'adUnitCodes': [ + 'tag_200124_banner' + ], + 'bidderRequests': [ + { + 'bidderCode': 'appnexus', + 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', + 'bidderRequestId': '11dc6ff6378de7', + 'bids': [ + { + 'bidder': 'appnexus', + 'params': { + 'placementId': 123456 + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 600 + ] + ] + } + }, + 'adUnitCode': 'tag_200124_banner', + 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40', + 'sizes': [ + [ + 300, + 600 + ] + ], + 'bidId': '34a63e5d5378a3', + 'bidderRequestId': '11dc6ff6378de7', + 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + } + ], + 'auctionStart': 1647424261187, + 'timeout': 1000, + 'gdprConsent': { + 'consentString': 'CONSENT', + 'gdprApplies': true, + 'apiVersion': 2, + 'vendorData': 'a lot of borring stuff', + }, + 'start': 1647424261189 + }, + ], + 'noBids': [ + { + 'bidder': 'appnexusAst', + 'params': { + 'placementId': 10471298 + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 600 + ] + ] + } + }, + 'adUnitCode': 'tag_200124_banner', + 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40', + 'sizes': [ + [ + 300, + 600 + ] + ], + 'bidId': '5fe418f2d70364', + 'bidderRequestId': '4229a45ab8ea87', + 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + } + ], + 'bidsReceived': [ + { + 'bidderCode': 'appnexus', + 'width': 300, + 'height': 600, + 'statusMessage': 'Bid available', + 'adId': '7a4ced80f33d33', + 'requestId': '34a63e5d5378a3', + 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40', + 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', + 'mediaType': 'banner', + 'source': 'client', + 'cpm': 27.4276, + 'creativeId': '158534630', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 2000, + 'ad': 'some html', + 'meta': { + 'advertiserDomains': [ + 'example.com' + ] + }, + 'originalCpm': 25.02521, + 'originalCurrency': 'EUR', + 'responseTimestamp': 1647424261559, + 'requestTimestamp': 1647424261189, + 'bidder': 'appnexus', + 'adUnitCode': 'tag_200124_banner', + 'timeToRespond': 370, + 'pbLg': '5.00', + 'pbMg': '20.00', + 'pbHg': '20.00', + 'pbAg': '20.00', + 'pbDg': '20.00', + 'pbCg': '20.000000', + 'size': '300x600', + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_adid': '7a4ced80f33d33', + 'hb_pb': '20.000000', + 'hb_size': '300x600', + 'hb_source': 'client', + 'hb_format': 'banner', + 'hb_adomain': 'example.com' + } + } + ], + 'winningBids': [ + + ], + 'timeout': 1000 + }; + + let bidWon = { + 'bidderCode': 'appnexus', + 'width': 970, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '65d16ef039a97a', + 'requestId': '2bd3e8ff8a113f', + 'transactionId': '8b2a8629-d1ea-4bb1-aff0-e335b96dd002', + 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', + 'mediaType': 'banner', + 'source': 'client', + 'cpm': 27.4276, + 'creativeId': '158533702', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 2000, + 'ad': 'some html', + 'meta': { + 'advertiserDomains': [ + 'example.com' + ] + }, + 'originalCpm': 25.02521, + 'originalCurrency': 'EUR', + 'responseTimestamp': 1647424261558, + 'requestTimestamp': 1647424261189, + 'bidder': 'appnexus', + 'adUnitCode': 'tag_200123_banner', + 'timeToRespond': 369, + 'originalBidder': 'appnexus', + 'pbLg': '5.00', + 'pbMg': '20.00', + 'pbHg': '20.00', + 'pbAg': '20.00', + 'pbDg': '20.00', + 'pbCg': '20.000000', + 'size': '970x250', + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_adid': '65d16ef039a97a', + 'hb_pb': '20.000000', + 'hb_size': '970x250', + 'hb_source': 'client', + 'hb_format': 'banner', + 'hb_adomain': 'example.com' + }, + 'status': 'rendered', + 'params': [ + { + 'placementId': 123456 + } + ] + }; + + after(function () { + oxxionAnalytics.disableAnalytics(); + }); + + describe('main test flow', function () { + beforeEach(function () { + sinon.stub(events, 'getEvents').returns([]); + sinon.spy(oxxionAnalytics, 'track'); + }); + afterEach(function () { + events.getEvents.restore(); + oxxionAnalytics.disableAnalytics(); + oxxionAnalytics.track.restore(); + }); + + it('test auctionEnd', function () { + adapterManager.registerAnalyticsAdapter({ + code: 'oxxion', + adapter: oxxionAnalytics + }); + + adapterManager.enableAnalytics({ + provider: 'oxxion', + options: { + domain: 'test' + } + }); + + events.emit(constants.EVENTS.BID_REQUESTED, auctionEnd['bidderRequests'][0]); + events.emit(constants.EVENTS.BID_RESPONSE, auctionEnd['bidsReceived'][0]); + events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout); + events.emit(constants.EVENTS.AUCTION_END, auctionEnd); + expect(server.requests.length).to.equal(1); + let message = JSON.parse(server.requests[0].requestBody); + expect(message).to.have.property('auctionEnd').exist; + expect(message.auctionEnd).to.have.lengthOf(1); + expect(message.auctionEnd[0]).to.have.property('bidsReceived').and.to.have.lengthOf(1); + expect(message.auctionEnd[0].bidsReceived[0]).not.to.have.property('ad'); + expect(message.auctionEnd[0].bidsReceived[0]).to.have.property('meta'); + expect(message.auctionEnd[0].bidsReceived[0].meta).to.have.property('advertiserDomains'); + expect(message.auctionEnd[0].bidsReceived[0]).to.have.property('adId'); + expect(message.auctionEnd[0]).to.have.property('bidderRequests').and.to.have.lengthOf(1); + expect(message.auctionEnd[0].bidderRequests[0]).to.have.property('gdprConsent'); + expect(message.auctionEnd[0].bidderRequests[0].gdprConsent).not.to.have.property('vendorData'); + sinon.assert.callCount(oxxionAnalytics.track, 4); + }); + + it('test bidWon', function() { + adapterManager.registerAnalyticsAdapter({ + code: 'oxxion', + adapter: oxxionAnalytics + }); + + adapterManager.enableAnalytics({ + provider: 'oxxion', + options: { + domain: 'test' + } + }); + events.emit(constants.EVENTS.BID_WON, bidWon); + expect(server.requests.length).to.equal(1); + let message = JSON.parse(server.requests[0].requestBody); + expect(message).not.to.have.property('ad'); + expect(message).to.have.property('adId') + expect(message).to.have.property('cpmIncrement').and.to.equal(27.4276); + // sinon.assert.callCount(oxxionAnalytics.track, 1); + }); + }); +}); From e986edda7bb4649670fa5519d6a62e70824425a8 Mon Sep 17 00:00:00 2001 From: Chris Huie Date: Wed, 15 Feb 2023 13:47:43 -0700 Subject: [PATCH 364/367] Revert "Oxxion Analytics Adapter : initial adapter release (#9449)" (#9549) This reverts commit 23fe08397668f252c774213a3be14617264a4e8d. --- modules/oxxionAnalyticsAdapter.js | 210 ------------ modules/oxxionAnalyticsAdapter.md | 33 -- .../modules/oxxionAnalyticsAdapter_spec.js | 324 ------------------ 3 files changed, 567 deletions(-) delete mode 100644 modules/oxxionAnalyticsAdapter.js delete mode 100644 modules/oxxionAnalyticsAdapter.md delete mode 100644 test/spec/modules/oxxionAnalyticsAdapter_spec.js diff --git a/modules/oxxionAnalyticsAdapter.js b/modules/oxxionAnalyticsAdapter.js deleted file mode 100644 index 73160b5bebf..00000000000 --- a/modules/oxxionAnalyticsAdapter.js +++ /dev/null @@ -1,210 +0,0 @@ -import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; -import { ajax } from '../src/ajax.js'; - -const analyticsType = 'endpoint'; -const url = 'URL_TO_SERVER_ENDPOINT'; - -const { - EVENTS: { - AUCTION_END, - BID_WON, - BID_RESPONSE, - BID_REQUESTED, - BID_TIMEOUT, - } -} = CONSTANTS; - -let saveEvents = {} -let allEvents = {} -let auctionEnd = {} -let initOptions = {} -let endpoint = 'https://default' -let requestsAttributes = ['adUnitCode', 'auctionId', 'bidder', 'bidderCode', 'bidId', 'cpm', 'creativeId', 'currency', 'width', 'height', 'mediaType', 'netRevenue', 'originalCpm', 'originalCurrency', 'requestId', 'size', 'source', 'status', 'timeToRespond', 'transactionId', 'ttl', 'sizes', 'mediaTypes', 'src', 'params', 'userId', 'labelAny', 'bids', 'adId']; - -function getAdapterNameForAlias(aliasName) { - return adapterManager.aliasRegistry[aliasName] || aliasName; -} - -function filterAttributes(arg, removead) { - let response = {}; - if (typeof arg == 'object') { - if (typeof arg['bidderCode'] == 'string') { - response['originalBidder'] = getAdapterNameForAlias(arg['bidderCode']); - } else if (typeof arg['bidder'] == 'string') { - response['originalBidder'] = getAdapterNameForAlias(arg['bidder']); - } - if (!removead && typeof arg['ad'] != 'undefined') { - response['ad'] = arg['ad']; - } - if (typeof arg['gdprConsent'] != 'undefined') { - response['gdprConsent'] = {}; - if (typeof arg['gdprConsent']['consentString'] != 'undefined') { response['gdprConsent']['consentString'] = arg['gdprConsent']['consentString']; } - } - if (typeof arg['meta'] == 'object' && typeof arg['meta']['advertiserDomains'] != 'undefined') { - response['meta'] = {'advertiserDomains': arg['meta']['advertiserDomains']}; - } - requestsAttributes.forEach((attr) => { - if (typeof arg[attr] != 'undefined') { response[attr] = arg[attr]; } - }); - if (typeof response['creativeId'] == 'number') { response['creativeId'] = response['creativeId'].toString(); } - } - return response; -} - -function cleanAuctionEnd(args) { - let response = {}; - let filteredObj; - let objects = ['bidderRequests', 'bidsReceived', 'noBids', 'adUnits']; - objects.forEach((attr) => { - if (Array.isArray(args[attr])) { - response[attr] = []; - args[attr].forEach((obj) => { - filteredObj = filterAttributes(obj, true); - if (typeof obj['bids'] == 'object') { - filteredObj['bids'] = []; - obj['bids'].forEach((bid) => { - filteredObj['bids'].push(filterAttributes(bid, true)); - }); - } - response[attr].push(filteredObj); - }); - } - }); - return response; -} - -function cleanCreatives(args) { - return filterAttributes(args, false); -} - -function enhanceMediaType(arg) { - saveEvents['bidRequested'].forEach((bidRequested) => { - if (bidRequested['auctionId'] == arg['auctionId'] && Array.isArray(bidRequested['bids'])) { - bidRequested['bids'].forEach((bid) => { - if (bid['transactionId'] == arg['transactionId'] && bid['bidId'] == arg['requestId']) { arg['mediaTypes'] = bid['mediaTypes']; } - }); - } - }); - return arg; -} - -function addBidResponse(args) { - let eventType = BID_RESPONSE; - let argsCleaned = cleanCreatives(JSON.parse(JSON.stringify(args))); ; - if (allEvents[eventType] == undefined) { allEvents[eventType] = [] } - allEvents[eventType].push(argsCleaned); -} - -function addBidRequested(args) { - let eventType = BID_REQUESTED; - let argsCleaned = filterAttributes(args, true); - if (saveEvents[eventType] == undefined) { saveEvents[eventType] = [] } - saveEvents[eventType].push(argsCleaned); -} - -function addTimeout(args) { - let eventType = BID_TIMEOUT; - if (saveEvents[eventType] == undefined) { saveEvents[eventType] = [] } - saveEvents[eventType].push(args); - let argsCleaned = []; - let argsDereferenced = JSON.parse(JSON.stringify(args)); - argsDereferenced.forEach((attr) => { - argsCleaned.push(filterAttributes(JSON.parse(JSON.stringify(attr)), false)); - }); - if (auctionEnd[eventType] == undefined) { auctionEnd[eventType] = [] } - auctionEnd[eventType].push(argsCleaned); -} - -function addAuctionEnd(args) { - let eventType = AUCTION_END; - if (saveEvents[eventType] == undefined) { saveEvents[eventType] = [] } - saveEvents[eventType].push(args); - let argsCleaned = cleanAuctionEnd(JSON.parse(JSON.stringify(args))); - if (auctionEnd[eventType] == undefined) { auctionEnd[eventType] = [] } - auctionEnd[eventType].push(argsCleaned); -} - -function handleBidWon(args) { - args = enhanceMediaType(filterAttributes(JSON.parse(JSON.stringify(args)), true)); - let increment = args['cpm']; - if (typeof saveEvents['auctionEnd'] == 'object') { - saveEvents['auctionEnd'].forEach((auction) => { - if (auction['auctionId'] == args['auctionId'] && typeof auction['bidsReceived'] == 'object') { - auction['bidsReceived'].forEach((bid) => { - if (bid['transactionId'] == args['transactionId'] && bid['adId'] != args['adId']) { - if (args['cpm'] < bid['cpm']) { - increment = 0; - } else if (increment > args['cpm'] - bid['cpm']) { - increment = args['cpm'] - bid['cpm']; - } - } - }); - } - }); - } - args['cpmIncrement'] = increment; - if (typeof saveEvents.bidRequested == 'object' && saveEvents.bidRequested.length > 0 && saveEvents.bidRequested[0].gdprConsent) { args.gdpr = saveEvents.bidRequested[0].gdprConsent; } - ajax(endpoint + '.oxxion.io/analytics/bid_won', null, JSON.stringify(args), {method: 'POST', withCredentials: true}); -} - -function handleAuctionEnd() { - ajax(endpoint + '.oxxion.io/analytics/auctions', function (data) { - let list = JSON.parse(data); - if (Array.isArray(list) && typeof allEvents['bidResponse'] != 'undefined') { - let alreadyCalled = []; - allEvents['bidResponse'].forEach((bidResponse) => { - let tmpId = bidResponse['originalBidder'] + '_' + bidResponse['creativeId']; - if (list.includes(tmpId) && !alreadyCalled.includes(tmpId)) { - alreadyCalled.push(tmpId); - ajax(endpoint + '.oxxion.io/analytics/creatives', null, JSON.stringify(bidResponse), {method: 'POST', withCredentials: true}); - } - }); - } - allEvents = {}; - }, JSON.stringify(auctionEnd), {method: 'POST', withCredentials: true}); - auctionEnd = {}; -} - -let oxxionAnalytics = Object.assign(adapter({url, analyticsType}), { - track({ - eventType, - args - }) { - switch (eventType) { - case AUCTION_END: - addAuctionEnd(args); - handleAuctionEnd(); - break; - case BID_WON: - handleBidWon(args); - break; - case BID_RESPONSE: - addBidResponse(args); - break; - case BID_REQUESTED: - addBidRequested(args); - break; - case BID_TIMEOUT: - addTimeout(args); - break; - } - }}); - -// save the base class function -oxxionAnalytics.originEnableAnalytics = oxxionAnalytics.enableAnalytics; - -// override enableAnalytics so we can get access to the config passed in from the page -oxxionAnalytics.enableAnalytics = function (config) { - oxxionAnalytics.originEnableAnalytics(config); // call the base class function - initOptions = config.options; - if (initOptions.domain) { endpoint = 'https://' + initOptions.domain; } -}; - -adapterManager.registerAnalyticsAdapter({ - adapter: oxxionAnalytics, - code: 'oxxion' -}); - -export default oxxionAnalytics; diff --git a/modules/oxxionAnalyticsAdapter.md b/modules/oxxionAnalyticsAdapter.md deleted file mode 100644 index 506f013eb37..00000000000 --- a/modules/oxxionAnalyticsAdapter.md +++ /dev/null @@ -1,33 +0,0 @@ -# Overview -Module Name: oxxion Analytics Adapter - -Module Type: Analytics Adapter - -Maintainer: tech@oxxion.io - -# Oxxion Analytics Adapter - -Oxxion helps you to understand how your prebid stack performs. - -# Integration - -Add the oxxion analytics adapter module to your prebid configuration : -``` -pbjs.enableAnalytics( - ... - { - provider: 'oxxion', - options : { - domain: 'test.endpoint' - } - } - ... -) -``` - -# Parameters - -| Name | Type | Description | -|:-------------------------------|:---------|:------------------------------------------------------------------------------------------------------------| -| domain | String | This string identifies yourself in Oxxion's systems and is provided to you by your Oxxion representative. | - diff --git a/test/spec/modules/oxxionAnalyticsAdapter_spec.js b/test/spec/modules/oxxionAnalyticsAdapter_spec.js deleted file mode 100644 index 5f449eb882b..00000000000 --- a/test/spec/modules/oxxionAnalyticsAdapter_spec.js +++ /dev/null @@ -1,324 +0,0 @@ -import oxxionAnalytics from 'modules/oxxionAnalyticsAdapter.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('Oxxion Analytics', function () { - let timestamp = new Date() - 256; - let auctionId = '5018eb39-f900-4370-b71e-3bb5b48d324f'; - let timeout = 1500; - - let bidTimeout = [ - { - 'bidId': '5fe418f2d70364', - 'bidder': 'appnexusAst', - 'adUnitCode': 'tag_200124_banner', - 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b' - } - ]; - - const auctionEnd = { - 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', - 'timestamp': 1647424261187, - 'auctionEnd': 1647424261714, - 'auctionStatus': 'completed', - 'adUnits': [ - { - 'code': 'tag_200124_banner', - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 600 - ] - ] - } - }, - 'bids': [ - { - 'bidder': 'appnexus', - 'params': { - 'placementId': 123456 - } - }, - { - 'bidder': 'appnexusAst', - 'params': { - 'placementId': 234567 - } - } - ], - 'sizes': [ - [ - 300, - 600 - ] - ], - 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40' - } - ], - 'adUnitCodes': [ - 'tag_200124_banner' - ], - 'bidderRequests': [ - { - 'bidderCode': 'appnexus', - 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', - 'bidderRequestId': '11dc6ff6378de7', - 'bids': [ - { - 'bidder': 'appnexus', - 'params': { - 'placementId': 123456 - }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 600 - ] - ] - } - }, - 'adUnitCode': 'tag_200124_banner', - 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40', - 'sizes': [ - [ - 300, - 600 - ] - ], - 'bidId': '34a63e5d5378a3', - 'bidderRequestId': '11dc6ff6378de7', - 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - } - ], - 'auctionStart': 1647424261187, - 'timeout': 1000, - 'gdprConsent': { - 'consentString': 'CONSENT', - 'gdprApplies': true, - 'apiVersion': 2, - 'vendorData': 'a lot of borring stuff', - }, - 'start': 1647424261189 - }, - ], - 'noBids': [ - { - 'bidder': 'appnexusAst', - 'params': { - 'placementId': 10471298 - }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 600 - ] - ] - } - }, - 'adUnitCode': 'tag_200124_banner', - 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40', - 'sizes': [ - [ - 300, - 600 - ] - ], - 'bidId': '5fe418f2d70364', - 'bidderRequestId': '4229a45ab8ea87', - 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - } - ], - 'bidsReceived': [ - { - 'bidderCode': 'appnexus', - 'width': 300, - 'height': 600, - 'statusMessage': 'Bid available', - 'adId': '7a4ced80f33d33', - 'requestId': '34a63e5d5378a3', - 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40', - 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', - 'mediaType': 'banner', - 'source': 'client', - 'cpm': 27.4276, - 'creativeId': '158534630', - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 2000, - 'ad': 'some html', - 'meta': { - 'advertiserDomains': [ - 'example.com' - ] - }, - 'originalCpm': 25.02521, - 'originalCurrency': 'EUR', - 'responseTimestamp': 1647424261559, - 'requestTimestamp': 1647424261189, - 'bidder': 'appnexus', - 'adUnitCode': 'tag_200124_banner', - 'timeToRespond': 370, - 'pbLg': '5.00', - 'pbMg': '20.00', - 'pbHg': '20.00', - 'pbAg': '20.00', - 'pbDg': '20.00', - 'pbCg': '20.000000', - 'size': '300x600', - 'adserverTargeting': { - 'hb_bidder': 'appnexus', - 'hb_adid': '7a4ced80f33d33', - 'hb_pb': '20.000000', - 'hb_size': '300x600', - 'hb_source': 'client', - 'hb_format': 'banner', - 'hb_adomain': 'example.com' - } - } - ], - 'winningBids': [ - - ], - 'timeout': 1000 - }; - - let bidWon = { - 'bidderCode': 'appnexus', - 'width': 970, - 'height': 250, - 'statusMessage': 'Bid available', - 'adId': '65d16ef039a97a', - 'requestId': '2bd3e8ff8a113f', - 'transactionId': '8b2a8629-d1ea-4bb1-aff0-e335b96dd002', - 'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b', - 'mediaType': 'banner', - 'source': 'client', - 'cpm': 27.4276, - 'creativeId': '158533702', - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 2000, - 'ad': 'some html', - 'meta': { - 'advertiserDomains': [ - 'example.com' - ] - }, - 'originalCpm': 25.02521, - 'originalCurrency': 'EUR', - 'responseTimestamp': 1647424261558, - 'requestTimestamp': 1647424261189, - 'bidder': 'appnexus', - 'adUnitCode': 'tag_200123_banner', - 'timeToRespond': 369, - 'originalBidder': 'appnexus', - 'pbLg': '5.00', - 'pbMg': '20.00', - 'pbHg': '20.00', - 'pbAg': '20.00', - 'pbDg': '20.00', - 'pbCg': '20.000000', - 'size': '970x250', - 'adserverTargeting': { - 'hb_bidder': 'appnexus', - 'hb_adid': '65d16ef039a97a', - 'hb_pb': '20.000000', - 'hb_size': '970x250', - 'hb_source': 'client', - 'hb_format': 'banner', - 'hb_adomain': 'example.com' - }, - 'status': 'rendered', - 'params': [ - { - 'placementId': 123456 - } - ] - }; - - after(function () { - oxxionAnalytics.disableAnalytics(); - }); - - describe('main test flow', function () { - beforeEach(function () { - sinon.stub(events, 'getEvents').returns([]); - sinon.spy(oxxionAnalytics, 'track'); - }); - afterEach(function () { - events.getEvents.restore(); - oxxionAnalytics.disableAnalytics(); - oxxionAnalytics.track.restore(); - }); - - it('test auctionEnd', function () { - adapterManager.registerAnalyticsAdapter({ - code: 'oxxion', - adapter: oxxionAnalytics - }); - - adapterManager.enableAnalytics({ - provider: 'oxxion', - options: { - domain: 'test' - } - }); - - events.emit(constants.EVENTS.BID_REQUESTED, auctionEnd['bidderRequests'][0]); - events.emit(constants.EVENTS.BID_RESPONSE, auctionEnd['bidsReceived'][0]); - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout); - events.emit(constants.EVENTS.AUCTION_END, auctionEnd); - expect(server.requests.length).to.equal(1); - let message = JSON.parse(server.requests[0].requestBody); - expect(message).to.have.property('auctionEnd').exist; - expect(message.auctionEnd).to.have.lengthOf(1); - expect(message.auctionEnd[0]).to.have.property('bidsReceived').and.to.have.lengthOf(1); - expect(message.auctionEnd[0].bidsReceived[0]).not.to.have.property('ad'); - expect(message.auctionEnd[0].bidsReceived[0]).to.have.property('meta'); - expect(message.auctionEnd[0].bidsReceived[0].meta).to.have.property('advertiserDomains'); - expect(message.auctionEnd[0].bidsReceived[0]).to.have.property('adId'); - expect(message.auctionEnd[0]).to.have.property('bidderRequests').and.to.have.lengthOf(1); - expect(message.auctionEnd[0].bidderRequests[0]).to.have.property('gdprConsent'); - expect(message.auctionEnd[0].bidderRequests[0].gdprConsent).not.to.have.property('vendorData'); - sinon.assert.callCount(oxxionAnalytics.track, 4); - }); - - it('test bidWon', function() { - adapterManager.registerAnalyticsAdapter({ - code: 'oxxion', - adapter: oxxionAnalytics - }); - - adapterManager.enableAnalytics({ - provider: 'oxxion', - options: { - domain: 'test' - } - }); - events.emit(constants.EVENTS.BID_WON, bidWon); - expect(server.requests.length).to.equal(1); - let message = JSON.parse(server.requests[0].requestBody); - expect(message).not.to.have.property('ad'); - expect(message).to.have.property('adId') - expect(message).to.have.property('cpmIncrement').and.to.equal(27.4276); - // sinon.assert.callCount(oxxionAnalytics.track, 1); - }); - }); -}); From 06dd3e4fd933cebdc35120f286739b6f454325d1 Mon Sep 17 00:00:00 2001 From: Nayan Savla Date: Wed, 15 Feb 2023 12:57:57 -0800 Subject: [PATCH 365/367] Adding tmax to bid request. (#9548) Defaulting to 400 if none is supplied. --- modules/yieldmoBidAdapter.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js index 5a0f302ab34..b4b916a1048 100644 --- a/modules/yieldmoBidAdapter.js +++ b/modules/yieldmoBidAdapter.js @@ -382,6 +382,7 @@ function openRtbRequest(bidRequests, bidderRequest) { const schain = bidRequests[0].schain; let openRtbRequest = { id: bidRequests[0].bidderRequestId, + tmax: bidderRequest.timeout || 400, at: 1, imp: bidRequests.map(bidRequest => openRtbImpression(bidRequest)), site: openRtbSite(bidRequests[0], bidderRequest), From f066fea32b854b8963b29f028d8226e4a6c4d519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9onard=20Labat?= Date: Thu, 16 Feb 2023 16:03:50 +0100 Subject: [PATCH 366/367] Criteo Bid Adapter: Bumping PublisherTag version & Adapter version (#9554) --- modules/criteoBidAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 48fea78eeb4..f7ba82d3e06 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -11,7 +11,7 @@ import { getRefererInfo } from '../src/refererDetection.js'; import { hasPurpose1Consent } from '../src/utils/gpdr.js'; const GVLID = 91; -export const ADAPTER_VERSION = 34; +export const ADAPTER_VERSION = 35; const BIDDER_CODE = 'criteo'; const CDB_ENDPOINT = 'https://bidder.criteo.com/cdb'; const PROFILE_ID_INLINE = 207; @@ -27,7 +27,7 @@ const LOG_PREFIX = 'Criteo: '; Unminified source code can be found in the privately shared repo: https://github.com/Prebid-org/prebid-js-external-js-criteo/blob/master/dist/prod.js */ const FAST_BID_VERSION_PLACEHOLDER = '%FAST_BID_VERSION%'; -export const FAST_BID_VERSION_CURRENT = 134; +export const FAST_BID_VERSION_CURRENT = 135; const FAST_BID_VERSION_LATEST = 'latest'; const FAST_BID_VERSION_NONE = 'none'; const PUBLISHER_TAG_URL_TEMPLATE = 'https://static.criteo.net/js/ld/publishertag.prebid' + FAST_BID_VERSION_PLACEHOLDER + '.js'; From 9503f2a1d8b373f3ae694ac42e24cbee59b2aae6 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 17 Feb 2023 13:07:08 +0000 Subject: [PATCH 367/367] Prebid 7.37.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1c6a10e6ac6..674b6ca4576 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.37.0-pre", + "version": "7.37.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 95ba8e522d2..b47104c10cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "7.37.0-pre", + "version": "7.37.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": {