1/* global ET */ 2(function () { 3 if (!window.ET) window.ET = {}; 4 5 /** @type {Record<string, string>} supersolidD|solidD|likelyD|leanD|tiltD|tossup|tiltR|leanR|likelyR|solidR|supersolidR */ 6 ET.SENATE_EDITORIAL_RATINGS = { 7 AK: 'leanD', AL: 'solidR', AR: 'supersolidR', CO: 'supersolidD', DE: 'solidD', FL: 'likelyR', 8 GA: 'tiltD', IA: 'solidR', ID: 'solidR', IL: 'solidD', KS: 'solidR', KY: 'solidR', 9 LA: 'supersolidR', MA: 'solidD', ME: 'tiltD', MI: 'likelyR', MN: 'likelyD', MS: 'solidR', 10 MT: 'likelyR', NC: 'leanD', NE: 'leanR', NH: 'likelyD', NJ: 'solidD', NM: 'supersolidD', 11 OH: 'likelyR', OK: 'solidR', OR: 'solidD', RI: 'solidD', SC: 'solidR', SD: 'solidR', 12 TN: 'solidR', TX: 'leanR', VA: 'solidD', WV: 'solidR', WY: 'solidR' 13 }; 14 15 /** Senate forecast blend / simulation cook tier (may differ from display SENATE_EDITORIAL_RATINGS). */ 16 ET.SENATE_EDITORIAL_RATINGS_BASE = (function () { 17 var base = Object.assign({}, ET.SENATE_EDITORIAL_RATINGS); 18 base.FL = 'solidR'; 19 base.NE = 'likelyR'; 20 base.ME = 'solidR'; 21 base.MI = 'likelyR'; 22 base.TX = 'supersolidR'; 23 return base; 24 })(); 25 26 /** 27 * Senate blend tier applies only on/after this calendar date (YYYY-MM-DD). 28 * Before the date, SENATE_EDITORIAL_BLEND_PRIOR (if set) else SENATE_EDITORIAL_RATINGS is used. 29 */ 30 ET.SENATE_EDITORIAL_BLEND_EFFECTIVE_FROM = { 31 ME: '2026-06-07', 32 MI: '2026-06-08' 33 }; 34 35 /** Pre-effective-date cook tier when display SENATE_EDITORIAL_RATINGS already reflects the new rating. */ 36 ET.SENATE_EDITORIAL_BLEND_PRIOR = { 37 MI: 'tiltD' 38 }; 39 40 /** 41 * Senate-only cook-component margin overrides (rare). 42 * All other states use ET.INPUT_RATING_TO_MARGIN via editorial rating tier. 43 */ 44 ET.SENATE_EDITORIAL_BLEND_MARGINS = {}; 45 46 /** Bump when blend inputs change â busts race-page + hub forecast localStorage caches. */ 47 ET.SENATE_EDITORIAL_BLEND_REVISION = 39; 48 49 /** House flip stripes vs rating: held-seat party baseline (2026 map, redistricting-aware). */ 50 ET.HOUSE_FLIP_HELD_PARTY_BY_CODE = { 51 'AL-2': 'D', 52 'LA-6': 'D', 53 }; 54 55 /** Senate flip stripes vs rating: held-seat party baseline (open seats + overrides). */ 56 ET.SENATE_EDITORIAL_FLIP_INCUMBENT_PARTY = { 57 ME: 'R', 58 AL: 'R', IA: 'R', IL: 'D', KY: 'R', LA: 'R', MI: 'D', MN: 'D', MT: 'R', NH: 'D', 59 NC: 'R', OK: 'R', TX: 'R', WY: 'R' 60 }; 61 62 /** @type {Record<string, string>} */ 63 ET.GOV_EDITORIAL_RATINGS = { 64 AK: 'solidR', AL: 'supersolidR', AR: 'solidR', AZ: 'leanD', CA: 'solidD', CO: 'solidD', 65 CT: 'supersolidD', FL: 'solidR', GA: 'leanR', HI: 'solidD', IA: 'leanR', ID: 'solidR', 66 IL: 'supersolidD', KS: 'likelyR', MA: 'solidD', MD: 'solidD', ME: 'likelyD', MI: 'tiltD', MN: 'solidD', 67 NE: 'solidR', NH: 'supersolidR', NM: 'likelyD', NV: 'likelyR', NY: 'solidD', OH: 'leanR', 68 OK: 'supersolidR', OR: 'solidD', PA: 'solidD', RI: 'solidD', SC: 'supersolidR', SD: 'supersolidR', 69 TN: 'supersolidR', TX: 'likelyR', VT: 'solidR', WI: 'leanR', WY: 'supersolidR' 70 }; 71 72 /** Governor forecast blend / simulation cook tier (may differ from display GOV_EDITORIAL_RATINGS). */ 73 ET.GOV_EDITORIAL_RATINGS_BASE = (function () { 74 var base = Object.assign({}, ET.GOV_EDITORIAL_RATINGS); 75 base.GA = 'likelyR'; 76 base.OH = 'solidR'; 77 return base; 78 })(); 79 80 /** Governor-only cook-component margin overrides (rare); else INPUT_RATING_TO_MARGIN. */ 81 ET.GOV_EDITORIAL_BLEND_MARGINS = {}; 82 83 ET.GOV_EDITORIAL_BLEND_REVISION = 25; 84 85 ET.EDITORIAL_RATING_FILL = { 86 supersolidD: '#0c6df6', 87 solidD: '#0c6df6', 88 likelyD: '#469fff', 89 leanD: '#89c3ff', 90 tiltD: '#bdddff', 91 tossup: '#c4b5fd', 92 leanR: '#ffa7a8', 93 likelyR: '#fc6969', 94 solidR: '#f42726', 95 supersolidR: '#f42726', 96 tiltR: '#ffd2d2' 97 }; 98 99 ET.editorialRatingLabel = function (rating) { 100 var map = { 101 megaSolidD: 'Mega Solid D', megaSolidR: 'Mega Solid R', 102 ultraSolidD: 'Ultra Solid D', ultraSolidR: 'Ultra Solid R',
103 supersolidD: 'Super Solid D', supersolidR: 'Super Solid R', 104 solidD: 'Solid D', likelyD: 'Likely D', leanD: 'Lean D', tiltD: 'Tilt D', 105 tossup: 'Tossup', 106 leanR: 'Lean R', likelyR: 'Likely R', solidR: 'Solid R', tiltR: 'Tilt R' 107 }; 108 return map[rating] || ''; 109 }; 110 111 ET.editorialRatingTierWord = function (rating) { 112 if (rating && rating.indexOf('megaSolid') === 0) return 'Mega Solid'; 113 if (rating && rating.indexOf('ultraSolid') === 0) return 'Ultra Solid'; 114 if (rating === 'supersolidD' || rating === 'supersolidR') return 'Super Solid'; 115 var tier = ET.editorialRatingToMarginTier(rating); 116 if (tier === 'solid') return 'Solid'; 117 if (tier === 'likely') return 'Likely'; 118 if (tier === 'lean') return 'Lean'; 119 if (tier === 'tilt') return 'Tilt'; 120 return ''; 121 }; 122 123 /** Chip label: tier word (600) + one space + party letter (800). */ 124 ET.editorialRatingChipLabelInnerHtml = function (rating) { 125 var lead = ET.editorialRatingPartyLead(rating); 126 var tierWord = ET.editorialRatingTierWord(rating); 127 if (!lead || lead === 'Tie' || !tierWord) { 128 return ET.escapeHtml ? ET.escapeHtml(ET.editorialRatingLabel(rating)) : ET.editorialRatingLabel(rating); 129 } 130 var tierHtml = tierWord; 131 var partyHtml = lead; 132 if (ET.escapeHtml) { 133 tierHtml = ET.escapeHtml(tierWord); 134 partyHtml = ET.escapeHtml(lead); 135 } 136 return '<span style="font-weight:600;font-style:normal;">' + tierHtml + '</span>' + 137 ' <span style="font-weight:800;font-style:normal;">' + partyHtml + '</span>'; 138 }; 139 140 ET.editorialRatingPartyLead = function (rating) { 141 if (!rating || rating === 'tossup') return rating === 'tossup' ? 'Tie' : null; 142 if (rating.indexOf('D') !== -1) return 'D'; 143 if (rating.indexOf('R') !== -1) return 'R'; 144 return null; 145 }; 146 147 /** Race Overview / snapshot: color forecast rating by leading party (Lean D, Tilt R, etc.). */ 148 ET.formatRaceSnapshotForecastRatingHtml = function (rating) { 149 if (rating == null || rating === '' || rating === 'â') { 150 return ET.escapeHtml ? ET.escapeHtml('â') : 'â'; 151 } 152 var label = ET.editorialRatingLabel && ET.editorialRatingLabel(rating) 153 ? ET.editorialRatingLabel(rating) 154 : String(rating); 155 var lead = ET.editorialRatingPartyLead(rating); 156 if (!lead || lead === 'Tie') { 157 return ET.escapeHtml ? ET.escapeHtml(label) : label; 158 } 159 var cls = lead === 'R' ? 'race-snapshot__party--r' : 'race-snapshot__party--d'; 160 var escaped = ET.escapeHtml ? ET.escapeHtml(label) : label; 161 return '<span class="race-snapshot__party ' + cls + '">' + escaped + '</span>'; 162 }; 163 164 ET.editorialRatingToMarginTier = function (rating) { 165 if (!rating || rating === 'tossup') return 'tilt'; 166 if (rating.indexOf('megaSolid') === 0) return 'solid'; 167 if (rating.indexOf('ultraSolid') === 0) return 'solid'; 168 if (rating.indexOf('supersolid') === 0) return 'solid'; 169 if (rating.indexOf('solid') === 0) return 'solid'; 170 if (rating.indexOf('likely') === 0) return 'likely'; 171 if (rating.indexOf('lean') === 0) return 'lean'; 172 if (rating.indexOf('tilt') === 0) return 'tilt'; 173 return 'solid'; 174 }; 175 176 ET.editorialRatingFill = function (rating) { 177 if (!rating) return '#121820'; 178 return ET.EDITORIAL_RATING_FILL[rating] || '#121820'; 179 }; 180 181 /** Map fill from editorial rating (ratings mode, or polling mode when there is no GE average). */ 182 ET.forecastHubEditorialRatingStateFill = function (kind, key, name, ui) { 183 ui = ui || { showFlips: true, showMargins: false }; 184 if (kind === 'senate' && ui.showFlips && 185 typeof ET.senateHubMapFlipPatternFill === 'function') { 186 var senateFlipFill = ET.senateHubMapFlipPatternFill(name, key, ui); 187 if (senateFlipFill) return senateFlipFill; 188 } 189 var ratingsMode = ui.mapSource === 'ratings'; 190 if (typeof ET.forecastHubModelStateFill === 'function') { 191 var modelFill = ET.forecastHubModelStateFill(kind, key, name, ui); 192 if (modelFill) return modelFill; 193 } 194 var ratings = kind === 'gov' ? ET.GOV_EDITORIAL_RATINGS : ET.SENATE_EDITORIAL_RATINGS;
195 if (!ratings || !key) return null; 196 var rating = ratings[key]; 197 if (!rating) return null; 198 if (rating === 'tossup') { 199 // Governors: never purple/gray tossup â tilt to party holding the seat. 200 if (kind === 'gov') { 201 var heldTossup = (typeof ET.govFlipBaselineParty === 'function' && ET.govFlipBaselineParty(key)) 202 || (ET.GOV_INCUMBENT_PARTY && ET.GOV_INCUMBENT_PARTY[key]) 203 || 'R'; 204 if (heldTossup !== 'D' && heldTossup !== 'R') heldTossup = 'R'; 205 if (typeof ET.forecastHubMapUsesTierColors === 'function' 206 ? ET.forecastHubMapUsesTierColors(ui) 207 : !!ui.showMargins) { 208 return typeof ET.forecastHubMarginFill === 'function' 209 ? ET.forecastHubMarginFill(heldTossup, 'tilt') 210 : (heldTossup === 'D' ? ET.COLORS.BLUE : ET.COLORS.RED); 211 } 212 return heldTossup === 'D' ? ET.COLORS.BLUE : ET.COLORS.RED; 213 } 214 return ET.editorialRatingFill('tossup'); 215 } 216 var lead = ET.editorialRatingPartyLead(rating); 217 var tier = ET.editorialRatingToMarginTier(rating); 218 var flip = ET.editorialRatingFlipLead(kind, key, rating, name); 219 var useTierColors = typeof ET.forecastHubMapUsesTierColors === 'function' 220 ? ET.forecastHubMapUsesTierColors(ui) 221 : !!ui.showMargins; 222 if (useTierColors) { 223 if (ui.showFlips && flip && typeof ET.forecastHubMarginFlipPatternId === 'function') { 224 return 'url(#' + ET.forecastHubMarginFlipPatternId(kind, flip, tier) + ')'; 225 } 226 if (typeof ET.forecastHubMarginFill === 'function') { 227 return ET.forecastHubMarginFill(lead, tier); 228 } 229 } 230 if (typeof ET.forecastHubSimpleMapPartyFill === 'function') { 231 return ET.forecastHubSimpleMapPartyFill(kind, lead, flip, ui); 232 } 233 return lead === 'D' ? ET.COLORS.BLUE : ET.COLORS.RED; 234 }; 235 236 ET.senateEditorialIncumbentParty = function (stateName, stateKey) { 237 if (typeof ET.senateFlipBaselineParty === 'function') { 238 var held = ET.senateFlipBaselineParty(stateKey, stateName); 239 if (held === 'D' || held === 'R') return held; 240 } 241 if (ET.SENATE_EDITORIAL_FLIP_INCUMBENT_PARTY && stateKey && ET.SENATE_EDITORIAL_FLIP_INCUMBENT_PARTY[stateKey]) { 242 return ET.SENATE_EDITORIAL_FLIP_INCUMBENT_PARTY[stateKey]; 243 } 244 if (stateKey && ET.NAME_BY_KEY && ET.INCUMBENT_2026) { 245 var nmKey = ET.NAME_BY_KEY[stateKey]; 246 if (nmKey && ET.INCUMBENT_2026[nmKey] != null) { 247 return ET.INCUMBENT_2026[nmKey] === 'R' ? 'R' : 'D'; 248 } 249 } 250 if (!stateName || !ET.INCUMBENT_2026) return 'D'; 251 return ET.INCUMBENT_2026[stateName] === 'R' ? 'R' : 'D'; 252 }; 253 254 ET.editorialRatingFlipLead = function (kind, stateKey, rating, stateName) { 255 var lead = ET.editorialRatingPartyLead(rating); 256 if (!lead || lead === 'Tie') return null; 257 var inc = 'D'; 258 if (kind === 'senate') { 259 inc = ET.senateEditorialIncumbentParty(stateName, stateKey); 260 } else if (kind === 'gov') { 261 if (stateKey && ET.GOV_INCUMBENT_FULL_2026 && ET.GOV_INCUMBENT_FULL_2026[stateKey]) { 262 inc = ET.GOV_INCUMBENT_FULL_2026[stateKey].party; 263 } else { 264 var ge = ET.forecastHubGeBaseline && ET.forecastHubGeBaseline('gov', stateKey); 265 if (ge && (ge.w === 'R' || ge.w === 'D')) inc = ge.w; 266 } 267 } else if (kind === 'house') { 268 return null; 269 } 270 return lead === inc ? null : lead; 271 }; 272 273 ET.sleekHoverEditorialRatingChipHtml = function (rating, flip) { 274 var lead = ET.editorialRatingPartyLead(rating); 275 if (!lead || lead === 'Tie') { 276 return ET.sleekHoverChipHtml ? ET.sleekHoverChipHtml('Tie', 0) : ''; 277 } 278 var fullD = ET.COLORS.BLUE; 279 var fullR = ET.COLORS.RED; 280 var liteB = ET.SENATE_FLIP_CHIP_LIGHT_BLUE || '#2990f7'; 281 var liteR = ET.SENATE_FLIP_LIGHT_RED || '#fb6868'; 282 var chipOutline = flip 283 ? (ET.sleekMarginChipOutlineCss ? ET.sleekMarginChipOutlineCss(true) : 'box-shadow:inset 0 0 0 1px #ffffff;') 284 : 'box-shadow:inset 0 0 0 1px rgba(255,255,255,.38);'; 285 var baseCore = 'display:inline-block;box-sizing:border-box;font-size:14px;font-weight:800;letter-spacing:0.04em;padding:3px 10px;border-radius:6px;color:#fff;border:none;filter:none;text-shadow:none;' + chipOutline;
286 var labelInner = ET.editorialRatingChipLabelInnerHtml 287 ? ET.editorialRatingChipLabelInnerHtml(rating) 288 : ET.editorialRatingLabel(rating); 289 var inner = '<span style="position:relative;top:1px;display:inline-block">' + labelInner + '</span>'; 290 var bandPx = 7; 291 var seamPx = 0.45; 292 var ang = '-45deg'; 293 var bgStyle; 294 if (flip) { 295 if (lead === 'D') { 296 bgStyle = 'repeating-linear-gradient(' + ang + ',' + fullD + ' 0,' + fullD + ' ' + (bandPx + seamPx) + 'px,' + liteB + ' ' + (bandPx - seamPx) + 'px,' + liteB + ' ' + (bandPx * 2) + 'px)'; 297 } else { 298 bgStyle = 'repeating-linear-gradient(' + ang + ',' + fullR + ' 0,' + fullR + ' ' + (bandPx + seamPx) + 'px,' + liteR + ' ' + (bandPx - seamPx) + 'px,' + liteR + ' ' + (bandPx * 2) + 'px)'; 299 } 300 } else { 301 bgStyle = lead === 'D' ? fullD : fullR; 302 } 303 return '<span style="' + baseCore + 'background:' + bgStyle + '">' + inner + '</span>'; 304 }; 305 306 ET.hubEditorialRatingChipHtml = function (kind, stateKey, stateName, rating, priorParty) { 307 if (!rating) return ''; 308 var flip = null; 309 if (kind === 'house' && priorParty) { 310 var lead = ET.editorialRatingPartyLead(rating); 311 if (lead && lead !== 'Tie' && priorParty !== lead) flip = lead; 312 } else if (typeof ET.editorialRatingFlipLead === 'function') { 313 flip = ET.editorialRatingFlipLead(kind, stateKey, rating, stateName); 314 } 315 return ET.sleekHoverEditorialRatingChipHtml(rating, !!flip); 316 }; 317 318 ET.countSenateSeatsFromEditorialRatings = function () { 319 var r = ET.NOT_UP_BASE_R || 0; 320 var d = ET.NOT_UP_BASE_D || 0; 321 var toss = 0; 322 if (!ET.ELECTION_2026) return { r: r, d: d, tossup: toss }; 323 for (var f in ET.ELECTION_2026) { 324 if (!ET.ELECTION_2026.hasOwnProperty(f)) continue; 325 var nm = ET.NAME_BY_FIPS[f]; 326 var key = ET.KEY_BY_NAME[nm]; 327 var rating = ET.SENATE_EDITORIAL_RATINGS && ET.SENATE_EDITORIAL_RATINGS[key]; 328 var lead = ET.editorialRatingPartyLead(rating); 329 if (lead === 'Tie') toss++; 330 else if (lead === 'R') r++; 331 else if (lead === 'D') d++; 332 } 333 return { r: r, d: d, tossup: toss }; 334 }; 335 336 ET.govEditorialNoElectionKeys = function () { 337 return new Set(['WA', 'UT', 'ND', 'MO', 'LA', 'MS', 'IN', 'KY', 'WV', 'VA', 'NC', 'DE', 'NJ', 'MT']); 338 }; 339 340 ET.countGovSeatsFromEditorialRatings = function () { 341 var notUp = ET.forecastHubNotUpCounts('gov'); 342 var r = notUp.r; 343 var d = notUp.d; 344 var toss = 0; 345 var skip = ET.govEditorialNoElectionKeys(); 346 var ratings = ET.GOV_EDITORIAL_RATINGS || {}; 347 Object.keys(ratings).forEach(function (key) { 348 if (skip.has(key)) return; 349 var lead = ET.editorialRatingPartyLead(ratings[key]); 350 if (lead === 'Tie') { 351 // Never gray for governors â assign to party holding the seat. 352 var held = (typeof ET.govFlipBaselineParty === 'function' && ET.govFlipBaselineParty(key)) 353 || (ET.GOV_INCUMBENT_PARTY && ET.GOV_INCUMBENT_PARTY[key]) 354 || 'R'; 355 if (held === 'D') d++; 356 else r++; 357 } else if (lead === 'R') r++; 358 else if (lead === 'D') d++; 359 }); 360 return { r: r, d: d, tossup: toss }; 361 }; 362 363 /** Flip seat counts for hub seat bar (ratings, no detail): stripe width â seats gained by each party. */ 364 ET.countEditorialFlipSeats = function (kind) { 365 var flipR = 0; 366 var flipD = 0; 367 if (kind === 'gov') { 368 if (!ET.GOV_EDITORIAL_RATINGS || typeof ET.editorialRatingFlipLead !== 'function') { 369 return { flipR: flipR, flipD: flipD }; 370 } 371 var skipGov = ET.govEditorialNoElectionKeys(); 372 Object.keys(ET.GOV_EDITORIAL_RATINGS).forEach(function (key) { 373 if (skipGov.has(key)) return; 374 var fl = ET.editorialRatingFlipLead('gov', key, ET.GOV_EDITORIAL_RATINGS[key], null); 375 if (fl === 'R') flipR++; 376 else if (fl === 'D') flipD++; 377 }); 378 } else if (kind === 'senate') { 379 if (!ET.ELECTION_2026 || typeof ET.editorialRatingFlipLead !== 'function') { 380 return { flipR: flipR, flipD: flipD }; 381 } 382 for (var f in ET.ELECTION_2026) { 383 if (!ET.ELECTION_2026.hasOwnProperty(f)) continue;
384 var nm = ET.NAME_BY_FIPS[f]; 385 var keySen = ET.KEY_BY_NAME[nm]; 386 if (!keySen || !ET.SENATE_EDITORIAL_RATINGS || !ET.SENATE_EDITORIAL_RATINGS[keySen]) continue; 387 var flSen = ET.editorialRatingFlipLead('senate', keySen, ET.SENATE_EDITORIAL_RATINGS[keySen], nm); 388 if (flSen === 'R') flipR++; 389 else if (flSen === 'D') flipD++; 390 } 391 } 392 return { flipR: flipR, flipD: flipD }; 393 }; 394 395 ET.forecastHubEditorialSeatCounts = function (kind) { 396 if (kind === 'gov') { 397 if (typeof ET.countGovSeatsFromForecastSim === 'function') { 398 var govSim = ET.countGovSeatsFromForecastSim(); 399 if (govSim) return govSim; 400 } 401 if (typeof ET.countGovSeatsFromEditorialRatings === 'function') { 402 return ET.countGovSeatsFromEditorialRatings(); 403 } 404 return null; 405 } 406 if (typeof ET.countSenateSeatsFromForecastSim === 'function') { 407 var senSim = ET.countSenateSeatsFromForecastSim(); 408 if (senSim) return senSim; 409 } 410 if (typeof ET.countSenateSeatsFromEditorialRatings === 'function') { 411 return ET.countSenateSeatsFromEditorialRatings(); 412 } 413 return null; 414 }; 415 416 ET.setForecastHubSeatBarPartyNumbers = function (ids, kind) { 417 if (!ids) return; 418 var counts = ET.forecastHubEditorialSeatCounts(kind); 419 if (!counts) return; 420 var nr = document.getElementById(ids.nr); 421 var nd = document.getElementById(ids.nd); 422 if (nr) nr.textContent = String(counts.r); 423 if (nd) nd.textContent = String(counts.d); 424 }; 425 426 ET.senateForecastHubRaceSlotFromRating = function (name, key) { 427 var rating = ET.SENATE_EDITORIAL_RATINGS && ET.SENATE_EDITORIAL_RATINGS[key]; 428 if (!rating) return null; 429 var lead = ET.editorialRatingPartyLead(rating); 430 var winner = lead === 'Tie' ? 'TIE' : lead; 431 var tier = ET.editorialRatingToMarginTier(rating); 432 var flip = !!(ET.editorialRatingFlipLead('senate', key, rating, name)); 433 return { 434 winner: winner, 435 tier: tier, 436 flip: flip, 437 hasPolls: false, 438 key: key, 439 name: name, 440 marginAbs: 0, 441 editorialRating: rating 442 }; 443 }; 444 445 ET.govForecastHubRaceSlotFromRating = function (key) { 446 var rating = ET.GOV_EDITORIAL_RATINGS && ET.GOV_EDITORIAL_RATINGS[key]; 447 if (!rating) return null; 448 var lead = ET.editorialRatingPartyLead(rating); 449 var winner = lead === 'Tie' ? 'TIE' : lead; 450 var tier = ET.editorialRatingToMarginTier(rating); 451 // Never gray/TIE for governors â perfect tossup â party holding the governorship. 452 if (winner === 'TIE') { 453 var held = (typeof ET.govFlipBaselineParty === 'function' && ET.govFlipBaselineParty(key)) 454 || (ET.GOV_INCUMBENT_PARTY && ET.GOV_INCUMBENT_PARTY[key]) 455 || 'R'; 456 winner = (held === 'D' || held === 'R') ? held : 'R'; 457 tier = 'tilt'; 458 rating = winner === 'D' ? 'tiltD' : 'tiltR'; 459 } 460 var flip = !!(ET.editorialRatingFlipLead('gov', key, rating, null)); 461 return { 462 winner: winner, 463 tier: tier, 464 flip: flip, 465 hasPolls: false, 466 key: key, 467 marginAbs: 0, 468 editorialRating: rating 469 }; 470 }; 471 472 /** Load Cook PVI + forecast model stack on race pages (hubs include these explicitly). */ 473 if (!window.POLLSMAX_SKIP_FORECAST_MODEL) { 474 (function () { 475 var path = typeof location !== 'undefined' ? location.pathname : ''; 476 var onForecastPage = /\/forecast\/?$/.test(path); 477 if (onForecastPage) { 478 window.POLLSMAX_SKIP_FORECAST_MODEL = true; 479 return; 480 } 481 var chain = [ 482 '/assets/generic-ballot-polls-data.js?v=7', 483 '/assets/trump-approval-polls-data.js?v=7', 484 '/assets/cook-pvi-data.js?v=1', 485 '/assets/cook-race-ratings.js?v=2', 486 '/assets/forecast-senate-electoral.js?v=3', 487 '/assets/forecast-governor-electoral.js?v=2', 488 '/assets/forecast-model.js?v=ia-gov-tilt-r-1', 489 '/assets/forecast-calibration.js?v=forecast-cache-gov-rebuild-20260620'
490 ]; 491 function loadNext(i) { 492 if (i >= chain.length) { 493 if (typeof ET.applyForecastModelRatings === 'function') { 494 ET.applyForecastModelRatings(); 495 } 496 if (typeof ET.refreshStateRacePageHeadFromForecast === 'function' && 497 typeof ET.racePageViewMode === 'function' && 498 ET.racePageViewMode() === 'forecast') { 499 ET.refreshStateRacePageHeadFromForecast(); 500 } 501 return; 502 } 503 var s = document.createElement('script'); 504 s.src = chain[i]; 505 s.defer = true; 506 s.onload = function () { loadNext(i + 1); }; 507 document.head.appendChild(s); 508 } 509 loadNext(0); 510 })(); 511 } 512 513 function stableRatingDictString(obj) { 514 if (!obj || typeof obj !== 'object') return '{}'; 515 return '{' + Object.keys(obj).sort().map(function (k) { 516 return JSON.stringify(k) + ':' + JSON.stringify(obj[k]); 517 }).join(',') + '}'; 518 } 519 520 /** Hash of editorial / Cook inputs that affect forecast blend â busts baked charts when ratings change. */ 521 ET.editorialRatingsBakeFingerprint = function () { 522 var parts = [ 523 stableRatingDictString(ET.SENATE_EDITORIAL_RATINGS_BASE), 524 stableRatingDictString(ET.SENATE_EDITORIAL_BLEND_EFFECTIVE_FROM || {}), 525 stableRatingDictString(ET.SENATE_EDITORIAL_BLEND_PRIOR || {}), 526 stableRatingDictString(ET.SENATE_EDITORIAL_BLEND_MARGINS || {}), 527 stableRatingDictString(ET.GOV_EDITORIAL_RATINGS), 528 stableRatingDictString(ET.GOV_EDITORIAL_BLEND_MARGINS || {}), 529 stableRatingDictString(ET.COOK_HOUSE_RATINGS || {}) 530 ]; 531 var s = parts.join('|'); 532 var h = 2166136261; 533 var i; 534 for (i = 0; i < s.length; i++) { 535 h ^= s.charCodeAt(i); 536 h = Math.imul(h, 16777619); 537 } 538 return (h >>> 0).toString(36); 539 }; 540})();
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.