vendor: 19 bytes, lines 1-2
1(() => { 2 // src/s
2ciads/utils/log.js 3 var noop = () => { 4 }; 5 var log = window.location.search.match(/debug=ads/) ? console.debug.bind(window.console, "[sciads]") : noop; 6 7
7// src/sciads/perf.js 8 var PERF_KEYS = { 9 libLoaded: "ads:library_loaded", 10 consent: "ads:consent_determined", 11 measureConsent: "ads:time_to_consent", 12 page: "ads:page_requested", 13 gptLoaded: "ads:gpt_loaded", 14 gptQueue: "ads:gpt_queue_init", 15 firstCall: "ads:first_call", 16 firstLoaded: "ads:first_loaded", 17 measureFirstCall: "ads:time_to_first_call", 18 measureFirstLoad: "ads:time_to_first_ad" 19 }; 20 function logMeasurement(key, message) { 21 let t = Math.round(performance.getEntriesByName(key)[0].duration); 22 log(`${message}: ${t}ms`); 23 } 24 function trackPerformanceFirstCall(gptAd) { 25 if (!performance.getEntriesByName(PERF_KEYS.firstCall).length) { 26 performance.mark(PERF_KEYS.firstCall); 27 performance.measure(PERF_KEYS.measureFirstCall, PERF_KEYS.page, PERF_KEYS.firstCall); 28 } 29 } 30 function trackPerformanceFirstLoad(gptAd) { 31 if (!performance.getEntriesByName(PERF_KEYS.firstLoaded).length) { 32 performance.mark(PERF_KEYS.firstLoaded); 33 performance.measure(PERF_KEYS.measureFirstLoad, PERF_KEYS.page, PERF_KEYS.firstLoaded); 34 logMeasurement(PERF_KEYS.measureFirstLoad, "Time to first ad"); 35 let t = Math.round(performance.getEntriesByName(PERF_KEYS.measureFirstLoad)[0].duration); 36 } 37 } 38 39
39// src/sciads/consent.js 40 var optOuts = { 41 ads: false 42 }; 43 function isOptedOut() { 44 return optOuts.ads; 45 } 46 window.consentQueue = window.consentQueue || []; 47 function getConsent() { 48 return new Promise((resolve) => { 49 if (navigator.globalPrivacyControl) { 50 optOuts.ads = true; 51 resolve(); 52 return; 53 } 54 window.consentQueue.push(() => { 55 const consent = window.Osano?.cm?.getConsent() || {}; 56 const hasMarketingConsent = consent.MARKETING === "ACCEPT"; 57 const optedOut = consent.OPT_OUT === "ACCEPT"; 58 optOuts.ads = !hasMarketingConsent || optedOut; 59 resolve(); 60 }); 61 }).then(() => { 62 performance.mark(PERF_KEYS.consent); 63 performance.measure(PERF_KEYS.measureConsent, PERF_KEYS.libLoaded, PERF_KEYS.consent); 64 logMeasurement(PERF_KEYS.measureConsent, "Time to determine consent status"); 65 if (isOptedOut()) { 66 log(`Ads: user opted out. Showing nonpersonalized ads only.`); 67 } 68 }); 69 } 70 71
71// src/sciads/constants.js 72 var IAB_SIZES = ["320x50", "300x250", "300x600", "728x90", "970x250"]; 73 var PREMIUM_SIZES = ["320x450", "970x350"]; 74 75
75// src/sciads/utils/cookies.js 76 function readCookie(name) { 77 var nameEQ = name + "="; 78 var ca = document.cookie.split(";"); 79 for (var i = 0; i < ca.length; i++) { 80 var c = ca[i]; 81 while (c.charAt(0) == " ") c = c.substring(1, c.length); 82 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); 83 } 84 return null; 85 } 86 87
vendor: 1,685 bytes, lines 87-143
87// node_modules/jwt-decode/build/esm/index.js 88 var InvalidTokenError = class extends Error { 89 }; 90 InvalidTokenError.prototype.name = "InvalidTokenError"; 91 function b64DecodeUnicode(str) { 92 return decodeURIComponent(atob(str).replace(/(.)/g, (m, p) => { 93 let code = p.charCodeAt(0).toString(16).toUpperCase(); 94 if (code.length < 2) { 95 code = "0" + code; 96 } 97 return "%" + code; 98 })); 99 } 100 function base64UrlDecode(str) { 101 let output = str.replace(/-/g, "+").replace(/_/g, "/"); 102 switch (output.length % 4) { 103 case 0: 104 break; 105 case 2: 106 output += "=="; 107 break; 108 case 3: 109 output += "="; 110 break; 111 default: 112 throw new Error("base64 string is not of the correct length"); 113 } 114 try { 115 return b64DecodeUnicode(output); 116 } catch (err) { 117 return atob(output); 118 } 119 } 120 function jwtDecode(token, options) { 121 if (typeof token !== "string") { 122 throw new InvalidTokenError("Invalid token specified: must be a string"); 123 } 124 options || (options = {}); 125 const pos = options.header === true ? 0 : 1; 126 const part = token.split(".")[pos]; 127 if (typeof part !== "string") { 128 throw new InvalidTokenError(`Invalid token specified: missing part #${pos + 1}`); 129 } 130 let decoded; 131 try { 132 decoded = base64UrlDecode(part); 133 } catch (e) { 134 throw new InvalidTokenError(`Invalid token specified: invalid base64 for part #${pos + 1} (${e.message})`); 135 } 136 try { 137 return JSON.parse(decoded); 138 } catch (e) { 139 throw new InvalidTokenError(`Invalid token specified: invalid json for part #${pos + 1} (${e.message})`); 140 } 141 } 142 143
143// src/sciads/utils/user.js 144 function getUserData() { 145 const auth0Cookie = document.cookie.split(";").map((c) => c.trim()).filter((c) => c.startsWith("sa_user."))[0]; 146 if (!auth0Cookie) { 147 return null; 148 } 149 const cookieValue = auth0Cookie.split("=")[1]; 150 const data = jwtDecode(cookieValue); 151 return data; 152 } 153 154
154// src/sciads/utils/geo.js 155 var geoData; 156 async function getGeo() { 157 if (geoData) return geoData; 158 try { 159 geoData = await fetch("https://www.scientificamerican.com/api/geo/", { 160 headers: { Accept: "application/json" }, 161 credentials: "omit" 162 }).then((res) => res.json()); 163 } catch (e) { 164 console.warn("[sciads] [geo] Failed to fetch", e); 165 } 166 return geoData; 167 } 168 var gdprCountries = [ 169 // GDPR/EU 170 "AUT", 171 "BEL", 172 "BGR", 173 "HRV", 174 "CYP", 175 "CZE", 176 "DNK", 177 "EST", 178 "FIN", 179 "FRA", 180 "DEU", 181 "GRC", 182 "HUN", 183 "IRL", 184 "ITA", 185 "LVA", 186 "LTU", 187 "LUX", 188 "MLT", 189 "NLD", 190 "POL", 191 "PRT", 192 "ROU", 193 "SVK", 194 "SVN", 195 "ESP", 196 "SWE", 197 "CHE", 198 // Switzerland 199 "UKR", 200 // Ukraine 201 "GBR" 202 // United Kingdom 203 ]; 204 205
205// src/sciads/plugins/ppid.js 206 var ppid; 207 function getPublisherProvidedId() { 208 return ppid; 209 } 210 async function hash(message) { 211 if (!message) return; 212 if (window.location.protocol !== "https:") { 213 log("[ads] insecure context, will not pass PPID because crypto hashing is unavailable"); 214 return; 215 } 216 const encoder = new TextEncoder(); 217 const data = encoder.encode(message); 218 const hashBuffer = await window.crypto.subtle.digest("SHA-256", data); 219 const hashArray = Array.from(new Uint8Array(hashBuffer)); 220 const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join(""); 221 return hashHex; 222 } 223 async function publisherProvidedId() { 224 const geo = await getGeo(); 225 if (geo?.country !== "USA") { 226 return; 227 } 228 if (isOptedOut()) { 229 return; 230 } 231 const user = getUserData(); 232 const id = user?.["https://sciam.com/user_id"]; 233 if (!id) return null; 234 ppid = await hash(id); 235 return ppid; 236 } 237 238
238// src/sciads/gpt.js 239 window.googletag = window.googletag || {}; 240 window.googletag.cmd = window.googletag.cmd || []; 241 var gptQueue = []; 242 gptQueue.push = (fn) => { 243 window.googletag.cmd.push(() => { 244 try { 245 fn(); 246 } catch (e) { 247 console.log(e); 248 } 249 }); 250 }; 251 function parseSize(sizeStr) { 252 if (sizeStr === "fluid") { 253 return sizeStr; 254 } 255 let size = sizeStr.split("x").map((num) => parseInt(num, 10)); 256 return size; 257 } 258 function defineSlot(gptAd) { 259 const slot = googletag.defineSlot(gptAd.unitpath, gptAd.getSizesForBreakpoint(), gptAd.id); 260 const responsiveSizeMapping = googletag.sizeMapping(); 261 gptAd.breakpoints.forEach((breakpoint) => { 262 responsiveSizeMapping.addSize([breakpoint.width, 0], breakpoint.sizes.map(parseSize)); 263 }); 264 slot.defineSizeMapping(responsiveSizeMapping.build()); 265 slot.setConfig({ targeting: omitFalsy(gptAd.targeting) }); 266 slot.addService(googletag.pubads()); 267 googletag.display(gptAd.id); 268 log(`[ads] GPT slot defined for ${gptAd.id}`, gptAd, slot); 269 return slot; 270 } 271 var omitFalsy = (obj) => Object.fromEntries(Object.entries(obj).filter(([_, value]) => value)); 272 function setPageLevelTargeting() { 273 const targeting = getAdsConfig().targeting; 274 log(`[ads] GPT targeting set:`, targeting); 275 googletag.setConfig({ targeting }); 276 log(`[ads] Targeting is now`, googletag.getConfig("targeting")); 277 } 278 function enableGptServices() { 279 log("[ads] GPT Services enabled"); 280 googletag.setConfig({ singleRequest: true }); 281 googletag.setConfig({ disableInitialLoad: true }); 282 googletag.setConfig({ collapseDiv: "ON_NO_FILL" }); 283 if (isOptedOut()) { 284 googletag.setConfig({ 285 privacyTreatments: { treatments: ["disablePersonalization"] } 286 }); 287 } 288 googletag.pubads().setPrivacySettings({ 289 nonPersonalizedAds: isOptedOut(), 290 restrictDataProcessing: isOptedOut(), 291 limitedAds: isOptedOut() 292 // childDirectedTreatment: false, // @TODO: maybe set this if we can categorize institutions some day 293 }); 294 const ppid2 = getPublisherProvidedId(); 295 if (ppid2) { 296 googletag.pubads().setPublisherProvidedId(ppid2); 297 log("[ads] PPID enabled"); 298 } 299 googletag.enableServices(); 300 } 301 function bindGptEventHandlers() { 302 googletag.pubads().addEventListener("slotRequested", (event) => { 303 trackPerformanceFirstCall(); 304 const gptAd = getGptAdById(event.slot.getSlotElementId()); 305 gptAd.called = true; 306 gptAd.element.classList.add("is-called"); 307 }); 308 googletag.pubads().addEventListener("slotRenderEnded", (event) => { 309 trackPerformanceFirstLoad(); 310 const gptAd = getGptAdById(event.slot.getSlotElementId()); 311 gptAd.slotRenderedEvent = event; 312 const possibleClasses = [ 313 // No way we got here without these 314 "is-called", 315 "is-registered", 316 "is-empty", 317 "is-loaded", 318 "is-custom-size", 319 "is-fluid-size", 320 "is-standard-size" 321 ]; 322 let desiredClasses = ["is-registered", "is-called"]; 323 desiredClasses.push(event.isEmpty ? "is-empty" : "is-loaded"); 324 gptAd.loaded = true; 325 if (event.size) { 326 gptAd.size = event.size; 327 let size = event.size; 328 if (Array.isArray(size)) { 329 size = size.join("x"); 330 } 331 if (IAB_SIZES.includes(size)) { 332 desiredClasses.push("is-standard-size"); 333 } else if (size === "fluid") { 334 desiredClasses.push("is-fluid-size"); 335 } else if (PREMIUM_SIZES.includes(size)) { 336 desiredClasses.push("is-premium-size"); 337 } else { 338 desiredClasses.push("is-custom-size"); 339 } 340 } 341 possibleClasses.forEach((cls) => { 342 if (desiredClasses.includes(cls)) { 343 gptAd.element.classList.add(cls); 344 } else { 345 gptAd.element.classList.remove(cls); 346 } 347 }); 348 if (event.isEmpty) { 349 log(`[ads] ${gptAd.id}: rendered empty`); 350 return; 351 } 352 log(`[ads] ${gptAd.id}: loaded as ${event.size.join("x")}`); 353 }); 354 googletag.pubads().addEventListener("impressionViewable", (event) => { 355 const gptAd = getGptAdById(event.slot.getSlotElementId()); 356 gptAd.viewableImpression = true; 357 log(`[ads] ${gptAd.id}: viewable-impression`); 358 }); 359 } 360 function callAds(gptAds2) { 361 if (!gptAds2.length) return; 362 log("[ads] called:", gptAds2.map((ad) => ad.id).join(", ")); 363 const slots = gptAds2.map((gptAd) => gptAd.slot); 364 gptAds2.forEach((ad) => { 365 ad.called = true; 366 }); 367 googletag.pubads().refresh(slots); 368 } 369 370
370// src/sciads/observers.js 371 var OBSERVERS = {}; 372 function bindLazyLoadIntersectionObserver(gptAd) { 373 if (!OBSERVERS["lazyload"]) { 374 const lazyLoadDistance = Math.max(window.innerHeight, 750); 375 OBSERVERS["lazyload"] = new IntersectionObserver( 376 (entries) => { 377 entries.map((entry) => { 378 const gptAd2 = getGptAdById(entry.target.id); 379 gptAd2.inLazyRange = entry.isIntersecting; 380 }); 381 }, 382 { 383 rootMargin: `0px 0px ${lazyLoadDistance}px 0px` 384 } 385 ); 386 } 387 const observer = OBSERVERS["lazyload"]; 388 observer.unobserve(gptAd.element); 389 observer.observe(gptAd.element); 390 } 391 function bindRefreshLoadIntersectionObserver(gptAd) { 392 if (!OBSERVERS["lazyload-200"]) { 393 OBSERVERS["refresh"] = new IntersectionObserver( 394 (entries) => { 395 entries.map((entry) => { 396 const gptAd2 = getGptAdById(entry.target.id); 397 gptAd2.inRefreshRange = entry.isIntersecting; 398 }); 399 }, 400 { 401 rootMargin: `0px 0px 0px 0px` 402 } 403 ); 404 } 405 const observer = OBSERVERS["refresh"]; 406 observer.unobserve(gptAd.element); 407 observer.observe(gptAd.element); 408 } 409 var BREAKPOINTS = []; 410 function handleCrossBreakpoint({ width }) { 411 const gptAds2 = getAllAds().filter((gptAd) => { 412 const matchingBreakpoint = gptAd.breakpoints.map((bp) => bp.width).includes(width); 413 return matchingBreakpoint && gptAd.called; 414 }
414).forEach((gptAd) => { 415 gptAd.reset(); 416 }); 417 } 418 function bindBreakpointObserver(gptAd) { 419 gptAd.breakpoints.forEach((bp) => { 420 if (BREAKPOINTS.includes(bp)) { 421 return; 422 } 423 BREAKPOINTS.push(bp); 424 window.matchMedia(`(min-width: ${bp.width}px)`).addEventListener("change", (e) => { 425 handleCrossBreakpoint({ width: bp.width }); 426 }); 427 log(`Registered ad breakpoint at ${bp.width}px`); 428 }); 429 } 430 431
431// src/sciads/debug.js 432 var params = new URLSearchParams(window.location.search); 433 var excludedSizes = void 0; 434 function debugExcludeSizes(sizes) { 435 if (sizes.length === 0) { 436 return; 437 } 438 if (excludedSizes === void 0) { 439 excludedSizes = (params.get("debug:ads-exclude") || "").split(","); 440 if (excludedSizes.length) { 441 log(`[ads] debug:ads-exclude active, filtering out sizes`, excludedSizes); 442 } 443 } 444 if (excludedSizes === null) { 445 return sizes; 446 } 447 sizes = sizes.filter((size) => { 448 return excludedSizes.indexOf(size) === -1; 449 }); 450 if (sizes.length === 0) { 451 sizes.push("404x1"); 452 } 453 return sizes; 454 } 455 456
456// src/sciads/models.js 457 var adCounter = 0; 458 var gptAds = []; 459 var adsConfig = { 460 unitpath: "", 461 targeting: {} 462 }; 463 function setKeyValues(params2) { 464 for (let key in params2) { 465 adsConfig.targeting[key] = params2[key]; 466 } 467 } 468 function setAdsConfig(newConfig, reset = false) { 469 if (reset) { 470 adsConfig = newConfig; 471 } else { 472 Object.assign(adsConfig, newConfig); 473 } 474 if (!adsConfig.unitpath) { 475 console.error("unitpath was not set. Ads will not work."); 476 } 477 } 478 function getAdsConfig() { 479 return adsConfig; 480 } 481 var GptAd = class { 482 constructor(gptElement) { 483 gptElement.classList.add("is-registered"); 484 this.element = gptElement; 485 this.getPropertiesFromElement(); 486 this.setId(); 487 this.slotRenderedEvent = null; 488 this.called = false; 489 this.loaded = false; 490 this.empty = false; 491 this.viewableImpression = false; 492 this.size = null; 493 gptQueue.push(() => { 494 this.slot = defineSlot(this); 495 }); 496 this.inLazyRange = false; 497 this.inRefreshRange = false; 498 bindLazyLoadIntersectionObserver(this); 499 bindRefreshLoadIntersectionObserver(this); 500 bindBreakpointObserver(this); 501 } 502 /** 503 * Clear out the ad and make it eligible for refresh. 504 */ 505 reset() { 506 const id = this.element.id; 507 this.element.removeAttribute("id"); 508 this.element.classList.remove("is-registered"); 509 gptAds.splice(gptAds.indexOf(this), 1); 510 log(`[ad] reset for ${id}`); 511 requestAnimationFrame(() => { 512 registerAds(); 513 }); 514 } 515 /** 516 * Convert HTML into data structure 517 */ 518 getPropertiesFromElement() { 519 this.unitpath = adsConfig.unitpath; 520 if (this.element.getAttribute("unitpath")) { 521 this.unitpath = this.unitpath + "/" + this.element.getAttribute("unitpath"); 522 } 523 const attributes = Object.values(this.element.attributes); 524 this.targeting = {}; 525 attributes.filter((attr) => attr.name.startsWith("targeting-")).forEach((attr) => { 526 let key = attr.name.replace(/^targeting-/, ""); 527 this.targeting[key] = attr.value; 528 }); 529 this.breakpoints = []; 530 attributes.filter((attr) => attr.name.startsWith("sizes-from-")).forEach((attr) => { 531 let width = parseInt(attr.name.replace(/^sizes-from-/, ""), 10); 532 let sizes = attr.value.split(","); 533 sizes = debugExcludeSizes(sizes); 534 this.breakpoints.push({ width, sizes }); 535 }); 536 this.breakpoints = this.breakpoints.sort((a, b) => { 537 return a.width - b.width; 538 }); 539 } 540 setId() { 541 adCounter++; 542 const template = this.element.getAttribute("id-format") || "gpt-unit-{}"; 543 const id = template.replace("{}", adCounter); 544 this.id = id; 545 this.element.setAttribute("id", id); 546 } 547 getSizesForBreakpoint() { 548 let sizes = []; 549 for (let bp of this.breakpoints) { 550 if (bp.width <= window.innerWidth) { 551 sizes = bp.sizes; 552 } 553 } 554 return sizes; 555 } 556 }; 557 function registerAds() { 558 [...document.querySelectorAll("gpt-ad:not(.is-registered)")].forEach((el) => { 559 let ad = new GptAd(el); 560 gptAds.push(ad); 561 log(`Registered <gpt-ad> for ${ad.id}`, ad); 562 }); 563 } 564 function getGptAdById(id) { 565 return gptAds.find((ad) => { 566 return ad.id === id; 567 }); 568 } 569 function getAllAds() { 570 return gptAds; 571 } 572 573
573// src/sciads/utils/load.js 574 function loadScript(src, async = true) { 575 const script = document.createElement("script"); 576 script.src = src; 577 if (async) script.setAttribute("async", ""); 578 return new Promise((resolve, reject) => { 579 script.onload = resolve; 580 script.onerror = reject; 581 document.body.appendChild(script); 582 }); 583 } 584 585
585// src/sciads/plugins/mediatrust.js 586 function mediaTrust() { 587 const src = "https://scripts.webcontentassessor.com/scripts/4ca93f8138ee391320844a5f73486804166750feebd4d600d41de59ec8102b3d"; 588 return loadScript(src); 589 } 590 591
591// src/sciads/plugins/polar.js 592 function polar() { 593 const src = "https://cdn.mediavoice.com/nativeads/script/scientificamerican/pl-track.js"; 594 const isSponsorContent = window.location.pathname.startsWith("/custom-media/"); 595 if (isSponsorContent) { 596 loadScript(src); 597 } 598 } 599 600
600// src/sciads/plugins/testing.js 601 function testingKeyValues() { 602 const params2 = new URLSearchParams(window.location.search); 603 let targeting = {}; 604 [...params2.keys()].filter((key) => { 605 return key.startsWith("adkv_"); 606 }).forEach((key) => { 607 let value = params2.getAll(key); 608 let tkey = key.replace("adkv_", "", 1); 609 targeting[tkey] = value; 610 }); 611 setKeyValues(targeting); 612 } 613 614
614// src/sciads/plugins/entitlements.js 615 function getStateKey(uid) { 616 return `_ad_user_state-${uid}`; 617 } 618 var state = { 619 features: [] 620 // Chargebee 621 }; 622 function loadState(uid) { 623 try { 624 let data = sessionStorage.getItem(getStateKey(uid)); 625 if (data) { 626 state = JSON.parse(data); 627 return true; 628 } 629 } catch (e) { 630 console.error(e); 631 } 632 return false; 633 } 634 function userDataTargeting() { 635 return new Promise((resolve) => { 636 const user = getUserData(); 637 if (!user) { 638 log(`[ads] user not logged in`); 639 state.resources = []; 640 setKeyValues({ entitlements: ["no"] }); 641 return resolve(); 642 } 643 const entitlements = user?.features ?? []; 644 if (entitlements) { 645 state.features = entitlements ?? []; 646 setKeyValues({ entitlements: entitlements ?? ["no"] }); 647 return resolve(); 648 } 649 const uid = user["https://sciam.com/user_id"]; 650 const hasCachedState = loadState(uid); 651 if (hasCachedState) { 652 log(`[ads] using entitlements from session cache`, state); 653 resolve(); 654 } 655 }); 656 } 657 function getIsAdFree() { 658 const cb_adfree = (state.features || []).includes("ad-free-access"); 659 return cb_adfree; 660 } 661 662
662// src/sciads/plugins/upsapi.js 663 function upsapi() { 664 log("[ads] creating __uspapi"); 665 window.__uspapi = function(command, versionRequested, callback) { 666 if (command !== "getUSPData") { 667 console.error(`Command <${command}> not implemented. Only <getUSPData> is supported.`); 668 return; 669 } 670 const version = 1; 671 const noticeGiven = "Y"; 672 const optedOut = isOptedOut() ? "Y" : "N"; 673 const limited_service_provider_agreement_member = "-"; 674 callback( 675 { 676 version, 677 uspString: [version, noticeGiven, optedOut, limited_service_provider_agreement_member].join( 678 "" 679 ) 680 }, 681 true 682 ); 683 }; 684 } 685 686
686// src/sciads/plugins/interests.js 687 function interests() { 688 if (isOptedOut()) return; 689 let travel = readCookie("sciam_interest-travel"); 690 if (travel) { 691 setKeyValues({ travel: travel.split(",") }); 692 } 693 } 694 695
695// src/sciads/plugins/index.js 696 var PERF_KEYS2 = { 697 pluginsStart: "ads:plugins_start", 698 pluginsEnd: "ads:plugins_ready", 699 measurePlugins: "ads:measure_plugins" 700 }; 701 async function runPlugins() { 702 performance.mark(PERF_KEYS2.pluginsStart); 703 await Promise.allSettled([ 704 upsapi(), 705 testingKeyValues(), 706 userDataTargeting(), 707 mediaTrust(), 708 polar(), 709 publisherProvidedId(), 710 interests() 711 ]); 712 performance.mark(PERF_KEYS2.pluginsEnd); 713 performance.measure(PERF_KEYS2.measurePlugins, PERF_KEYS2.pluginsStart, PERF_KEYS2.pluginsEnd); 714 logMeasurement(PERF_KEYS2.measurePlugins, "Ads: plugins complete in"); 715 } 716 717
717// src/sciads/rendering.js 718 var _scrollPos = 0; 719 window.requestAnimationFrame(() => { 720 _scrollPos = window.scrollY; 721 }); 722 function render() { 723 let previousScrollPos = _scrollPos; 724 _scrollPos = window.scrollY; 725 let scrollDelta = Math.abs(previousScrollPos - _scrollPos); 726 if (scrollDelta > 500) { 727 log("Scrolling too fast - ad render skipped"); 728 return; 729 } 730 let adsToRender = getAllAds().filter((gptAd) => { 731 return !gptAd.called && gptAd.inLazyRange; 732 }); 733 callAds(adsToRender); 734 } 735 736
736// src/sciads/utils/testing.js 737 var abTestGroup; 738 function getABTestGroup() { 739 if (abTestGroup !== void 0) { 740 return abTestGroup; 741 } 742 abTestGroup = Math.floor(Math.random() * 10) + 1; 743 log(`[ads] ABT group ${abTestGroup}`); 744 setKeyValues({ abt: abTestGroup.toString() }); 745 return abTestGroup; 746 } 747 748
748// src/sciads/controller.js 749 async function initAdsLifeCycle() { 750 getABTestGroup(); 751 registerAds(); 752 const [geo] = await Promise.allSettled([getGeo(), getConsent()]); 753 let gptSrc = "https://securepubads.g.doubleclick.net/tag/js/gpt.js"; 754 if (isOptedOut()) { 755 const gdprApplies = geo.value?.country ? gdprCountries.includes(geo.value.country) : window.Osano?.cm?.gdprApplies; 756 const debugGdpr = window.location.search.match(/debug=gdpr/); 757 if (gdprApplies || debugGdpr) return log(`[ads] GDPR opt-out, no ads`); 758 gptSrc = "https://pagead2.googlesyndication.com/tag/js/gpt.js"; 759 } 760 loadScript(gptSrc).then(() => { 761 log("GPT loaded"); 762 performance.mark(PERF_KEYS.gptLoaded); 763 }); 764 await runPlugins(); 765 if (getIsAdFree()) { 766 return log(`[ads] Premium user, no ads`); 767 } 768 gptQueue.push(() => { 769 performance.mark(PERF_KEYS.gptQueue); 770 log("Started GPT Queue"); 771 setPageLevelTargeting(); 772 bindGptEventHandlers(); 773 enableGptServices(); 774 render(); 775 setInterval(() => { 776 registerAds(); 777 render(); 778 }, 250); 779 }); 780 } 781 782
782// src/sciads/commands.js 783 var COMMANDS = { 784 /** 785 * The "pagview" describes the page fo adtech 786 * purposes. This starts the lifecycle. 787 * 788 * @param {adsConfig} adsConfig 789 */ 790 page: function(adsConfig2) { 791 performance.mark(PERF_KEYS.page); 792 setAdsConfig(adsConfig2, true); 793 initAdsLifeCycle(); 794 }, 795 get: function(id) { 796 console.log(getGptAdById(id)); 797 } 798 }; 799 function handleCommand(cmdArr) { 800 const [cmd, args] = cmdArr; 801 log(`SciAds command "${cmd}"`, args); 802 const callback = COMMANDS[cmd]; 803 if (callback) { 804 callback(args); 805 } 806 } 807 808
808// src/sciads.js 809 performance.mark(PERF_KEYS.libLoaded); 810 function createApi() { 811 window.__ads = window.__ads || []; 812 window.__ads.push = handleCommand; 813 window.__ads.forEach(handleCommand); 814 } 815 function init() { 816 log("Hello SciAds"); 817 createApi(); 818 } 819 init(); 820})(); 821//# sourceMappingURL=sciads.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.