How telephone history explains the Oracle-Google Supreme Court case.

Split screen of phone receivers with the Oracle and Google logos behind them.
Photo illustration by Slate. Photos by Nastco/iStock/Getty Images Plus, Google, and Oracle.

On Wednesday, tech giants Oracle and Google will square off before the Supreme Court to argue what some have called the “copyright case of the century”—and in this time of COVID-19, the argument will be heard by telephone. Though the computer technologies involved in the case are far removed from century-old telephony, that ancient system’s history shows precisely what is at stake before the Supreme Court: The wrong outcome could end up unexpectedly empowering Big Tech more than ever.

The Google v. Oracle lawsuit is a copyright case, the kind that often involves copying a novel or music lyrics. But the words Oracle accuses Google of copying are no ordinary words. This gets technical, but bear with me. In the 1990s as part of its Java system, Sun Microsystems developed software tools for encrypting data, reading databases, and compressing files. Sun also devised an “application programming interface” consisting of command names and syntaxes that programmers would use to communicate with the tools. In much the same way as one pushes a button marked “Play” to tell a VCR to start a tape, a programmer writes words like “javax.crypto.KeyGenerator.getInstance” to tell the Java software to start making encryption keys.

When Google began developing its Android mobile platform around 2007, it created its own software tools and used command names mirroring Java’s. That way, Java programmers could carry over their existing knowledge and code to the new platform, just as VCR users can start a newfangled DVD with a button also marked “Play.” Oracle acquired Sun in 2010 and almost immediately sued Google for almost $9 billion, claiming that reusing Sun’s command names is the illegal act of copying.

The fact that Google chose to have a single set of commands work between Java and Android makes this case about “interoperability”: having a single means of communication to access multiple competing services. History is replete with examples of interoperability, but the telephone is perhaps the most widespread and storied. When the Supreme Court justices and attorneys convene Wednesday, they might be served by AT&T, Verizon, T-Mobile, Sprint, or anyone else, yet they will all reach one another. All of them, and all of us, can use a common means of communication to call any phone company, because telephone systems are interoperable.

Today we take interconnection, the telephone industry term for interoperability, for granted, but it was not always this way. In the late 1800s, after Alexander Graham Bell’s patents on the telephone expired, numerous phone services sprang up across America in competition with the dominant American Bell Telephone Co. But these “independent” services were separate islands: A Bell telephone could not call an independent or vice versa. A person wanting to talk to both Bell and independent customers had to purchase two service contracts, two wires, and even two handsets.

Public frustration about “dual service” helped to make Bell, later AT&T, into the original big tech company because of what economists call a “lock-in effect.” Bell subscribers wanting to switch to a competitor faced enormous switching costs—buying new equipment and connecting to an independent with fewer subscribers—and thus would be reluctant to support an upstart competitor. Being unable to reach Bell’s customers especially via the long-distance lines exclusively held by Bell, the independents largely dried up or were acquired, giving Bell near-complete control over the telephone market.

Toward the latter half of the 20th century, government regulators began to look to break up that dominant position and introduce competition in the telephone market. Interoperability was key. If independents could interconnect with Bell’s network, Bell subscribers would avoid switching costs to reach independent customers and vice versa, allowing competition to grow.

Interconnection prominently featured in the 1982 antitrust case against AT&T. Besides breaking the company into regional “Baby Bells,” the final court order required the newly formed entities to provide their competitors access “equal in type, quality, and price to that provided to AT&T and its affiliates.” The Telecommunications Act of 1996 further made interconnection a top priority, providing that every “telecommunications carrier has the duty … to interconnect directly or indirectly with the facilities and equipment of other telecommunications carriers.” The law also contains a “dialing parity” rule strikingly like the interoperability Google hopes to achieve. Before 1996, calling a customer on a competing phone service sometimes required dialing a lengthy access code that depended on what services the calling parties used. Dialing parity eliminated the access codes, ensuring that one phone number would reach the same customer on whatever service that customer happened to use, just as one command name reaches the same software tool on Java and Android.

Telephone interconnection shows why the Oracle v. Google case, seemingly relevant to only the techiest of techies, could have widespread implications for society’s relationship with dominant tech firms. Just as Bell’s monopoly derived from telephone subscriber lock-in, computer technology firms enjoy lock-in effects based on command names left and right: Oracle’s popular Java command names, internal codes in Microsoft’s ubiquitous DOCX document format, and Amazon’s leading cloud computing interface, for example. Android could have offered an encryption toolkit using all-new command names, but Java programmers might be reluctant to invest in switching; the Bell saga shows how noninteroperable dual service is the path to big tech monopolies. Interoperability to overcome lock-in has led competing word processors (including Oracle OpenOffice) to interoperate with Microsoft’s document format and led competing cloud services (including Oracle Cloud) to copy Amazon’s command names. If copyright law prohibits competitors from reusing command names to build interoperable products, then powerful companies will hold the keys to blocking competition and making our technological future dependent on them.

While the reasons for interoperability are the same between computer commands and telephones, the means of achieving it are naturally different. Telephone interconnection involves a complex regulatory system, and Oracle would be the first to point out that competitors pay fees for the privilege. But those are the result of physical buildout needs: To enable interconnection, a telephone company must lay down wires, maintain switching equipment, and operate premises. By contrast, Google can make Android interoperable with Java’s commands with no help from Oracle at all. Breaking down barriers to telephone interoperability required affirmative laws and rules, but the only barrier to interoperability in the Google v. Oracle case is a questionable reading of copyright law that the Supreme Court could eliminate with the flick of a pen.

As connected technologies such as social media, the Internet of Things, and self-driving cars embed themselves further in society, interoperability will only become more important as a means of ensuring competition and avoiding big tech lock-in. But the magic of interoperability may also be its downfall: Interoperability, at is best, is invisible. I do not expect any of the attorneys to think for a moment about why their phone services can access the Supreme Court’s line. As the justices debate the future of interoperability, they will—almost certainly without knowing it—be enjoying the fruits of a century of work toward interoperability just to have that debate. It remains to be seen whether their decision will keep things that way.

Future Tense
is a partnership of
Slate,
New America, and
Arizona State University
that examines emerging technologies, public policy, and society.

nnx3c!-- Rubicon Project Ad Tag --x3en

nn

nn")), n = v(f[r.size_id].split("x").map(function (e)
return Number(e);
), 2), i.width = n[0], i.height = n[1]), i.rubiconTargeting = (Array.isArray(r.targeting) ? r.targeting : []).reduce(function (e, r)
return e[r.key] = r.values[0], e;
,
rpfl_elemid: s.adUnitCode
), e.push(i)) : g.logError("Rubicon: bidRequest undefined at index position:".concat(t), c, d), e;
, []).sort(function (e, r) 0) - (e.cpm );
},
getUserSyncs: function getUserSyncs(e, r, t, i)
if (!R && e.iframeEnabled)
var n = "";
return t && "string" == typeof t.consentString && ("boolean" == typeof t.gdprApplies ? n += "?gdpr=".concat(Number(t.gdprApplies), "&gdpr_consent=").concat(t.consentString) : n += "?gdpr_consent=".concat(t.consentString)), i && (n += "".concat(n ? "&" : "?"https://slate.com/technology/2020/10/,"us_privacy=").concat(encodeURIComponent(i))), R = !0,
type: "iframe",
url: a + n
;

,
transformBidParams: function transformBidParams(e)
return g.convertTypes(
accountId: "number",
siteId: "number",
zoneId: "number"
, e);

};

function _(e, r)

function I(e, r)
var t = b.b.getConfig("pageUrl"),
t = e.params.referrer ? e.params.referrer : t

function A(e, r)
var t = e.params;

if ("video" === r)
var i = [];
return t.video && t.video.playerWidth && t.video.playerHeight ? i = [t.video.playerWidth, t.video.playerHeight] : Array.isArray(g.deepAccess(e, "mediaTypes.video.playerSize")) && 1 === e.mediaTypes.video.playerSize.length ? i = e.mediaTypes.video.playerSize[0] : Array.isArray(e.sizes) && 0 < e.sizes.length && Array.isArray(e.sizes[0]) && 1 < e.sizes[0].length && (i = e.sizes[0]), i; var n = []; return Array.isArray(t.sizes) ? n = t.sizes : void 0 !== g.deepAccess(e, "mediaTypes.banner.sizes") ? n = s(e.mediaTypes.banner.sizes) : Array.isArray(e.sizes) && 0 < e.sizes.length ? n = s(e.sizes) : g.logWarn("Rubicon: no sizes are setup or found"), S(n); function s(e) return g.parseSizesInput(e).reduce(function (e, r) var t = parseInt(f[r], 10); return t && e.push(t), e; , []); function c(e) return "object" === x(g.deepAccess(e, "params.video")) && void 0 !== g.deepAccess(e, "mediaTypes.".concat(u.d)); function m(e, r) var t = 1 < arguments.length && void 0 !== r && r; return c(e) ? -1 === ["outstream"https://slate.com/technology/2020/10/,"instream"].indexOf(g.deepAccess(e, "mediaTypes.".concat(u.d, ".context"))) ? void (t && g.logError("Rubicon: mediaTypes.video.context must be outstream or instream")) : A(e, "video").length < 2 ? void (t && g.logError("Rubicon: could not determine the playerSize of the video")) : (t && g.logMessage("Rubicon: making video request for adUnit", e.adUnitCode), "video") : 0 === A(e, "banner").length ? void (t && g.logError("Rubicon: could not determine the sizes for banner request")) : (t && g.logMessage("Rubicon: making banner request for adUnit", e.adUnitCode), "banner"); function S(e) var n = [15, 2, 9]; return e.sort(function (e, r) -1 < i ? -1 === t ? 1 : -1 === i ? -1 : t - i : e - r; ); function C(e) var r = parseInt(g.deepAccess(e, "params.video.size_id")); return isNaN(r) ? "outstream" === g.deepAccess(e, "mediaTypes.".concat(u.d, ".context")) ? 203 : 201 : r; function j(e) return ranges: low: [ max: 5, increment: .5 ], medium: [ max: 20, increment: .1 ], high: [ max: 20, increment: .01 ], auto: [ max: 5, increment: .05 , min: 5, max: 10, increment: .1 , min: 10, max: 20, increment: .5 ], dense: [ max: 3, increment: .01 , min: 3, max: 8, increment: .05 , min: 8, max: 20, increment: .5 ], custom: e.getConfig("customPriceBucket") && e.getConfig("customPriceBucket").buckets [e.getConfig("priceGranularity")] ; function k(r) var t = !0, e = Object.prototype.toString.call([]), i = Object.prototype.toString.call(0), n = mimes: e, protocols: e, maxduration: i, linearity: i, api: e ; return Object.keys(n).forEach(function (e) Object.prototype.toString.call(g.deepAccess(r, "mediaTypes.video." + e)) !== n[e] && (t = !1, g.logError("Rubicon: mediaTypes.video." + e + " is required and must be of type: " + n[e])); ), t; function T(e) var r = !1, t = ["asi"https://slate.com/technology/2020/10/,"sid"https://slate.com/technology/2020/10/,"hp"]; return e.nodes && ((r = e.nodes.reduce(function (e, r) return e ? t.every(function (e) return r[e]; ) : e; , !0)) function w(e, r) return "rp_schain" === e ? "rp_schain=".concat(r) : "".concat(e, "=").concat(encodeURIComponent(r)); var R = !1; Object(i.registerBidder)(h); } }, [677]); pbjsChunk([93], { 719: function _(e, t, r) e.exports = r(720); , 720: function _(e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", value: !0 ), r.d(t, "spec", function () return o; ), r.d(t, "_isInbounds", function () return a; ), t._getPlatform = v; var n = r(1), y = r(0), i = r(2), c = r(3), g = r(10), d = r(44); function h(e, t) return function (e) if (Array.isArray(e)) return e; (e) function s(e, t) function u() function (e) for (var t = 1; t < arguments.length; t++) var r = arguments[t]; for (var n in r) Object.prototype.hasOwnProperty.call(r, n) && (e[n] = r[n]); return e; ).apply(this, arguments); function p(e, t, r) return t in e ? Object.defineProperty(e, t, value: r, enumerable: !0, configurable: !0, writable: !0 ) : e[t] = r, e; var b = "sonobi", l = Object(y.generateUUID)(), o = { code: b, supportedMediaTypes: [i.b, i.d], isBidRequestValid: function isBidRequestValid(e) if (!e.params) return !1; if (!e.params.ad_unit && !e.params.placement_id) return !1; if (!Object(y.deepAccess)(e, "mediaTypes.banner") && !Object(y.deepAccess)(e, "mediaTypes.video")) return !1; if (Object(y.deepAccess)(e, "mediaTypes.banner")) if (!Object(y.deepAccess)(e, "mediaTypes.banner.sizes") && !e.params.sizes) return !1; else if (Object(y.deepAccess)(e, "mediaTypes.video")) if ("outstream" === Object(y.deepAccess)(e, "mediaTypes.video.context") && !e.params.sizes) return !1; if ("instream" === Object(y.deepAccess)(e, "mediaTypes.video.context") && !Object(y.deepAccess)(e, "mediaTypes.video.playerSize")) return !1; return !0; , buildRequests: function buildRequests(e, t) var r = e.map(function (e) ").concat(f(e)).concat(m(e))) : void Object(y.logError)("The ad unit code or Sonobi Placement id for slot ".concat(e.bidId, " is invalid")); ), n = ; r.forEach(function (e) u(n, e); ); var i = key_maker: JSON.stringify(n), ref: t.refererInfo.referer, s: Object(y.generateUUID)(), pv: l, vp: v(), lib_name: "prebid", lib_v: "3.23.0", us: 0 ; c.b.getConfig("userSync") && c.b.getConfig("userSync").syncsPerBidder && (i.us = c.b.getConfig("userSync").syncsPerBidder), d.a.canBidderRegisterSync("iframe", b) ? i.ius = 1 : i.ius = 0, Object(y.deepAccess)(e[0], "params.hfa") && (i.hfa = Object(y.deepAccess)(e[0], "params.hfa")), e[0].params.referrer && (i.ref = e[0].params.referrer), t && t.gdprConsent && (i.gdpr = t.gdprConsent.gdprApplies ? "true" : "false", t.gdprConsent.consentString && (i.consent_string = t.gdprConsent.consentString)); var s = function (t) ("fhnS5drwmH"); s && (i.digid = s.id, i.digkeyv = s.keyv), e[0].schain && (i.schain = JSON.stringify(e[0].schain)), Object(y.deepAccess)(e[0], "userId") && 0 < Object.keys(e[0].userId).length && (i.userid = JSON.stringify(e[0].userId)); var o = e[0].params.keywords; if (o && (i.kw = o), t && t.uspConsent && (i.us_privacy = t.uspConsent), Object(y.isEmpty)(n)) return null; var a = "https://apex.go.sonobi.com/trinity.json"; return Object(y.deepAccess)(e[0], "params.bid_request_url") && (a = Object(y.deepAccess)(e[0], "params.bid_request_url")), method: "GET", url: a, withCredentials: !0, data: i, bidderRequests: e ; , interpretResponse: function interpretResponse(e, l) { var f = e.body, m = [], v = l.data.ref; return 0 === Object.keys(f.slots).length || Object.keys(f.slots).forEach(function (e) ").slice(-1)[0], n = function (e, t) for (var r = 0; r < e.length; r++) if (e[r].bidId === t) return e[r]; (l.bidderRequests, r), i = null; "video" === t.sbi_ct && (i = "video"https://slate.com/technology/2020/10/,"outstream" === Object(y.deepAccess)(n, "mediaTypes.video.context") && (i = "outstream")); var s, o, a, c, d, u, p, b = j(i, v); t.sbi_aid && t.sbi_mouse && t.sbi_size && (a = void 0 === (o = (s = h(t.sbi_size.split("x"), 2))[0]) ? 1 : o, d = void 0 === (c = s[1]) ? 1 : c, u = , t.sbi_dozer && (u.dealId = t.sbi_dozer), "video" === i ? (u.mediaType = "video", u.vastUrl = b(f.sbi_dc, t.sbi_aid), delete u.ad, delete u.width, delete u.height) : "outstream" === i && n && (u.mediaType = "video", u.vastUrl = b(f.sbi_dc, t.sbi_aid), u.renderer = function (e, t) var r = 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : , n = g.a.install( id: t.aid, url: "https://mtrx.go.sonobi.com/sbi_outstream_renderer.js", config: r, loaded: !1, adUnitCode: e ); try n.setRender(O); catch (e) Object(y.logWarn)("Prebid Error calling setRender on renderer", e); return n.setEventHandlers( impression: function impression() return Object(y.logMessage)("Sonobi outstream video impression event"); , loaded: function loaded() return Object(y.logMessage)("Sonobi outstream video loaded event"); , ended: function ended() Object(y.logMessage)("Sonobi outstream renderer video event"); ), n; (n.adUnitCode, u, Object(y.deepAccess)(n, "renderer.options")), p = Object(y.deepAccess)(n, "params.sizes"), Array.isArray(p) && Array.isArray(p[0]) && (p = p[0]), p && (u.width = p[0], u.height = p[1])), m.push(u)); ), m; }, getUserSyncs: function getUserSyncs(e, t) var r = []; try e.pixelEnabled && t[0].body.sbi_px.forEach(function (e) r.push( type: e.type, url: e.url ); ); catch (e) return r; }; function f(e) return Object(y.deepAccess)(e, "mediaTypes.video") ? "" : e.params.sizes ? Object(y.parseSizesInput)(e.params.sizes).join(",") : Object(y.deepAccess)(e, "mediaTypes.banner.sizes") ? Object(y.parseSizesInput)(Object(y.deepAccess)(e, "mediaTypes.banner.sizes")).join(",") : e.sizes ? Object(y.parseSizesInput)(e.sizes).join(",") : void 0; function m(e) return e.params.floor ? " var j = function j(i, s) return function (e, t) ; ; var a = function a(e) var r = 0 < arguments.length && void 0 !== e ? e : window; return function () var e = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : 0, t = 1 < arguments.length && void 0 !== arguments[1] ? arguments[1] : Number.MAX_SAFE_INTEGER; return r.innerWidth >= e && r.innerWidth < t; ; ; function v() var e = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : window, t = a(e), r = 992, n = 768; return t(0, 768) ? "mobile" : t(n, r) ? "tablet" : "desktop"; function O(i) i.renderer.push(function () var e = h(i.getSize().split("x"), 2), t = e[0], r = e[1], n = new window.SbiOutstreamRenderer(); n.init( vastUrl: i.vastUrl, height: r, width: t ), n.setRootElement(i.adUnitCode); ); Object(n.registerBidder)(o); } }, [719]); pbjsChunk([85], { 741: function _(e, r, t) e.exports = t(742); , 742: function _(e, r, t) { "use strict"; Object.defineProperty(r, "__esModule", value: !0 ), t.d(r, "spec", function () return n; ); var a = t(1), d = t(0), p = 12, o = 11, c = 0, u = 22, n = code: "teads", supportedMediaTypes: ["video"https://slate.com/technology/2020/10/,"banner"], isBidRequestValid: function isBidRequestValid(e) d.logError("Teads placementId and pageId parameters are required. Bid aborted."), a; , buildRequests: function buildRequests(e, r) var t = e.map(I), a = referrer: function (e) var r = ""; e && e.refererInfo && e.refererInfo.referer && (r = e.refererInfo.referer); return r; (r), data: t, deviceWidth: screen.width, hb_version: "3.23.0" ; e[0].schain && (a.schain = e[0].schain); var n, d, i, s = r.gdprConsent; return r && s && (n = "boolean" == typeof s.gdprApplies, d = "string" == typeof s.consentString, i = n ? function (e, r, t) var a = p; e ? function (e, r) 2 !== r) && !e.isServiceSpecific; (r, t) && (a = o) : a = c; return a; (s.gdprApplies, s.vendorData, s.apiVersion) : u, a.gdpr_iab = consent: d ? s.consentString : "", status: i, apiVersion: s.apiVersion ), r && r.uspConsent && (a.us_privacy = r.uspConsent), method: "POST", url: "https://a.teads.tv/hb/bid-request", data: JSON.stringify(a) ; , interpretResponse: function interpretResponse(e) var t = []; return (e = e.body).responses && e.responses.forEach(function (e) var r = cpm: e.cpm, width: e.width, height: e.height, currency: e.currency, netRevenue: !0, ttl: e.ttl, ad: e.ad, requestId: e.bidId, creativeId: e.creativeId, placementId: e.placementId ; e.dealId && (r.dealId = e.dealId), t.push(r); ), t; ; function I(e) var r, t = , a = d.getValue(e.params, "placementId"), n = d.getValue(e.params, "pageId"); return t.sizes = (r = e, d.parseSizesInput(function (e) (r))), t.bidId = d.getBidIdParameter("bidId", e), t.bidderRequestId = d.getBidIdParameter("bidderRequestId", e), t.placementId = parseInt(a, 10), t.pageId = parseInt(n, 10), t.adUnitCode = d.getBidIdParameter("adUnitCode", e), t.auctionId = d.getBidIdParameter("auctionId", e), t.transactionId = d.getBidIdParameter("transactionId", e), t; function i(e) return 0 < parseInt(e); Object(a.registerBidder)(n); } }, [741]); pbjsChunk([76], { 761: function _(r, e, t) r.exports = t(762); , 762: function _(r, e, t) { "use strict"; Object.defineProperty(e, "__esModule", value: !0 ), t.d(e, "tripleliftAdapterSpec", function () return s; ); var n = t(2), i = t(1), o = t(0), u = t(3); function p(r) function (r, e) "Set" === t) return Array.from(r); if ("Arguments" === t (r) function d(r, e) e > r.length) && (e = r.length);

for (var t = 0, n = new Array(e); t < e; t++) n[t] = r[t]; return n; var a = !0, c = null, s = { code: "triplelift", supportedMediaTypes: [n.b], isBidRequestValid: function isBidRequestValid(r) return void 0 !== r.params.inventoryCode; , buildRequests: function buildRequests(r, e) { var t, n = "https://tlx.3lift.com/header/auction?", i = function (r) { var e = , t = r[0].schain; e.imp = r.map(function (r, e) { return id: e, tagid: r.params.inventoryCode, floor: r.params.floor, banner: format: r.sizes.filter(l).map(function (r) return w: r[0], h: r[1] ; ) ; }); var n = [].concat(p(function (r) return f(r, "tdid"https://slate.com/technology/2020/10/,"adserver.org"https://slate.com/technology/2020/10/,"TDID"); (r)), p(function (r) return f(r, "idl_env"https://slate.com/technology/2020/10/,"liveramp.com"https://slate.com/technology/2020/10/,"idl"); (r)), p(function (r) return f(r, "criteoId"https://slate.com/technology/2020/10/,"criteo.com"https://slate.com/technology/2020/10/,"criteoId"); (r))); 0 < n.length && (e.user = ext: eids: n ); t && (e.ext = schain: t ); return e; }(r); return n = o.tryAppendQueryString(n, "lib"https://slate.com/technology/2020/10/,"prebid"), n = o.tryAppendQueryString(n, "v"https://slate.com/technology/2020/10/,"3.23.0"), e && e.refererInfo && (t = e.refererInfo.referer, n = o.tryAppendQueryString(n, "referrer", t)), e && e.timeout && (n = o.tryAppendQueryString(n, "tmax", e.timeout)), e && e.gdprConsent && (void 0 !== e.gdprConsent.gdprApplies && (a = e.gdprConsent.gdprApplies, n = o.tryAppendQueryString(n, "gdpr", a.toString())), void 0 !== e.gdprConsent.consentString && (c = e.gdprConsent.consentString, n = o.tryAppendQueryString(n, "cmp_cs", c))), e && e.uspConsent && (n = o.tryAppendQueryString(n, "us_privacy", e.uspConsent)), !0 === u.b.getConfig("coppa") && (n = o.tryAppendQueryString(n, "coppa", !0)), n.lastIndexOf("&") === n.length - 1 && (n = n.substring(0, n.length - 1)), o.logMessage("tlCall request built: " + n), method: "POST", url: n, data: i, bidderRequest: e ; }, interpretResponse: function interpretResponse(r, e) , getUserSyncs: function getUserSyncs(r, e, t, n) var i = function (r) if (!r) return; if (r.iframeEnabled) return "iframe"; if (r.pixelEnabled) return "image"; (r); if (i) var u = "https://eb2.3lift.com/sync?"; return "image" === i && (u = o.tryAppendQueryString(u, "px", 1), u = o.tryAppendQueryString(u, "src"https://slate.com/technology/2020/10/,"prebid")), null !== c && (u = o.tryAppendQueryString(u, "gdpr", a), u = o.tryAppendQueryString(u, "cmp_cs", c)), n && (u = o.tryAppendQueryString(u, "us_privacy", n)), [ type: i, url: u ]; }; function f(r, e, t, n) { return r.map((o = e, function (r) return r && r.userId && r.userId[o]; )).filter(function (r) return !!r; ).map((i = t, u = n, function (r) return source: i, uids: [ id: r, ext: rtiPartner: u ] ; )); var i, u, o; } function l(r) return 2 === r.length && "number" == typeof r[0] && "number" == typeof r[1]; Object(i.registerBidder)(s); } }, [761]); pbjsChunk([75], { 763: function _(e, r, t) e.exports = t(764); , 764: function _(e, r, t) { "use strict"; Object.defineProperty(r, "__esModule", value: !0 ), t.d(r, "spec", function () return v; ); var m = t(0), s = t(1), o = t(10), c = t(2), f = "Bid from response has no auid parameter - ", l = "Bid from response has no adm parameter - ", p = "Array of bid objects is empty", g = "Can't find in requested bids the bid with auid - ", u = "Seatbid array from response has empty item", y = "Response is empty", b = "Response has empty seatbid array", h = "Seatbid from response has no array of bid objects - ", v = { code: "trustx", supportedMediaTypes: [c.b, c.d], isBidRequestValid: function isBidRequestValid(e) return !!e.params.uid; , buildRequests: function buildRequests(e, r) []).forEach(function (e) ); var t = pt: l, auids: p.join(","), sizes: m.getKeys(f).join(","), r: o, wrapperType: "Prebid_js", wrapperVersion: "3.23.0" ; return a && (t.keywords = JSON.stringify(a)), r && (r.refererInfo && r.refererInfo.referer && (t.u = r.refererInfo.referer), r.timeout && (t.wtimeout = r.timeout), r.gdprConsent && (r.gdprConsent.consentString && (t.gdpr_consent = r.gdprConsent.consentString), t.gdpr_applies = "boolean" == typeof r.gdprConsent.gdprApplies ? Number(r.gdprConsent.gdprApplies) : 1), r.uspConsent && (t.us_privacy = r.uspConsent)), method: "GET", url: "https://sofia.trustx.org/hb", data: m.parseQueryStringParameters(t).replace(/&$/, ""), bidsMap: u ; , interpretResponse: function interpretResponse(e, r, t) { var s = 2 < arguments.length && void 0 !== t ? t : o.a; e = e && e.body; var n, d = [], i = r.bidsMap, a = r.data.pt; return e ? e.seatbid && !e.seatbid.length && (n = b) : n = y, !n && e.seatbid && e.seatbid.forEach(function (e) { !function (e, d, r, t, s) if (!e) return; var n; e.auid (function (e) m.logError(p) : m.logError(h + JSON.stringify(e)) : m.logError(u); return e && e.bid && e.bid[0]; (e), i, a, d, s); }), n && m.logError(n), d; }, getUserSyncs: function getUserSyncs(e) if (e.pixelEnabled) return [ type: "image", url: "https://sofia.trustx.org/push_sync" ]; }; function E(e) var r; r = e.value, m.isArray(r) && 0 < r.length && "" === e.value[0] && delete e.value; function w(e) e.renderer.push(function () window.ANOutstreamVideo.renderAd( targetId: e.adUnitCode, adResponse: e.adResponse ); ); Object(s.registerBidder)(v); } }, [763]); pbjs.processQueue(); }, ]; window.modules["via.legacy"] = [function(require,module,exports){"use strict"; DS.service("via", function () { "use strict"; // remove `via` from url, to be used after amplitude logs it to prevent users from sharing such urls function removeFromLocation() var url = new URL(location.href); url.searchParams.delete("via"); history.replaceState(null, "", url.toString()); // and add `via` param to any outbound links function addViaToUrl(href, via) // keys correspond to "page_types" in editable_components.yml var PREFIXES = article: "article", homepage: "homepage", "vertical front": "section", "rubric front": "rubric" ; var pageType; function setPageType(amplitudePageType) pageType = PREFIXES[amplitudePageType]; var DELIMITER = "_"; function concatVia(node, via) var tag = node.dataset && node.dataset.via; if (tag) via = (via.length ? tag + DELIMITER : tag) + via; return via; function addToClickedLinks() document.documentElement.addEventListener("click", function (e) var a; var via = ""; // detect link nodes and collect via directives to append to the href var node = e.target; // the element where this event originated may have been removed from the dom, e.g. in the case of the OIL CMP which disappears after you interact with it while (node && node !== e.currentTarget) if (node.tagName === "A") a = node; via = concatVia(node, via); node = node.parentNode; if (a && via) if (pageType) via = pageType + DELIMITER + via; a.href = addViaToUrl(a.href, via); ); function addToSubmittedForms() document.documentElement.addEventListener("submit", function (e) var form = e.target; // collect via directives var via = ""; var node = e.target; while (node !== e.currentTarget) via = concatVia(node, via); node = node.parentNode; if (via) if (pageType) via = pageType + DELIMITER + via; // dynamically create a hidden input for the form url var input = document.createElement("input"); input.type = "hidden"; input.name = "via"; input.value = via; form.appendChild(input); ); // start listening only once, when first injected addToClickedLinks(); addToSubmittedForms(); return setPageType: setPageType, removeFromLocation: removeFromLocation ; }); }, ]; window.modules["visibility.legacy"] = [function(require,module,exports){"use strict"; DS.service("$visibility", ["$document"https://slate.com/technology/2020/10/,"$window"https://slate.com/technology/2020/10/,"_throttle"https://slate.com/technology/2020/10/,"Eventify", function ($document, $window, _throttle, Eventify) var list = [], Visible, VisibleEvent; /** * @param number a * @param number b * @returns * * @see http://jsperf.com/math-min-vs-if-condition-vs/8 */ function min(a, b) return a < b ? a : b; /** * @param number a * @param number b * @returns * * @see http://jsperf.com/math-min-vs-if-condition-vs/8 */ function max(a, b) return a > b ? a : b;

/**
* Fast loop through watched elements
*/

function onScroll()
list.forEach(updateVisibility);

/**
* updates seen property
* @param Visble item
* @param evt
* @fires Visible#shown
* @fires Visible#hidden
*/

function updateSeen(item, evt)
var px = evt.visiblePx,
percent = evt.visiblePercent; // if some pixels are visible and we're greater/equal to threshold

if (px && percent >= item.shownThreshold && !item.seen)
item.seen = true;
setTimeout(function ()
item.trigger("shown", new VisibleEvent("shown", evt));
, 15); // if no pixels or percent is less than threshold
else if ((!px
/**
* sets preload property
* @param Visible item
* @param evt
* @param Number innerHeight
* @fires Visible#preload
*/

function updatePreload(item, evt, innerHeight)
if (!item.preload && item.preloadThreshhold && shouldBePreloaded(evt.target, evt.rect, item.preloadThreshhold, innerHeight))
item.preload = true;
setTimeout(function ()
item.trigger("preload", new VisibleEvent("preload", evt));
, 15);

/**
* Trigger events
* @param Visible item
*/

function updateVisibility(item)
/**
* Return normalized viewport height
* @return number
*/

function getViewportHeight() $document.documentElement.clientHeight
/**
* Return normalized viewport width
* @return number
*/

function getViewportWidth()
return $window.innerWidth
/**
* make sure an element isn't hidden by styles or etc
* @param Element el
* @return Boolean
*/

function isElementNotHidden(el)
return el && el.offsetParent !== null && !el.getAttribute("hidden") && getComputedStyle(el).display !== "none" && getComputedStyle(el).visibility !== "hidden";

/**
* Apparently the fastest way...
* @param Element el
* @returns boolean
* @example if (!$visibility.isElementInViewport(el)) ...
*/

function isElementInViewport(el) $document.documentElement.clientWidth);

/**
* @param Element el
* @param ClientRect rect
* @param Number preloadThreshhold
* @param Number innerHeight
* @return Boolean
*/

function shouldBePreloaded(el, rect, preloadThreshhold, innerHeight)
return rect.top <= innerHeight + preloadThreshhold && isElementNotHidden(el); /** * Create a one-dimensional spacial hash of x * @param number x * @param number stepSize * @param number optimalK * @param number base * @return number */ function getLinearSpacialHash(x, stepSize, optimalK, base) 1)), remainder = x % stepSize, result = index.toString(base); if (optimalK > 1)
result += getLinearSpacialHash(remainder, Math.floor(stepSize / base), optimalK - 1, base);

return result;

/**
* @param ClientRect rect
* @param number innerHeight
* @returns number
*/

function getVerticallyVisiblePixels(rect, innerHeight)
return min(innerHeight, max(rect.bottom, 0)) - min(max(rect.top, 0), innerHeight);

/**
* Get offset of element relative to entire page
*
* @param Element el
* @returns left: number, top: number
* @see http://jsperf.com/offset-vs-getboundingclientrect/7
*/

function getPageOffset(el)
var offsetLeft = el.offsetLeft,
offsetTop = el.offsetTop;

while (el = el.offsetParent)
offsetLeft += el.offsetLeft;
offsetTop += el.offsetTop;

return
left: offsetLeft,
top: offsetTop
;

/**
* Create a new Visible class to observe when elements enter and leave the viewport
*
* Call destroy function to stop listening (this is until we have better support for watching for Node Removal)
* @param Element el
* @param shownThreshold: number, hiddenThreshold: number [options]
* @class
* @example this.visible = new $visibility.Visible(el);
*/

Visible = function Visible(el, options) ;
this.el = el;
this.seen = false;
this.preload = false;
this.preloadThreshhold = options && options.preloadThreshhold ;

Visible.prototype =
/**
* Stop triggering.
*/
destroy: function destroy()
// remove from list
list.splice(list.indexOf(this), 1);

/**
* @name Visible#on
* @function
* @param 'shown' e EventName
* @param function cb Callback
*/

/**
* @name Visible#trigger
* @function
* @param 'hidden' e
* @param
*/

;
Eventify.enable(Visible.prototype);

VisibleEvent = function VisibleEvent(type, options)
var _this = this;

this.type = type;
Object.keys(options).forEach(function (key)
_this[key] = options[key];
);
; // listen for scroll events (throttled)

$document.addEventListener("scroll", _throttle(onScroll, 200)); // public

this.getPageOffset = getPageOffset;
this.getLinearSpacialHash = getLinearSpacialHash;
this.getVerticallyVisiblePixels = getVerticallyVisiblePixels;
this.getViewportHeight = getViewportHeight;
this.getViewportWidth = getViewportWidth;
this.isElementNotHidden = isElementNotHidden;
this.isElementInViewport = isElementInViewport;
this.Visible = Visible;
]);
}, ];
require=(function e(t,n,r){function s(o,u){if(!n[o])if(!t[o])var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",fvar l=n[o]=exports:;t[o][0].call(l.exports,function(e)var n=t[o][1][e];return s(n?n:e),l,l.exports,e,t,n,r)return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o