diff --git a/.travis.yml b/.travis.yml
index 917b119c05c..8addbe93b94 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1,21 @@
+sudo: required
+dist: trusty
+
language: node_js
node_js:
- "5.1"
+addons:
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+
before_install:
- npm install -g gulp
- - export CHROME_BIN=chromium-browser
+ - export CHROME_BIN=google-chrome
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
diff --git a/adapters.json b/adapters.json
index dd928df7c95..dc7796ea482 100644
--- a/adapters.json
+++ b/adapters.json
@@ -1,23 +1,27 @@
[
"aardvark",
"adblade",
+ "adbund",
"adbutler",
"adequant",
"adform",
"adkernel",
"admedia",
+ "vertamedia",
"aol",
"appnexus",
"appnexusAst",
"conversant",
"districtmDMX",
"fidelity",
- "getintent",
"gumgum",
"hiromedia",
"indexExchange",
"kruxlink",
+ "getintent",
"komoona",
+ "lifestreet",
+ "mantis",
"openx",
"piximedia",
"pubmatic",
@@ -30,7 +34,10 @@
"sonobi",
"sovrn",
"springserve",
+ "thoughtleadr",
+ "stickyadstv",
"triplelift",
+ "twenga",
"yieldbot",
"nginad",
"brightcom",
@@ -65,21 +72,41 @@
"appnexusAst": {
"supportedMediaTypes": ["video"]
}
+ }, {
+ "vertamedia": {
+ "supportedMediaTypes": ["video"]
+ }
+ },
+ {
+ "appnexus": {
+ "alias": "matomy"
+ }
},
{
"rubicon": {
- "alias": "rubiconLite"
+ "alias": "rubiconLite",
+ "supportedMediaTypes": ["video"]
}
},
{
"appnexus": {
"alias": "featureforward"
}
+ },
+ {
+ "appnexus": {
+ "alias": "oftmedia"
+ }
},
{
"adkernel": {
"alias": "headbidding"
}
+ },
+ {
+ "getintent": {
+ "supportedMediaTypes" : ["video"]
+ }
}
]
diff --git a/browsers.json b/browsers.json
index d220f9a0014..85bbc6b10b0 100644
--- a/browsers.json
+++ b/browsers.json
@@ -119,6 +119,14 @@
"device": null,
"os": "Windows"
},
+ "bs_chrome_56_mac_sierra": {
+ "base": "BrowserStack",
+ "os": "OS X",
+ "os_version": "Sierra",
+ "browser": "chrome",
+ "device": null,
+ "browser_version": "56.0"
+ },
"bs_safari_9.1_mac_elcapitan": {
"base": "BrowserStack",
"os_version": "El Capitan",
diff --git a/gulpHelpers.js b/gulpHelpers.js
index 342cd04dbb8..6091dc4c495 100644
--- a/gulpHelpers.js
+++ b/gulpHelpers.js
@@ -53,10 +53,10 @@ module.exports = {
createEnd2EndTestReport : function(targetDestinationDir) {
var browsers = require('./browsers.json');
- var env = ['default'];
+ var env = [];
var input = 'bs';
for(var key in browsers) {
- if(key.substring(0, input.length) === input) {
+ if(key.substring(0, input.length) === input && browsers[key].browser !== 'iphone') {
env.push(key);
}
}
diff --git a/gulpfile.js b/gulpfile.js
index 6d60a8809b8..d343068d165 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -21,6 +21,7 @@ var header = require('gulp-header');
var zip = require('gulp-zip');
var replace = require('gulp-replace');
var shell = require('gulp-shell');
+var optimizejs = require('gulp-optimize-js');
var CI_MODE = process.env.NODE_ENV === 'ci';
var prebid = require('./package.json');
@@ -73,6 +74,7 @@ gulp.task('webpack', function () {
.pipe(replace('$prebid.version$', prebid.version))
.pipe(uglify())
.pipe(header(banner, { prebid: prebid }))
+ .pipe(optimizejs())
.pipe(gulp.dest('build/dist'))
.pipe(connect.reload());
});
@@ -219,45 +221,46 @@ gulp.task('docs', ['clean-docs'], function () {
});
gulp.task('e2etest', function() {
- var cmd = '--env default';
+ var cmdQueue = [];
if(argv.browserstack) {
var browsers = require('./browsers.json');
- var env = [];
- var input = 'bs';
- for(var key in browsers) {
- if(key.substring(0, input.length) === input) {
- env.push(key);
- }
+ delete browsers['bs_ie_9_windows_7'];
+
+ var cmdStr = ' --config nightwatch.conf.js';
+ if (argv.group) {
+ cmdStr = cmdStr + ' --group ' + argv.group;
}
- cmd = '--env default,' + env.join(',');
- }
+ cmdStr = cmdStr + ' --reporter ./test/spec/e2e/custom-reporter/pbjs-html-reporter.js';
- if(argv.browserstack) {
- cmd = cmd + ' --config nightwatch.conf.js';
- } else {
- cmd = cmd + ' --config nightwatch.json';
- }
+ var startWith = 'bs';
- if (argv.group) {
- cmd = cmd + ' --group ' + argv.group;
+ Object.keys(browsers).filter(function(v){
+ return v.substring(0, startWith.length) === startWith && browsers[v].browser !== 'iphone';
+ }).map(function(v,i,arr) {
+ var newArr = (i%2 === 0) ? arr.slice(i,i+2) : null;
+ if(newArr) {
+ var cmd = 'nightwatch --env ' + newArr.join(',') + cmdStr;
+ cmdQueue.push(cmd);
+ }
+ });
}
- cmd = cmd + ' --reporter ./test/spec/e2e/custom-reporter/pbjs-html-reporter.js';
return gulp.src('')
- .pipe(shell('nightwatch ' + cmd));
+ .pipe(shell(cmdQueue.join(';')));
});
gulp.task('e2etest-report', function() {
+ var reportPort = 9010;
var targetDestinationDir = './e2etest-report';
helpers.createEnd2EndTestReport(targetDestinationDir);
connect.server({
- port: port,
+ port: reportPort,
root: './',
livereload: true
});
setTimeout(function() {
- opens('http://localhost:' + port + '/' + targetDestinationDir.slice(2) + '/results.html');
+ opens('http://localhost:' + reportPort + '/' + targetDestinationDir.slice(2) + '/results.html');
}, 5000);
});
diff --git a/integrationExamples/gpt/pbjs_example_gpt.html b/integrationExamples/gpt/pbjs_example_gpt.html
index f38d6dfc13b..19f4e6cc8a0 100644
--- a/integrationExamples/gpt/pbjs_example_gpt.html
+++ b/integrationExamples/gpt/pbjs_example_gpt.html
@@ -201,14 +201,14 @@
{
bidder: 'memeglobal',
params: {
- tagid: 007, // REQUIRED int. To get one, contact http://www.memeglobal.com
+ tagid: 007, // REQUIRED int. To get one, contact http://www.memeglobal.com
}
},
{
bidder: 'adblade',
params: {
partnerId: 42980,
- bidfloor: 0.01 // OPTIONAL float bid floor in $ CPM
+ bidfloor: 0.01 // OPTIONAL float bid floor in $ CPM
}
},
{
@@ -231,6 +231,13 @@
cur: 'EUR'
}
},
+ {
+ bidder: 'adbund',
+ params: {
+ sid: '110238', // REQUIRED int. To get one, sign up http://www.adbund.com
+ bidfloor: 0.036 // OPTIONAL float bid floor in $ CPM
+ }
+ },
{
bidder: 'smartyads',
params: {
@@ -326,22 +333,22 @@
}
},
{
- bidder: 'wideorbit',
+ bidder: 'memeglobal',
params: {
- pbId: 123, // REQUIRED Publisher Id,
- pId: 123456 // REQUIRED Placement Id
+ tagid: 007, // REQUIRED int. To get one, contact http://www.memeglobal.com
}
},
{
- bidder: 'memeglobal',
+ bidder: 'gumgum',
params: {
- tagid: 007, // REQUIRED int. To get one, contact http://www.memeglobal.com
+ inScreen: 'ggumtest' // REQUIRED str Tracking Id
}
},
{
- bidder: 'gumgum',
+ bidder: 'wideorbit',
params: {
- inScreen: 'ggumtest' // REQUIRED str Tracking Id
+ pbId: 123, // REQUIRED Publisher Id,
+ pId: 123456 // REQUIRED Placement Id
}
}
]
@@ -352,7 +359,7 @@
$$PREBID_GLOBAL$$.addAdUnits(adUnits);
//register a callback handler
- $$PREBID_GLOBAL$$.addCallback('adUnitBidsBack', function (adUnitCode) {
+ $$PREBID_GLOBAL$$.addCallback('adUnitBidsBack', function (adUnitCode) {
console.debug('ad unit bids back for:', adUnitCode);
});
diff --git a/integrationExamples/gpt/x-domain/creative.html b/integrationExamples/gpt/x-domain/creative.html
new file mode 100644
index 00000000000..68120e0e863
--- /dev/null
+++ b/integrationExamples/gpt/x-domain/creative.html
@@ -0,0 +1,72 @@
+
diff --git a/integrationExamples/gpt/x-domain/creative.js b/integrationExamples/gpt/x-domain/creative.js
deleted file mode 100644
index 787b67f928b..00000000000
--- a/integrationExamples/gpt/x-domain/creative.js
+++ /dev/null
@@ -1,56 +0,0 @@
-// this script can be returned by an ad server delivering a cross domain iframe, into which the
-// creative will be rendered, e.g. DFP delivering a SafeFrame
-
-// set these domains as fits your environment and ensure matching protocols
-// alternatively this can be passed as a macro on the query string of the ad server call, for
-// example `%%PUBLISHER_DOMAIN%%`.
-const publisherDomain = 'http://localhost:9999';
-const adServerDomain = 'http://tpc.googlesyndication.com';
-
-function renderAd(ev) {
- var key = ev.message ? 'message' : 'data';
- var adObject = {};
- try {
- adObject = JSON.parse(ev[key]);
- } catch (e) {
- return;
- }
-
- if (adObject.ad || adObject.adUrl) {
- var doc = window.document;
- var ad = adObject.ad;
- var url = adObject.adUrl;
- var width = adObject.width;
- var height = adObject.height;
-
- if (adObject.mediaType === 'video') {
- console.log('Error trying to write ad.');
- } else
-
- if (ad) {
- doc.write(ad);
- doc.close();
- } else if (url) {
- doc.write('');
- doc.close();
- } else {
- console.log('Error trying to write ad. No ad for bid response id: ' + id);
- }
- }
- }
-
-function requestAdFromPrebid() {
- var message = JSON.stringify({
- message: 'Prebid Request',
- adId: '%%PATTERN:hb_adid%%',
- adServerDomain
- });
- window.parent.postMessage(message, publisherDomain);
-}
-
-function listenAdFromPrebid() {
- window.addEventListener('message', renderAd, false);
-}
-
-listenAdFromPrebid();
-requestAdFromPrebid();
diff --git a/nightwatch.conf.js b/nightwatch.conf.js
index c0583fee4df..072114953fe 100644
--- a/nightwatch.conf.js
+++ b/nightwatch.conf.js
@@ -1,17 +1,35 @@
module.exports = (function(settings) {
var browsers = require('./browsers.json');
+ delete browsers['bs_ie_9_windows_7'];
+
for(var browser in browsers) {
+ if(browsers[browser].browser === 'iphone') continue;
+
var desiredCapabilities = {
"browserName": browsers[browser].browser,
"version": browsers[browser].browser_version,
- "platform": browsers[browser].os,
+ "platform": browsers[browser].os,
"os": browsers[browser].os,
- "os_version": browsers[browser].os_version,
- "browser": browsers[browser].browser,
- "browser_version": browsers[browser].browser_version,
+ "os_version": browsers[browser].os_version,
+ "browser": browsers[browser].browser,
+ "browser_version": browsers[browser].browser_version,
};
- settings.test_settings[browser] = {}
+ settings.test_settings[browser] = {
+ "silent": true,
+ "exclude":["custom-assertions","custom-commands","common","custom-reporter"],
+ "screenshots" : {
+ "enabled" : false,
+ "path" : ""
+ },
+ "javascriptEnabled": true,
+ "acceptSslCerts": true,
+ "browserstack.local": true,
+ "browserstack.debug": true,
+ "browserstack.selenium_version" : "2.53.0",
+ "browserstack.user": "${BROWSERSTACK_USERNAME}",
+ "browserstack.key": "${BROWSERSTACK_KEY}"
+ };
settings.test_settings[browser]['desiredCapabilities'] = desiredCapabilities;
}
return settings;
diff --git a/package.json b/package.json
index ec6ea57e99c..baa1291af12 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "prebid.js",
- "version": "0.18.0",
+ "version": "0.21.0-pre",
"description": "Header Bidding Management Library",
"main": "src/prebid.js",
"scripts": {
@@ -23,9 +23,9 @@
"devDependencies": {
"babel-core": "^6.5.2",
"babel-loader": "^6.2.3",
- "babel-plugin-transform-object-assign": "^6.8.0",
- "babel-plugin-transform-es3-property-literals": "^6.8.0",
"babel-plugin-transform-es3-member-expression-literals": "^6.8.0",
+ "babel-plugin-transform-es3-property-literals": "^6.8.0",
+ "babel-plugin-transform-object-assign": "^6.8.0",
"babel-preset-es2015": "^6.5.0",
"block-loader": "^2.1.0",
"chai": "^3.3.0",
@@ -46,6 +46,7 @@
"gulp-jshint": "^1.8.4",
"gulp-karma": "0.0.4",
"gulp-mocha": "^2.2.0",
+ "gulp-optimize-js": "^1.1.0",
"gulp-rename": "^1.2.0",
"gulp-replace": "^0.4.0",
"gulp-shell": "^0.5.2",
@@ -96,5 +97,8 @@
"webpack-stream": "^3.1.0",
"yargs": "^1.3.1"
},
- "dependencies": {}
+ "dependencies": {
+ "array-includes": "^3.0.2",
+ "array.prototype.find": "^2.0.3"
+ }
}
diff --git a/src/adaptermanager.js b/src/adaptermanager.js
index 4c8ae95b3f7..69d7df404f3 100644
--- a/src/adaptermanager.js
+++ b/src/adaptermanager.js
@@ -26,7 +26,7 @@ function getBids({bidderCode, requestId, bidderRequestId, adUnits}) {
}
sizes = sizeMapping;
}
- return Object.assign(bid, {
+ return Object.assign({}, bid, {
placementCode: adUnit.code,
mediaType: adUnit.mediaType,
sizes: sizes,
diff --git a/src/adapters/adbund.js b/src/adapters/adbund.js
new file mode 100644
index 00000000000..74809aa5e04
--- /dev/null
+++ b/src/adapters/adbund.js
@@ -0,0 +1,66 @@
+var CONSTANTS = require('../constants.json');
+var utils = require('../utils.js');
+var bidfactory = require('../bidfactory.js');
+var bidmanager = require('../bidmanager.js');
+var adloader = require('../adloader');
+
+var adBundAdapter = function adBundAdapter() {
+ var timezone = (new Date()).getTimezoneOffset();
+ var bidAPIs = [
+ 'http://us-east-engine.adbund.xyz/prebid/ad/get',
+ 'http://us-west-engine.adbund.xyz/prebid/ad/get'
+ ];
+ //Based on the time zone to select the interface to the server
+ var bidAPI = bidAPIs[timezone < 0 ? 0 : 1];
+
+ function _stringify(param) {
+ var result = [];
+ var key;
+ for (key in param) {
+ if (param.hasOwnProperty(key)) {
+ result.push(key + '=' + encodeURIComponent(param[key]));
+ }
+ }
+ return result.join('&');
+ }
+
+ function _createCallback(bid) {
+ return function (data) {
+ var response;
+ if (data && data.cpm) {
+ response = bidfactory.createBid(CONSTANTS.STATUS.GOOD);
+ response.bidderCode = 'adbund';
+ Object.assign(response, data);
+ } else {
+ response = bidfactory.createBid(CONSTANTS.STATUS.NO_BID);
+ response.bidderCode = 'adbund';
+ }
+ bidmanager.addBidResponse(bid.placementCode, response);
+ };
+ }
+
+ function _requestBids(bid) {
+ var info = {
+ referrer: utils.getTopWindowUrl(),
+ domain: utils.getTopWindowLocation().hostname,
+ ua: window.navigator.userAgent
+ };
+ var param = Object.assign({}, bid.params, info);
+ param.sizes = JSON.stringify(param.sizes || bid.sizes);
+ param.callback = '$$PREBID_GLOBAL$$.adbundResponse';
+ $$PREBID_GLOBAL$$.adbundResponse = _createCallback(bid);
+ adloader.loadScript(bidAPI + '?' + _stringify(param));
+ }
+
+ function _callBids(params) {
+ (params.bids || []).forEach(function (bid) {
+ _requestBids(bid);
+ });
+ }
+
+ return {
+ callBids: _callBids
+ };
+};
+
+module.exports = adBundAdapter;
\ No newline at end of file
diff --git a/src/adapters/adform.js b/src/adapters/adform.js
index 61b013315f8..705e91591f4 100644
--- a/src/adapters/adform.js
+++ b/src/adapters/adform.js
@@ -2,6 +2,7 @@ var utils = require('../utils.js');
var adloader = require('../adloader.js');
var bidmanager = require('../bidmanager.js');
var bidfactory = require('../bidfactory.js');
+var STATUSCODES = require('../constants.json').STATUS;
function AdformAdapter() {
@@ -70,7 +71,7 @@ function AdformAdapter() {
if (adItem && adItem.response === 'banner' &&
verifySize(adItem, bid.sizes)) {
- bidObject = bidfactory.createBid(1);
+ bidObject = bidfactory.createBid(STATUSCODES.GOOD, bid);
bidObject.bidderCode = bidder;
bidObject.cpm = adItem.win_bid;
bidObject.cur = adItem.win_cur;
@@ -80,7 +81,7 @@ function AdformAdapter() {
bidObject.dealId = adItem.deal_id;
bidmanager.addBidResponse(bid.placementCode, bidObject);
} else {
- bidObject = bidfactory.createBid(2);
+ bidObject = bidfactory.createBid(STATUSCODES.NO_BID, bid);
bidObject.bidderCode = bidder;
bidmanager.addBidResponse(bid.placementCode, bidObject);
}
diff --git a/src/adapters/adkernel.js b/src/adapters/adkernel.js
index a78416999c2..b3383f44e9b 100644
--- a/src/adapters/adkernel.js
+++ b/src/adapters/adkernel.js
@@ -26,6 +26,7 @@ const AdKernelAdapter = function AdKernelAdapter() {
const _dispatch = {};
const originalBids = {};
const site = createSite();
+ const syncedHostZones = {};
//translate adunit info into rtb impression dispatched by host/zone
this.addImp = function (bid) {
@@ -48,16 +49,34 @@ const AdKernelAdapter = function AdKernelAdapter() {
//save rtb impression for specified ad-network host and zone
_dispatch[host][zone].push(imp);
originalBids[bidId] = bid;
+ //perform user-sync
+ if (!(host in syncedHostZones)){
+ syncedHostZones[host] = [];
+ }
+ if (syncedHostZones[host].indexOf(zone) === -1) {
+ syncedHostZones[host].push(zone);
+ insertUserSync(host, zone);
+ }
};
+ function insertUserSync(host, zone) {
+ var iframe = utils.createInvisibleIframe();
+ iframe.src = `//${host}/user-sync?zone=${zone}`;
+ try {
+ document.body.appendChild(iframe);
+ } catch (error) {
+ utils.logError(error);
+ }
+ }
+
/**
* Main function to get bid requests
*/
this.dispatch = function (callback) {
utils._each(_dispatch, (zones, host) => {
- utils.logMessage('processing network ' + host);
+ utils.logMessage(`processing network ${host}`);
utils._each(zones, (impressions, zone) => {
- utils.logMessage('processing zone ' + zone);
+ utils.logMessage(`processing zone ${zone}`);
dispatchRtbRequest(host, zone, impressions, callback);
});
});
@@ -106,7 +125,7 @@ const AdKernelAdapter = function AdKernelAdapter() {
* Build ad-network specific endpoint url
*/
function buildEndpointUrl(host) {
- return window.location.protocol + '//' + host + '/rtbg';
+ return `${window.location.protocol}//${host}/rtbg`;
}
function buildRequestParams(zone, rtbReq) {
@@ -134,7 +153,7 @@ const AdKernelAdapter = function AdKernelAdapter() {
//process individual bids
utils._each(bids, (bid) => {
if (!validateBidParams(bid.params)) {
- utils.logError('Incorrect configuration for adkernel bidder:', bid.params);
+ utils.logError(`Incorrect configuration for adkernel bidder: ${bid.params}`);
bidmanager.addBidResponse(bid.placementCode, createEmptyBidObject(bid));
} else {
dispatcher.addImp(bid);
@@ -144,10 +163,10 @@ const AdKernelAdapter = function AdKernelAdapter() {
dispatcher.dispatch((bid, imp, bidResp) => {
let adUnitId = bid.placementCode;
if (bidResp) {
- utils.logMessage('got response for ' + adUnitId);
+ utils.logMessage(`got response for ${adUnitId}`);
bidmanager.addBidResponse(adUnitId, createBidObject(bidResp, bid, imp.banner.w, imp.banner.h));
} else {
- utils.logMessage('got empty response for ' + adUnitId);
+ utils.logMessage(`got empty response for ${adUnitId}`);
bidmanager.addBidResponse(adUnitId, createEmptyBidObject(bid));
}
});
diff --git a/src/adapters/appnexusAst.js b/src/adapters/appnexusAst.js
index 67cc393bba7..3258eeb7821 100644
--- a/src/adapters/appnexusAst.js
+++ b/src/adapters/appnexusAst.js
@@ -27,6 +27,7 @@ function AppnexusAstAdapter() {
baseAdapter.callBids = function(bidRequest) {
const bids = bidRequest.bids || [];
var member = 0;
+ let userObj;
const tags = bids
.filter(bid => valid(bid))
.map(bid => {
@@ -39,7 +40,7 @@ function AppnexusAstAdapter() {
tag.uuid = bid.bidId;
if(bid.params.placementId) {
tag.id = parseInt(bid.params.placementId, 10);
- } else {
+ } else {
tag.code = bid.params.invCode;
}
tag.allow_smaller_sizes = bid.params.allowSmallerSizes || false;
@@ -84,17 +85,17 @@ function AppnexusAstAdapter() {
}
if (bid.params.user) {
- tag.user = {};
+ userObj = {};
Object.keys(bid.params.user)
.filter(param => USER_PARAMS.includes(param))
- .forEach(param => tag.user[param] = bid.params.user[param]);
+ .forEach(param => userObj[param] = bid.params.user[param]);
}
return tag;
});
if (!utils.isEmpty(tags)) {
- const payloadJson = {tags: [...tags]};
+ const payloadJson = {tags: [...tags], user: userObj};
if (member > 0) {
payloadJson.member_id = member;
}
@@ -239,6 +240,7 @@ function AppnexusAstAdapter() {
bid.width = ad.rtb.video.player_width;
bid.height = ad.rtb.video.player_height;
bid.vastUrl = ad.rtb.video.asset_url;
+ bid.descriptionUrl = ad.rtb.video.asset_url;
} else {
bid.width = ad.rtb.banner.width;
bid.height = ad.rtb.banner.height;
diff --git a/src/adapters/brightcom.js b/src/adapters/brightcom.js
index 1040df3b990..9df4a872d47 100644
--- a/src/adapters/brightcom.js
+++ b/src/adapters/brightcom.js
@@ -112,7 +112,7 @@ var BrightcomAdapter = function BrightcomAdapter() {
// Define the bid request call URL
var bidRequestCallUrl = 'https://' + brightcomUrl +
- '?callback=' + brightcomCallbackFunction +
+ '?callback=' + encodeURIComponent(brightcomCallbackFunction) +
'&request=' + encodeURIComponent(JSON.stringify(brightcomBidReq));
// Add the call to get the bid
diff --git a/src/adapters/centro.js b/src/adapters/centro.js
index 7e7dc100c77..cad9dc7713b 100644
--- a/src/adapters/centro.js
+++ b/src/adapters/centro.js
@@ -39,12 +39,10 @@ var CentroAdapter = function CentroAdapter() {
utils.logError(LOG_ERROR_MESS.noUnit, bidderCode);
return;
}
- var query = ['s=' + bid.unit];//,'url=www.abc15.com','sz=320x50'];
+ var query = ['s=' + bid.unit, 'adapter=prebid'];//,'url=www.abc15.com','sz=320x50'];
var isDev = bid.unit.toString() === '28136';
- if (bid.page_url) {
- query.push('url=' + encodeURIComponent(bid.page_url));
- }
+ query.push('url=' + encodeURIComponent(bid.page_url || location.href));
//check size format
if (
size instanceof Array &&
@@ -55,7 +53,7 @@ var CentroAdapter = function CentroAdapter() {
query.push('sz=' + size.join('x'));
}
//make handler name for JSONP request
- var handlerName = handlerPrefix + bid.unit + size.join('x');
+ var handlerName = handlerPrefix + bid.unit + size.join('x') + encodeURIComponent(placementCode);
query.push('callback=' + handlerName);
//maybe is needed add some random parameter to disable cache
@@ -77,7 +75,7 @@ var CentroAdapter = function CentroAdapter() {
var bidObject;
var bid = resp && resp.bid || resp;
- if (bid && bid.adTag && bid.sectionID === unit) {
+ if (bid && bid.adTag && bid.sectionID && bid.sectionID.toString() === unit.toString()) {
bidObject = bidfactory.createBid(1);
bidObject.cpm = bid.value;
bidObject.ad = bid.adTag;
diff --git a/src/adapters/getintent.js b/src/adapters/getintent.js
index 1293d98f903..a98fab952ae 100644
--- a/src/adapters/getintent.js
+++ b/src/adapters/getintent.js
@@ -1,5 +1,7 @@
/*jshint loopfunc: true */
+import { STATUS } from 'src/constants';
+
var bidfactory = require('../bidfactory.js');
var bidmanager = require('../bidmanager.js');
var adloader = require('../adloader.js');
@@ -33,25 +35,34 @@ var GetIntentAdapter = function GetIntentAdapter() {
pid: bidRequest.params.pid, // required
tid: bidRequest.params.tid, // required
known: bidRequest.params.known || 1,
+ is_video: bidRequest.mediaType === 'video',
+ video: bidRequest.params.video || {},
size: bidRequest.sizes[0].join("x"),
};
addOptional(bidRequest.params, request, ['cur', 'floor']);
- window.gi_hb.makeBid(request, function(bidResponse) {
- if (bidResponse.no_bid === 1) {
- var nobid = bidfactory.createBid(2);
- nobid.bidderCode = bidRequest.bidder;
- bidmanager.addBidResponse(bidRequest.placementCode, nobid);
- } else {
- var size = bidResponse.size.split('x');
- var bid = bidfactory.createBid(1);
- bid.bidderCode = bidRequest.bidder;
- bid.cpm = bidResponse.cpm;
- bid.ad = bidResponse.ad;
- bid.width = size[0];
- bid.height = size[1];
- bidmanager.addBidResponse(bidRequest.placementCode, bid);
- }
- });
+ (function (r, br) {
+ window.gi_hb.makeBid(r, function(bidResponse) {
+ if (bidResponse.no_bid === 1) {
+ var nobid = bidfactory.createBid(STATUS.NO_BID);
+ nobid.bidderCode = br.bidder;
+ bidmanager.addBidResponse(br.placementCode, nobid);
+ } else {
+ var bid = bidfactory.createBid(STATUS.GOOD);
+ var size = bidResponse.size.split('x');
+ bid.bidderCode = br.bidder;
+ bid.cpm = bidResponse.cpm;
+ bid.width = size[0];
+ bid.height = size[1];
+ if (br.mediaType === 'video') {
+ bid.vastUrl = bidResponse.vast_url;
+ bid.descriptionUrl = bidResponse.vast_url;
+ } else {
+ bid.ad = bidResponse.ad;
+ }
+ bidmanager.addBidResponse(br.placementCode, bid);
+ }
+ });
+ })(request, bidRequest);
}
}
diff --git a/src/adapters/gumgum.js b/src/adapters/gumgum.js
index 7434444d570..d9a08d96b97 100644
--- a/src/adapters/gumgum.js
+++ b/src/adapters/gumgum.js
@@ -13,6 +13,9 @@ const GumgumAdapter = function GumgumAdapter() {
let topWindow;
let topScreen;
let pageViewId;
+ const requestCache = {};
+ const throttleTable = {};
+ const defaultThrottle = 3e4;
try {
topWindow = global.top;
@@ -21,6 +24,10 @@ const GumgumAdapter = function GumgumAdapter() {
return utils.logError(error);
}
+ function _getTimeStamp() {
+ return new Date().getTime();
+ }
+
function _callBids({ bids }) {
const browserParams = {
vw: topWindow.innerWidth,
@@ -36,6 +43,7 @@ const GumgumAdapter = function GumgumAdapter() {
, params = {}
, placementCode
} = bidRequest;
+ const timestamp = _getTimeStamp();
const trackingId = params.inScreen;
const nativeId = params.native;
const slotId = params.inSlot;
@@ -52,6 +60,21 @@ const GumgumAdapter = function GumgumAdapter() {
', please check your implementation.'
);
}
+
+ /* throttle based on the latest request for this product */
+ const productId = bid.pi;
+ const requestKey = productId + '|' + placementCode;
+ const throttle = throttleTable[productId];
+ const latestRequest = requestCache[requestKey];
+ if (latestRequest && throttle && (timestamp - latestRequest) < throttle) {
+ return utils.logWarn(
+ `[GumGum] The refreshes for "${ placementCode }" with the params ` +
+ `${ JSON.stringify(params) } should be at least ${ throttle / 1e3 }s apart.`
+ );
+ }
+ /* update the last request */
+ requestCache[requestKey] = timestamp;
+
/* tracking id is required for in-image and in-screen */
if (trackingId) bid.t = trackingId;
/* native ads require a native placement id */
@@ -75,26 +98,30 @@ const GumgumAdapter = function GumgumAdapter() {
});
}
- const _handleGumGumResponse = cachedBidRequest => bidResponse => {
- const ad = bidResponse && bidResponse.ad;
- const pag = bidResponse && bidResponse.pag;
+ const _handleGumGumResponse = cachedBidRequest => (bidResponse = {}) => {
+ const { pi: productId
+ } = cachedBidRequest;
+ const { ad = {}
+ , pag = {}
+ , thms: throttle
+ } = bidResponse;
/* cache the pageViewId */
if (pag && pag.pvid) pageViewId = pag.pvid;
- /* create the bid */
if (ad && ad.id) {
+ /* set the new throttle */
+ throttleTable[productId] = throttle || defaultThrottle;
+ /* create the bid */
const bid = bidfactory.createBid(1);
const { t: trackingId
- , pi: productId
- , placementCode
- } = cachedBidRequest;
- bidResponse.placementCode = placementCode;
+ } = pag;
+ bidResponse.request = cachedBidRequest;
const encodedResponse = encodeURIComponent(JSON.stringify(bidResponse));
const gumgumAdLoader = `
+ `;
+ }
+ return null;
+ }
+
+ return {
+ callBids: _callBids
+ };
+};
+
+module.exports = LifestreetAdapter;
\ No newline at end of file
diff --git a/src/adapters/mantis.js b/src/adapters/mantis.js
new file mode 100644
index 00000000000..5b4b17f1638
--- /dev/null
+++ b/src/adapters/mantis.js
@@ -0,0 +1,223 @@
+var bidfactory = require('../bidfactory.js');
+var bidmanager = require('../bidmanager.js');
+var adloader = require('../adloader');
+var constants = require('../constants.json');
+
+module.exports = function () {
+ function inIframe() {
+ try {
+ return window.self !== window.top && !window.mantis_link;
+ } catch (e) {
+ return true;
+ }
+ }
+
+ function isDesktop(ignoreTouch) {
+ var scope = function (win) {
+ var width = win.innerWidth || win.document.documentElement.clientWidth || win.document.body.clientWidth;
+ var supportsTouch = !ignoreTouch && ('ontouchstart' in window || navigator.msMaxTouchPoints);
+
+ return !supportsTouch && (!width || width >= (window.mantis_breakpoint || 768));
+ };
+
+ if (inIframe()) {
+ try {
+ return scope(window.top);
+ } catch (ex) {
+ }
+ }
+
+ return scope(window);
+ }
+
+ function isSendable(val) {
+ if (val === null || val === undefined) {
+ return false;
+ }
+
+ if (typeof val === 'string') {
+ return !(!val || /^\s*$/.test(val));
+ }
+
+ if (typeof val === 'number') {
+ return !isNaN(val);
+ }
+
+ return true;
+ }
+
+ function isObject(value) {
+ return Object.prototype.toString.call(value) === '[object Object]';
+ }
+
+ function isAmp() {
+ return typeof window.context === "object" && (window.context.tagName === "AMP-AD" || window.context.tagName === "AMP-EMBED");
+ }
+
+ function isSecure() {
+ return document.location.protocol === "https:";
+ }
+
+ function isArray(value) {
+ return Object.prototype.toString.call(value) === '[object Array]';
+ }
+
+ function jsonp(callback) {
+ if (!window.mantis_jsonp) {
+ window.mantis_jsonp = [];
+ }
+
+ window.mantis_jsonp.push(callback);
+
+ return 'mantis_jsonp[' + (window.mantis_jsonp.length - 1) + ']';
+ }
+
+ function jsonToQuery(data, chain, form) {
+ if (!data) {
+ return null;
+ }
+
+ var parts = form || [];
+
+ for (var key in data) {
+ var queryKey = key;
+
+ if (chain) {
+ queryKey = chain + '[' + key + ']';
+ }
+
+ var val = data[key];
+
+ if (isArray(val)) {
+ for (var index = 0; index < val.length; index++) {
+ var akey = queryKey + '[' + index + ']';
+ var aval = val[index];
+
+ if (isObject(aval)) {
+ jsonToQuery(aval, akey, parts);
+ } else if (isSendable(aval)) {
+ parts.push(akey + '=' + encodeURIComponent(aval));
+ }
+ }
+ } else if (isObject(val)) {
+ jsonToQuery(val, queryKey, parts);
+ } else if (isSendable(val)) {
+ parts.push(queryKey + '=' + encodeURIComponent(val));
+ }
+ }
+
+ return parts.join('&');
+ }
+
+
+ function buildMantisUrl(path, data, domain) {
+ var params = {
+ referrer: document.referrer,
+ tz: new Date().getTimezoneOffset(),
+ buster: new Date().getTime(),
+ secure: isSecure()
+ };
+
+ if (!inIframe() || isAmp()) {
+ params.mobile = !isAmp() && isDesktop(true) ? 'false' : 'true';
+ }
+
+ if (window.mantis_uuid) {
+ params.uuid = window.mantis_uuid;
+ } else if (window.localStorage) {
+ var localUuid = window.localStorage.getItem('mantis:uuid');
+
+ if (localUuid) {
+ params.uuid = localUuid;
+ }
+ }
+
+ if (!inIframe()) {
+ try {
+ params.title = window.top.document.title;
+ params.referrer = window.top.document.referrer;
+ params.url = window.top.document.location.href;
+ } catch (ex) {
+
+ }
+ } else {
+ params.iframe = true;
+ }
+
+ if (isAmp()) {
+ if (!params.url && window.context.canonicalUrl) {
+ params.url = window.context.canonicalUrl;
+ }
+
+ if (!params.url && window.context.location) {
+ params.url = window.context.location.href;
+ }
+
+ if (!params.referrer && window.context.referrer) {
+ params.referrer = window.context.referrer;
+ }
+ }
+
+ Object.keys(data || {}).forEach(function (key) {
+ params[key] = data[key];
+ });
+
+ var query = jsonToQuery(params);
+
+ return (window.mantis_domain === undefined ? domain || 'https://mantodea.mantisadnetwork.com' : window.mantis_domain) + path + '?' + query;
+ }
+
+ var Prebid = function (bidfactory, bidmanager, adloader, constants) {
+ return {
+ callBids: function (params) {
+ var property = null;
+
+ params.bids.some(function (bid) {
+ if (bid.params.property) {
+ property = bid.params.property;
+
+ return true;
+ }
+ });
+
+ var url = {
+ jsonp: jsonp(function (resp) {
+ params.bids.forEach(function (bid) {
+ var ad = resp.ads[bid.bidId];
+
+ var bidObject;
+
+ if (ad) {
+ bidObject = bidfactory.createBid(constants.STATUS.GOOD);
+ bidObject.bidderCode = 'mantis';
+ bidObject.cpm = ad.cpm;
+ bidObject.ad = ad.html;
+ bidObject.width = ad.width;
+ bidObject.height = ad.height;
+ } else {
+ bidObject = bidfactory.createBid(constants.STATUS.NO_BID);
+ bidObject.bidderCode = 'mantis';
+ }
+
+ bidmanager.addBidResponse(bid.placementCode, bidObject);
+ });
+ }),
+ property: property,
+ bids: params.bids.map(function (bid) {
+ return {
+ bidId: bid.bidId,
+ sizes: bid.sizes.map(function (size) {
+ return {width: size[0], height: size[1]};
+ })
+ };
+ }),
+ version: 1
+ };
+
+ adloader.loadScript(buildMantisUrl('/website/prebid', url));
+ }
+ };
+ };
+
+ return new Prebid(bidfactory, bidmanager, adloader, constants);
+};
\ No newline at end of file
diff --git a/src/adapters/memeglobal.js b/src/adapters/memeglobal.js
index 82b6ad4cf11..9eb7f297d97 100644
--- a/src/adapters/memeglobal.js
+++ b/src/adapters/memeglobal.js
@@ -106,7 +106,7 @@ var MemeGlobalAdapter = function MemeGlobalAdapter() {
bidResponse.placementCode = placementCode;
bidResponse.size = bidRequested.sizes;
var responseAd = bidderBid.adm;
- var responseNurl = '
';
+ var responseNurl = '
';
bidResponse.creative_id = bidderBid.id;
bidResponse.bidderCode = bidderName;
bidResponse.cpm = responseCPM;
diff --git a/src/adapters/openx.js b/src/adapters/openx.js
index fe889cd9d78..21c5ba3476d 100644
--- a/src/adapters/openx.js
+++ b/src/adapters/openx.js
@@ -43,18 +43,16 @@ const OpenxAdapter = function OpenxAdapter() {
};
// no fill :(
- if (!auid) {
+ if (!auid || !adUnit.pub_rev) {
addBidResponse(null, bid);
continue;
}
adUnit.used = true;
- if (adUnit.pub_rev) {
- beaconParams.br = beaconParams.bt < beaconParams.bd ? 't' : 'p';
- beaconParams.bp = adUnit.pub_rev;
- beaconParams.ts = adUnit.ts;
- addBidResponse(adUnit, bid);
- }
+ beaconParams.br = beaconParams.bt < beaconParams.bd ? 't' : 'p';
+ beaconParams.bp = adUnit.pub_rev;
+ beaconParams.ts = adUnit.ts;
+ addBidResponse(adUnit, bid);
buildBoPixel(adUnit.creative[0], beaconParams);
}
};
diff --git a/src/adapters/pubmatic.js b/src/adapters/pubmatic.js
index 434097e98c5..c039c4eac7a 100644
--- a/src/adapters/pubmatic.js
+++ b/src/adapters/pubmatic.js
@@ -118,7 +118,7 @@ var PubmaticAdapter = function PubmaticAdapter() {
adResponse.adSlot = bid.adSlot;
adResponse.cpm = Number(adUnitInfo.bid);
adResponse.ad = unescape(adUnit.creative_tag); // jshint ignore:line
- adResponse.ad += utils.createTrackPixelHtml(decodeURIComponent(adUnit.tracking_url));
+ adResponse.ad += utils.createTrackPixelIframeHtml(decodeURIComponent(adUnit.tracking_url));
adResponse.width = dimensions[0];
adResponse.height = dimensions[1];
adResponse.dealId = adUnitInfo.wdeal;
diff --git a/src/adapters/rhythmone.js b/src/adapters/rhythmone.js
index b86d3aee4d3..77ab3e4cd13 100644
--- a/src/adapters/rhythmone.js
+++ b/src/adapters/rhythmone.js
@@ -261,6 +261,9 @@ module.exports = function(bidManager, global, loader){
bidParams = getBidParameters(params.bids);
debug = (bidParams !== null && bidParams.debug === true);
+
+ auctionEnded = false;
+ requestCompleted = false;
track(debug, 'hb', 'callBids');
@@ -337,4 +340,4 @@ module.exports = function(bidManager, global, loader){
logToConsole("version: "+version);
};
-};
\ No newline at end of file
+};
diff --git a/src/adapters/rubicon.js b/src/adapters/rubicon.js
index 8baccc2dd87..d9d884aa0dc 100644
--- a/src/adapters/rubicon.js
+++ b/src/adapters/rubicon.js
@@ -7,6 +7,17 @@ import { STATUS } from 'src/constants';
const RUBICON_BIDDER_CODE = 'rubicon';
+// use deferred function call since version isn't defined yet at this point
+function getIntegration() {
+ return 'pbjs_lite_' + $$PREBID_GLOBAL$$.version;
+}
+
+// use protocol relative urls for http or https
+const FASTLANE_ENDPOINT = '//fastlane.rubiconproject.com/a/api/fastlane.json';
+const VIDEO_ENDPOINT = '//optimized-by-adv.rubiconproject.com/v1/auction/video';
+
+const TIMEOUT_BUFFER = 500;
+
var sizeMap = {
1:'468x60',
2:'728x90',
@@ -49,7 +60,12 @@ function RubiconAdapter() {
bids.forEach(bid => {
try {
- ajax(buildOptimizedCall(bid), bidCallback, undefined, {withCredentials: true});
+ // Video endpoint only accepts POST calls
+ if (bid.mediaType === 'video') {
+ ajax(VIDEO_ENDPOINT, bidCallback, buildVideoRequestPayload(bid, bidderRequest), {withCredentials: true});
+ } else {
+ ajax(buildOptimizedCall(bid), bidCallback, undefined, {withCredentials: true});
+ }
} catch(err) {
utils.logError('Error sending rubicon request for placement code ' + bid.placementCode, null, err);
addErrorBid();
@@ -77,6 +93,82 @@ function RubiconAdapter() {
});
}
+ function _getScreenResolution() {
+ return [window.screen.width, window.screen.height].join('x');
+ }
+
+ function buildVideoRequestPayload(bid, bidderRequest) {
+ bid.startTime = new Date().getTime();
+
+ let params = bid.params;
+
+ if(!params || typeof params.video !== 'object') {
+ throw 'Invalid Video Bid';
+ }
+
+ let size;
+ if(params.video.playerWidth && params.video.playerHeight) {
+ size = [
+ params.video.playerWidth,
+ params.video.playerHeight
+ ];
+ } else if(
+ Array.isArray(bid.sizes) && bid.sizes.length > 0 &&
+ Array.isArray(bid.sizes[0]) && bid.sizes[0].length > 1
+ ) {
+ size = bid.sizes[0];
+ } else {
+ throw "Invalid Video Bid - No size provided";
+ }
+
+ let postData = {
+ page_url: !params.referrer ? utils.getTopWindowUrl() : params.referrer,
+ resolution: _getScreenResolution(),
+ account_id: params.accountId,
+ integration: getIntegration(),
+ timeout: bidderRequest.timeout - (Date.now() - bidderRequest.auctionStart + TIMEOUT_BUFFER),
+ stash_creatives: true,
+ ae_pass_through_parameters: params.video.aeParams,
+ slots: []
+ };
+
+ // Define the slot object
+ let slotData = {
+ site_id: params.siteId,
+ zone_id: params.zoneId,
+ position: params.position || 'btf',
+ floor: 0.01,
+ element_id: bid.placementCode,
+ name: bid.placementCode,
+ language: params.video.language,
+ width: size[0],
+ height: size[1]
+ };
+
+ // check and add inventory, keywords, visitor and size_id data
+ if(params.video.size_id) {
+ slotData.size_id = params.video.size_id;
+ } else {
+ throw "Invalid Video Bid - Invalid Ad Type!";
+ }
+
+ if(params.inventory && typeof params.inventory === 'object') {
+ slotData.inventory = params.inventory;
+ }
+
+ if(params.keywords && Array.isArray(params.keywords)) {
+ slotData.keywords = params.keywords;
+ }
+
+ if(params.visitor && typeof params.visitor === 'object') {
+ slotData.visitor = params.visitor;
+ }
+
+ postData.slots.push(slotData);
+
+ return(JSON.stringify(postData));
+ }
+
function buildOptimizedCall(bid) {
bid.startTime = new Date().getTime();
@@ -85,6 +177,7 @@ function RubiconAdapter() {
siteId,
zoneId,
position,
+ floor,
keywords,
visitor,
inventory,
@@ -93,6 +186,7 @@ function RubiconAdapter() {
} = bid.params;
// defaults
+ floor = (floor = parseFloat(floor)) > 0.01 ? floor : 0.01;
position = position || 'btf';
// use rubicon sizes if provided, otherwise adUnit.sizes
@@ -112,9 +206,9 @@ function RubiconAdapter() {
'size_id', parsedSizes[0],
'alt_size_ids', parsedSizes.slice(1).join(',') || undefined,
'p_pos', position,
- 'rp_floor', '0.01',
- 'tk_flint', 'pbjs.lite',
- 'p_screen_res', window.screen.width +'x'+ window.screen.height,
+ 'rp_floor', floor,
+ 'tk_flint', getIntegration(),
+ 'p_screen_res', _getScreenResolution(),
'kw', keywords,
'tk_user_key', userId
];
@@ -136,7 +230,7 @@ function RubiconAdapter() {
(memo, curr, index) =>
index % 2 === 0 && queryString[index + 1] !== undefined ?
memo + curr + '=' + encodeURIComponent(queryString[index + 1]) + '&' : memo,
- '//fastlane.rubiconproject.com/a/api/fastlane.json?' // use protocol relative link for http or https
+ FASTLANE_ENDPOINT + '?'
).slice(0, -1); // remove trailing &
}
@@ -151,23 +245,29 @@ function RubiconAdapter() {