{"version":3,"sources":["webpack:///./app/scripts/components/OtherCandidate.js","webpack:///./app/scripts/components/Contest.tsx","webpack:///./app/scripts/components/FramesChild.js","webpack:///./app/scripts/components/HeadshotCandidateRow.tsx","webpack:///./app/scripts/utils/format-percent.ts","webpack:///./config/modern-polyfills.js","webpack:///./app/scripts/endpoints.ts","webpack:///./app/scripts/utils/load-json-script.js","webpack:///./app/scripts/utils/sum-values.js","webpack:///./app/scripts/constants.ts","webpack:///./app/scripts/election-utils.ts","webpack:///./app/scripts/utils/get-json.js","webpack:///./app/scripts/utils/shallow-equal.ts","webpack:///./app/scripts/components/PureComponent.tsx","webpack:///../src/utils.mjs","webpack:///../src/constants.mjs","webpack:///../src/framer.mjs","webpack:///../src/frames.mjs","webpack:///./app/scripts/components/PartyPill.tsx"],"names":["OtherCandidate","isViewable","candidateCount","embedType","onClick","classes","cx","class","xlinkHref","Contest","Component","constructor","super","this","state","viewAllCandidates","onViewableToggle","bind","setState","prevState","render","candidates","contest","columnCount","contestTitle","isShowcaseRace","renderCandidate","partyName","annotations","notes","tableHeader","isHomepage","asOf","source","candidatesRender","props","converter","PreactHTMLConverter","shouldDisplayResult","contest_result","CandidatesShown","visibleCandidatesCount","uncontested","candidacies","length","uncontestedNoHouse","office","totalVotes","sumValues","sort_candidates_by_party","pct_votes","formatPercent","DDHQestimatedvotes","pct_votes_turnout","pct_votes_turnout_w_uncontested","text_conditionals","pct_votes_explain","ManualoverrideSource","showcaseClass","seat__races","seat__highlight_races","rowClass","klaxon","alert_winners","alert_conditionals","checkClass","party","contestMetricsClass","homepage__metrics","precinctsClass","IsAnnotations","value","IsNoted","isCanvass","intcomma","pollinglocationsreporting","total_pollinglocations","pollinglocations_reporting_percent","toFixed","map","candidate","idx","convert","aria-hidden","defaultProps","includeCountyRundown","FramesChild","ref","createRef","polling","componentDidMount","initFrameAndPoll","componentDidUpdate","sendFrameHeight","klass","children","HeadshotCandidateRow","PureComponent","getColor","ballotName","candidateId","contestIsCalled","contestResult","isIncumbent","isWinner","totalVotesInContest","candidateColors","votes","divStyle","filter","obj","name","color","checkStyle","IsAsterisk","style","title","isCalled","Header","colSpan","n","d","require","HOMEPAGE_URL","STORY_API_URL","id","showBubbleMap","showCategoriesMap","showPrecinctsReporting","RESULTS_IN_USE","loadJsonScript","elementId","element","document","getElementById","getAttribute","JSON","parse","textContent","arr","key","reduce","acc","LENGTH_OF_CHECK_INTERVAL","journalize","lastUpdatedFormat","now","apdate","formatted_time","aptime","apmonth","getDate","timer","chunk","size","_","i","push","slice","delay","callback","ms","clearTimeout","setTimeout","PARTY_SORT_ORDER","sort","a","b","indexOf","vote_pct","cand_num","context","label_conditionals","result","totals","winner_conditionals","determineDistrictTitle","division_type","office_division","capfirst","trim","determineContestTitle","determineContestTitleYourRaces","jsonResponse","res","ok","Error","status","statusText","json","getJSON","input","init","fetch","then","hOP","Object","prototype","hasOwnProperty","is","x","y","shallowEqual","objA","objB","keysA","keys","keysB","call","shouldComponentUpdate","const","extend","let","EMBED_SIZE","Framer","container","src","allowfullscreen","referrerpolicy","sandbox","processMessage_","window","addEventListener","createIframe_","height","data","documentElement","offsetHeight","parent","postMessage","sentinel","AMP_SENTINEL","initFrame","cb","removeEventListener","setInterval","sendHeightOnPoll","remove","removeChild","iframe","createElement","setAttribute","appendChild","event","contentWindow","type","setIframeHeight_","PartyPill","excludeInitial","partyPrefix","toLowerCase","partyInitial","toUpperCase","memoize"],"mappings":"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","file":"3.c536eb539b.mjs","sourcesContent":["import cx from 'classnames';\nimport { h } from 'preact';\n\nfunction OtherCandidate({ isViewable, candidateCount, embedType, onClick }) {\n  const classes = cx('candidate race__candidate-row', {\n    'race__candidate-row--hidden': !isViewable,\n  });\n\n  return (\n    <tr class={classes}>\n      <td\n        class=\"candidate__cell candidate__party t-align-center\"\n        onClick={onClick}\n      >\n        <svg class=\"icon icon-angle-down\">\n          <use xlinkHref=\"#icon-angle-down\" />\n        </svg>\n      </td>\n      <th class=\"candidate__cell candidate__name\">\n        <button class={embedType} onClick={onClick}>\n          Show All ({candidateCount}){' '}\n        </button>\n      </th>\n      <th class=\"candidate__cell candidate__votes\"></th>\n      <th class=\"candidate__cell candidate__pct\"></th>\n    </tr>\n  );\n}\n\nexport default OtherCandidate;\n","import cx from 'classnames';\nimport { intcomma } from 'journalize';\nimport { Component, h } from 'preact';\n\nimport OtherCandidate from './OtherCandidate';\nimport { PreactHTMLConverter } from 'preact-html-converter';\n\n// internal\nimport {\n  alert_conditionals,\n  alert_winners,\n  text_conditionals,\n  sort_candidates_by_party,\n} from '../election-utils';\nimport sumValues from '../utils/sum-values';\nimport formatPercent from '../utils/format-percent';\n\nimport { isCanvass, visibleCandidatesCount, DDHQestimatedvotes } from '../endpoints';\n\ntype Props = {\n  contest: { [key: string]: any };\n  columnCount: number;\n  contestTitle: string;\n  includeCountyRundown?: boolean;\n  isShowcaseRace?: boolean;\n  renderParty: any;\n  renderCandidate: any;\n  candidatesRender: any;\n  embedType: string;\n  broadcastHeaderImage: string;\n  activeContestId: string;\n  partyName: string;\n  tableHeader: JSX.Element;\n  annotations: { [key: string]: any };\n  notes: { [key: string]: any };\n  isHomepage?: boolean;\n  asOf: string;\n  source: string;\n};\n\nclass Contest extends Component<Props> {\n  constructor() {\n    super();\n\n    this.state = {\n      viewAllCandidates: false,\n    };\n    this.onViewableToggle = this.onViewableToggle.bind(this);\n  }\n\n  onViewableToggle() {\n    this.setState(prevState => ({\n      viewAllCandidates: !prevState.viewAllCandidates, // set viewAllCandidates to what is wasn't before\n    }));\n  }\n  render() {\n    const {\n      contest,\n      columnCount,\n      contestTitle,\n      isShowcaseRace,\n      renderCandidate,\n      partyName,\n      annotations,\n      notes,\n      tableHeader,\n      isHomepage,\n      asOf,\n      source,\n      embedType,\n      candidatesRender,\n    } = this.props;\n\n    const { viewAllCandidates } = this.state;\n\n    const converter = PreactHTMLConverter();\n\n    const shouldDisplayResult = contest.contest_result !== 'not called';\n\n    let CandidatesShown = isHomepage ? 2 : visibleCandidatesCount\n\n    // Get uncontested races that are not state races because we won't be receiving votes for those races\n\n    // Uncontested are going to be called regardless of being marked as winners\n\n    const uncontested = contest.candidacies.length == 1;\n\n    const uncontestedNoHouse = contest.candidacies.length == 1 && contest.office !== 'U.S. House';\n\n    // const uncontested = contest.candidacies.length == 1 && contest.office !== 'U.S. House';\n\n    const totalVotes = sumValues(contest.candidacies, 'votes');\n\n    let candidates;\n\n    candidates =\n      totalVotes == 0\n        ? sort_candidates_by_party(contest.candidacies)\n        : contest.candidacies;\n\n    const pct_votes = formatPercent(totalVotes, contest[DDHQestimatedvotes]);\n    const pct_votes_turnout =\n      embedType == 'homepage'\n        ? pct_votes < 100\n          ? `An estimated ${pct_votes}% of votes have been counted.`\n          : `An estimated >99% of votes have been counted.`\n        : pct_votes < 100\n        ? `An estimated ${pct_votes}% of votes have been counted, according to Decision Desk HQ turnout models.`\n        : `An estimated >99% of votes have been counted, according to Decision Desk HQ turnout models.`;\n\n    const pct_votes_turnout_w_uncontested =\n       (uncontestedNoHouse == true)\n          ? text_conditionals(pct_votes, contest.candidacies.length) :\n          pct_votes_turnout\n\n    const pct_votes_explain = !shouldDisplayResult && !uncontested\n      ? text_conditionals(pct_votes, contest.candidacies.length)\n      : ``;\n\n\n    let embedTypeUsable = 'none';\n\n    if (typeof embedType !== 'undefined') {\n      embedTypeUsable = embedType;\n    }\n\n    const showcaseClass = cx({\n      seat__races: !isShowcaseRace,\n      seat__highlight_races: isShowcaseRace,\n    });\n\n    const rowClass = cx('seat__race', {\n      'seat__race--Democrat': partyName == 'Democrat',\n      'seat__race--Republican': partyName == 'Republican',\n    });\n\n    const klaxon_sos = 'Race declared by Decision Desk HQ'; // if we switch sources to TX SOS and someone else has declared the winner\n\n    const klaxon = shouldDisplayResult \n      ? source == 'Decision Desk HQ'\n        ? alert_winners(contest.contest_result, totalVotes)\n        : klaxon_sos\n      : alert_conditionals(pct_votes, contest.candidacies.length);\n\n    const checkmark = '\\u2713';\n\n    let checkClass = cx('check', {\n      'dem-winner':\n        contest.party == 'Democrat' && contest.contest_result != 'runoff',\n      'rep-winner':\n        contest.party == 'Republican' && contest.contest_result != 'runoff',\n      'runoff-winner': contest.contest_result == 'runoff',\n    });\n\n    const contestMetricsClass = cx('contest__metrics', {\n      homepage__metrics: isHomepage,\n      'non-homepage__metrics': !isHomepage,\n    });\n\n    let hasTurnoutmodel = source == 'Decision Desk HQ' ? true : false;\n\n    const precinctsClass = cx('contest__precincts');\n\n    let ManualoverrideSource;\n\n    // If there is a race, that's being manually updated, you can change the Source to whatever the new votes are coming from here if you uncomment the code below. This is only if the source isn't Texas Secretary of State. If it is, then you don't have to do anything.\n\n    // if (contest.office == 'U.S. House' && contest.office_division == 37 && contest.party == 'Republican') {\n    //   ManualoverrideSource = 'Travis County Elections'\n    // }\n    // else {\n    //   ManualoverrideSource = ''\n    // }\n\n    ManualoverrideSource = '';\n\n    const IsAnnotations =\n      annotations && annotations.length > 0 && annotations[0].value != ''\n        ? true\n        : false;\n\n    const IsNoted = notes && notes.length > 0 ? true : false;\n\n    return (\n      <div class=\"seat\">\n        {!isShowcaseRace && embedType == null && (\n          <span>\n            <h3 class=\"seat__title\">\n              <span>{contestTitle}</span>\n            </h3>\n          </span>\n        )}\n        <div class={showcaseClass}>\n          <div class={rowClass}>\n            <div class=\"race\">\n              {embedType == 'homepage' && (\n                <span>\n                  <div class=\"office__title\">{contestTitle}</div>\n                </span>\n              )}\n              {embedType == 'internal' && (\n                <span>\n                  <h2 class=\"office__title\">{contestTitle}</h2>\n                </span>\n              )}\n\n              <div class={contestMetricsClass}>\n                {isCanvass == false && (\n                  <h4 class=\"klaxon__text\">\n                    {shouldDisplayResult && source == 'Decision Desk HQ' ? (\n                      <span class={checkClass}>{checkmark}</span>\n                    ) : (\n                      ''\n                    )}\n                    {klaxon}\n                  </h4>\n                )}\n                {ManualoverrideSource == '' && isCanvass == false && (\n                  <p class={precinctsClass}>\n                    {source != 'Decision Desk HQ'\n                      ? `${intcomma(\n                          contest.pollinglocationsreporting\n                        )} of ${intcomma(\n                          contest.total_pollinglocations\n                        )} polling locations reporting (${contest.pollinglocations_reporting_percent.toFixed(\n                          1\n                        )}%).`\n                      : pct_votes_turnout_w_uncontested}{' '}\n                    {pct_votes_explain}\n                  </p>\n                )}\n                {\n                  (ManualoverrideSource = !'' &&\n                    source != 'Texas Secretary of State' &&\n                    source != 'Decision Desk HQ' &&\n                    isCanvass == false && (\n                      <p class={precinctsClass}>\n                        {`${intcomma(\n                          contest.pollinglocationsreporting\n                        )} of ${intcomma(\n                          contest.total_pollinglocations\n                        )} polling locations reporting (${contest.pollinglocations_reporting_percent.toFixed(\n                          1\n                        )}%).`}\n\n                        {/* <span class=\"source\">{` Source: ${ManualoverrideSource}`}</span> */}\n                      </p>\n                    ))\n                }\n              </div>\n\n              <table class=\"race__candidates\">\n                {tableHeader}\n                <tbody>\n                  {isShowcaseRace &&\n                    candidates.map((candidate: any, idx: any) =>\n                      renderCandidate(\n                        candidate,\n                        idx,\n                        candidatesRender,\n                        viewAllCandidates,\n                        { totalVotes }\n                      )\n                    )}\n\n                  {!isShowcaseRace &&\n                    candidates.map((candidate: any, idx: any) =>\n                      renderCandidate(candidate, idx, viewAllCandidates, {\n                        totalVotes,\n                      })\n                    )}\n                  {candidates.length > CandidatesShown && (\n                    <OtherCandidate\n                      isViewable={!viewAllCandidates}\n                      candidateCount={candidates.length}\n                      embedType={embedType}\n                      onClick={() => {\n                        this.onViewableToggle();\n                      }}\n                    />\n                  )}\n                </tbody>\n                {candidates.length > CandidatesShown &&\n                  viewAllCandidates && (\n                    <tr class=\"candidate race__candidate-row\">\n                      <td\n                        class=\"candidate__cell candidate__party t-align-center\"\n                        onClick={() => {\n                          this.onViewableToggle();\n                        }}\n                      >\n                        <svg class=\"icon icon-angle-up\">\n                          <use xlinkHref=\"#icon-angle-up\" />\n                        </svg>\n                      </td>\n                      <th class=\"candidate__cell candidate__name\">\n                        <button\n                          class={embedType}\n                          onClick={() => {\n                            this.onViewableToggle();\n                          }}\n                        >\n                          Show fewer ({CandidatesShown})\n                        </button>\n                      </th>\n                      <th class=\"candidate__cell candidate__votes\"></th>\n                      <th class=\"candidate__cell candidate__pct\"></th>\n                    </tr>\n                  )}\n              </table>\n\n              {/* {isHomepage && (\n            <div class=\"dropped_out__div\" style=\"margin-top: 0.625rem;\">\n              *Dropped out\n            </div>\n          )} */}\n              {IsNoted == true && (\n                <p class=\"note__text\">{converter.convert(notes[0].value)}</p>\n              )}\n              {IsAnnotations == true && (\n                <div class=\"anno-text notes-annotations\">\n                  <span class=\"is-sr-only\">Note:</span>\n                  <svg class=\"icon note-icon anno-div\" aria-hidden=\"true\">\n                    <use xlinkHref=\"#note-icon\" />\n                  </svg>\n\n                  <p class=\"annotations t-links-underlined\">\n                    <span class=\"font-weight-bold\">Noteworthy: </span>\n                    {converter.convert(annotations[0].value)}\n                  </p>\n                </div>\n              )}\n              <div class=\"below-races\">\n              <div class=\"source\">{` Source: ${source}`}</div>\n                {(embedType == 'homepage' || embedType == 'internal') && (\n                  <div class=\"countdown\">\n                    <span class=\"counter-homepage\">LAST UPDATED {asOf}</span>\n                  </div>\n                )}\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    );\n  }\n}\n\nContest.defaultProps = {\n  isShowcaseRace: false,\n  includeCountyRundown: false,\n};\n\nexport default Contest;\n","import { Component, h, createRef } from 'preact';\nimport { initFrameAndPoll, sendFrameHeight } from '@newswire/frames';\n\nclass FramesChild extends Component {\n  constructor(props) {\n    super(props);\n    this.ref = createRef();\n\n    const { polling } = this.props;\n\n    let opts = {};\n    if (polling) opts.polling = polling;\n  }\n\n  componentDidMount() {\n    const { polling } = this.props;\n\n    initFrameAndPoll(polling);\n  }\n\n  componentDidUpdate() {\n    sendFrameHeight();\n  }\n\n  render({ class: klass }) {\n    return (\n      <div class={klass} ref={this.ref}>\n        {this.props.children}\n      </div>\n    );\n  }\n}\n\nexport default FramesChild;\n","import cx from 'classnames';\nimport { intcomma } from 'journalize';\nimport { h, VNode } from 'preact';\n\nimport PureComponent from './PureComponent';\n\nimport formatPercent from '../utils/format-percent';\nimport { isCanvass } from '../endpoints';\nimport PartyPill from './PartyPill';\n\ninterface Props {\n  ballotName: string;\n  candidateId: string;\n  contestIsCalled: boolean;\n  contestResult: string;\n  isIncumbent: boolean;\n  isWinner: boolean;\n  candidateColors: { [key: string]: any };\n  party: string;\n  totalVotesInContest: number;\n  votes: number;\n}\n\nclass HeadshotCandidateRow extends PureComponent<Props> {\n  static columnCount: number;\n  static Header: VNode;\n\n  render() {\n    const {\n      ballotName,\n      candidateId,\n      contestIsCalled,\n      contestResult,\n      isIncumbent,\n      isWinner,\n      party,\n      isViewable,\n      totalVotesInContest,\n      candidateColors,\n      votes,\n    } = this.props;\n\n    let getColor;\n\n    if (candidateColors) {\n      getColor = candidateColors\n        .filter(obj => obj.name == ballotName)\n        .map(obj => obj.color);\n    } else {\n      getColor = ['#777777'];\n    }\n\n    const divStyle = {\n      'background-color': getColor[0],\n    };\n\n    const checkStyle = {\n      color: getColor[0],\n    };\n\n    const IsAsterisk = ballotName == 'Rick Perry' ? true : false;\n\n    let rowClass = cx(\n      'candidate',\n      'contest__candidate-row',\n      'contest__candidate-row--headshot',\n      {\n        'contest__candidate-row--winner dem--border':\n          contestIsCalled && isWinner && party == 'Democrat',\n        'contest__candidate-row--winner rep--border':\n          contestIsCalled && isWinner && party == 'Republican',\n      }\n    );\n\n    let checkClass = cx('check', {\n      'dem-winner': party == 'Democrat',\n      'rep-winner': party == 'Republican',\n      'runoff-winner': contestResult == 'runoff',\n    });\n\n    if (!isViewable) {\n      rowClass += ' race__candidate-row--hidden';\n    }\n\n    const checkmark = '\\u2713';\n\n    return (\n      <tr class={rowClass}>\n        <td class=\"candidate__cell candidate__party\">\n            <PartyPill party={party} style={divStyle} />\n        </td>\n        <th class=\"candidate__cell candidate__name\">\n          {contestIsCalled && isWinner && contestResult != 'runoff' && (\n            <span class={checkClass} style={checkStyle}>\n              {checkmark}\n            </span>\n          )}\n          {contestIsCalled && isWinner && contestResult == 'runoff' && (\n            <span class={checkClass}>{checkmark}</span>\n          )}\n          {contestIsCalled &&\n          isWinner &&\n          isCanvass == true &&\n          contestResult != 'runoff' ? (\n            <span class={checkClass}>{ballotName}</span>\n          ) : (\n            ballotName\n          )}\n          {IsAsterisk && <span class=\"asterisk\">*</span>}{' '}\n          {isIncumbent && (\n            <span class=\"pill pill--basic\" title=\"Currently holds this seat\">\n              Incumbent\n            </span>\n          )}\n        </th>\n        <td class=\"candidate__cell candidate__votes\">{intcomma(votes)}</td>\n        <td class=\"candidate__cell candidate__pct\">\n          {formatPercent(votes, totalVotesInContest)}\n          <span class=\"candidate__pct-symbol\">%</span>\n        </td>\n      </tr>\n    );\n  }\n}\n\nHeadshotCandidateRow.defaultProps = {\n  isIncumbent: false,\n  isCalled: false,\n  isWinner: false,\n  isViewable: true,\n};\n\nHeadshotCandidateRow.Header = (\n  <thead>\n    <tr>\n      <th class=\"contest__candidate-header\" colSpan={2}>\n        Candidates\n      </th>\n      <th class=\"contest__candidate-header contest__candidate-header--numeric\">\n        Votes\n      </th>\n      <th class=\"contest__candidate-header contest__candidate-header--numeric\">\n        Pct.\n        <span class=\"candidate__pct-symbol\">%</span>\n      </th>\n    </tr>\n  </thead>\n);\n\nHeadshotCandidateRow.columnCount = 6;\n\nexport default HeadshotCandidateRow;\n","function formatPercent(n: number, d: number): string {\n  if (d == null || d <= 0) return '0.0';\n\n  return ((n / d) * 100).toFixed(1);\n}\n\nexport default formatPercent;\n","'use strict';\n\n// We depend on intersection-observer enough that it should just be assumed as necessary\nrequire('intersection-observer');\n","// Live results being updated by Republic\nconst FLAT_RESULTS_URL =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2022_general/republic_json/results_FLAT.json';\n\n// This has emptied out results i.e. is static\nconst STATIC_FLAT_RESULTS_URL =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2022_general/republic_json/results_static_FLAT.json';\n\n// This has the final certified results and is static\nconst FINAL_RESULTS_URL =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2022_general/republic_json/results_FLAT_FINAL_RESULTS.json';\n\nconst COUNTY_FAKE_DATA =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2022_general/republic_json/county_fake_data.json';\n\nconst DDHQ_FAKE_DATA =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2022_general/republic_json/results_FLAT_FINAL_Oct_13.json';\n\nconst DDHQ_FAKE_DATA_2 =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2022_general/republic_json/results_FLAT_FINAL_Oct_25.json';\n\nconst DDHQ_MID_TEST =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2022_general/republic_json/results_FLAT_Oct_25_mid_test.json';\n\nconst SOS_FAKE_DATA =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2022_general/republic_json/results_FLAT_SOS_TEST.json';\n\nconst MINI_CHART_TEST =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2022_general/republic_json/results_MiniChart_test.json';\n\n// Used for homepage takeover\nconst HOMEPAGE_URL =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2022_general/homepage_takeover/2022-general.json';\n\n// Calls TT stories using the API\nconst STORY_API_URL = (id: number): string =>\n  `https://www.texastribune.org/api/v2/articles/${id}/?format=json&fields=sitewide_image,summary,authors,url,pub_date,updated_date,homepage_headline`;\n\n// This is for the other candidates for the hide/show toggle\nconst visibleCandidatesCount = 6;\n\n// The Decision Desk estimated votes count that we will be using, it can be either estimated_votes_high, estimated_votes_mid or estimated_votes_low. Ask DDHQ for guidance on which to use before the election.\nconst DDHQestimatedvotes = 'estimated_votes_mid';\n\n// Show bubble piegram map toggle option. Set to false if we want to hide it.\nconst showBubbleMap = true;\n\n// Show categories map toggle option. Set to false if we want to hide it.\nconst showCategoriesMap = true;\n\n// Show precincts or estimated votes still being counted text\nconst showPrecinctsReporting = false;\n\n// Adds the checkmark if this is the final official results from local canvass\nconst isCanvass = true;\n\n// Show last updated timestamp, set to true to last updated text\nconst showLastUpdated = false;\n\n// What we are using across the ap\n// will be used on the results page, in the homepage takeover\n// and in the embeds\nconst RESULTS_IN_USE = FINAL_RESULTS_URL;\n\nexport {\n  RESULTS_IN_USE,\n  HOMEPAGE_URL,\n  STORY_API_URL,\n  visibleCandidatesCount,\n  showPrecinctsReporting,\n  isCanvass,\n  showLastUpdated,\n  showBubbleMap,\n  showCategoriesMap,\n  DDHQestimatedvotes\n};","/**\n * Grabs the contents of a `jsonScript` created JSON inline string and returns\n * it as a JSON object. If the element does not exist, or if the script\n * element does not have the JSON MIME type, null is returned instead.\n *\n * @param  {String} elementId the ID of the JSON script element\n * @return {Object|null}\n */\nexport default function loadJsonScript(elementId) {\n  const element = document.getElementById(elementId);\n\n  if (element && element.getAttribute('type') === 'application/json') {\n    return JSON.parse(element.textContent);\n  } else {\n    return null;\n  }\n}\n","export default function sumValues(arr, key) {\n  return arr.reduce((acc, obj) => acc + obj[key], 0);\n}\n","const LENGTH_OF_CHECK_INTERVAL = 1000 * 60 * 2; // 2 minutes\nconst TIMERS_SHOULD_RUN = false;\n\nexport { LENGTH_OF_CHECK_INTERVAL, TIMERS_SHOULD_RUN };\n","var journalize = require('journalize');\n\nimport { capfirst } from 'journalize';\n\nimport context from 'Data/text.json';\n\nexport function lastUpdatedFormat(now) {\n  // format dates to ap style\n  const formatted_date = journalize.apdate(now),\n    formatted_time = journalize.aptime(now),\n    formatted_month = journalize.apmonth(now),\n    just_day = now.getDate();\n\n  return formatted_time;\n}\n\nexport function format(num) {\n  return num < 10 ? '0' + num : num;\n}\n\nexport const chunk = (arr, size) =>\n  arr.reduce((acc, _, i) => {\n    if (i % size === 0) acc.push(arr.slice(i, i + size));\n    return acc;\n  }, []);\n\nexport const delay = (function() {\n  var timer = 0;\n  return function(callback, ms) {\n    clearTimeout(timer);\n    timer = setTimeout(callback, ms);\n  };\n})();\n\nconst PARTY_SORT_ORDER = [\n  'Republican',\n  'Democrat',\n  'Libertarian',\n  'Green',\n  'Independent',\n  'Write-in',\n];\n\n// If we need light blue #99d2da; background-color:rgba(153, 210, 218, .1)\n// If we need dark blue #325ba8; background-color:rgba(90, 137, 204, .1)\n\nconst TT_directory_slugs = [\n  { office: 'Texas House', 'directory-slug': 'tx-house' },\n  { office: 'Texas Senate', 'directory-slug': 'tx-senate' },\n  { office: 'U.S. House', 'directory-slug': 'us-house' },\n  { office: 'State Board of Education', 'directory-slug': 'sboe' },\n];\n\nexport function get_directory_slug(office) {\n  return TT_directory_slugs.filter(slug => slug.office == office);\n}\n\nexport function sort_candidates_by_party(candidates) {\n  return candidates.sort(\n    (a, b) =>\n      PARTY_SORT_ORDER.indexOf(a.party) - PARTY_SORT_ORDER.indexOf(b.party)\n  );\n}\n\nexport function alert_conditionals(vote_pct, cand_num) {\n  if (vote_pct == 0 && cand_num > 1) {\n    return context.label_conditionals['zero-results'];\n  } else if (vote_pct > 0 && vote_pct < 50 && cand_num > 1) {\n    return context.label_conditionals['more-than-0-less-than-50'];\n  } else if (vote_pct >= 50 && vote_pct < 99 && cand_num > 1) {\n    return context.label_conditionals['more-than-50-no-winner'];\n  } else if (vote_pct >= 99 && cand_num > 1) {\n    return context.label_conditionals['all-results-in-no-winner'];\n  } else if (cand_num == 1) {\n    return context.label_conditionals['uncontested'];\n  }\n}\n\nexport function alert_winners(result, totals) {\n  if (result == 'winner' && totals > 0) {\n    return context.winner_conditionals['winner'];\n  } \n  else if (result == 'winner' && totals == 0) {\n    return context.winner_conditionals['winner_zero']\n  }\n    else if (result == 'uncontested') {\n    return context.winner_conditionals['uncontested'];\n  } else if (result == 'runoff') {\n    return '';\n  }\n}\n\nexport function text_conditionals(vote_pct, cand_num) {\n  if (vote_pct == 0 && cand_num > 1) {\n    return context.text_conditionals['zero-results'];\n  } else if (vote_pct > 0 && vote_pct < 50 && cand_num > 1) {\n    return context.text_conditionals['more-than-0-less-than-50'];\n  } else if (vote_pct >= 50 && vote_pct < 99 && cand_num > 1) {\n    return context.text_conditionals['more-than-50-no-winner'];\n  } else if (vote_pct >= 99 && cand_num > 1) {\n    return context.text_conditionals['all-results-in-no-winner'];\n  } else if (cand_num == 1) {\n    return context.text_conditionals['uncontested'];\n  }\n}\n\nexport function determineDistrictTitle(contest) {\n  return `${contest.office} ${\n    contest.office === 'President' ||\n    contest.division_type === 'class' ||\n    contest.division_type === 'statewide'\n      ? ''\n      : contest.division_type === 'place' && contest.office_division === 1\n      ? 'Chief Justice'\n      : capfirst(contest.division_type) + ' ' + contest.office_division\n  }`.trim();\n}\n\nexport function determineContestTitle(contest) {\n  if (contest.division_type === 'statewide' || contest.division_type === 'seat')\n    return '';\n\n  return determineDistrictTitle(contest);\n}\n\nexport function determineContestTitleYourRaces(contest) {\n  return determineDistrictTitle(contest);\n}\n","/**\n * A wrapper for the initial response from a fetch call that funnels to\n * res.json().\n *\n * @private\n * @param {Response} res\n * @returns {Promise}\n */\nfunction jsonResponse(res) {\n  if (!res.ok) throw new Error(`${res.status}: ${res.statusText}`);\n\n  return res.json();\n}\n\n/**\n * A light wrapper around fetch that assumes you're seeking a JSON response.\n *\n * @param {String|Request} input\n * @param {Object} init\n * @returns {Promise}\n */\nexport default function getJSON(input, init) {\n  return fetch(input, init).then(jsonResponse);\n}\n","const hOP = Object.prototype.hasOwnProperty;\n\n/**\n * inlined Object.is polyfill to avoid requiring consumers ship their own\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is\n */\nfunction is(x: any, y: any): boolean {\n  // SameValue algorithm\n  if (x === y) {\n    // Steps 1-5, 7-10\n    // Steps 6.b-6.e: +0 != -0\n    // Added the nonzero y check to make Flow happy, but it is redundant\n    return x !== 0 || y !== 0 || 1 / x === 1 / y;\n  }\n  // Step 6.a: NaN == NaN\n  return x !== x && y !== y;\n}\n\n/**\n * Performs equality by iterating through keys on an object and returning false\n * when any key has values which are not strictly equal between the arguments.\n * Returns true when the values of all keys are strictly equal.\n */\nfunction shallowEqual(objA: object, objB: object): boolean {\n  if (is(objA, objB)) {\n    return true;\n  }\n\n  if (\n    typeof objA !== 'object' ||\n    objA === null ||\n    typeof objB !== 'object' ||\n    objB === null\n  ) {\n    return false;\n  }\n\n  const keysA = Object.keys(objA);\n  const keysB = Object.keys(objB);\n\n  if (keysA.length !== keysB.length) {\n    return false;\n  }\n\n  // Test for A's keys different from B.\n  for (let i = 0; i < keysA.length; i++) {\n    if (!hOP.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\nexport default shallowEqual;\n","// packages\nimport { Component } from 'preact';\n\n// internal\nimport shallowEqual from '../utils/shallow-equal';\n\nabstract class PureComponent<P = {}, S = {}> extends Component<P, S> {\n  shouldComponentUpdate(props, state) {\n    const check =\n      shallowEqual(props, this.props) && shallowEqual(state, this.state);\n    // if (props.projection)\n    //   console.log(\n    //     'projection check:',\n    //     props.projection === this.props.projection,\n    //     !check\n    //   );\n    return !check;\n  }\n}\n\nexport default PureComponent;\n","/**\n * A white-list of attributes to consider booleans for our purposes. Because\n * iframe attributes like \"sandbox\" actually mean something when they're an\n * empty string, we can't assume that means \"true\" across the board.\n *\n * @private\n * @type {Array}\n */\nconst booleans = ['allowfullscreen'];\n\n/**\n * Searches an element's attributes and returns an Object of all the ones that\n * begin with a specified prefix. Each matching attribute name is returned\n * without the prefix.\n *\n * @private\n * @param  {Element} element\n * @param  {string} prefix\n * @return {object}\n */\nfunction getMatchingAttributes(element, prefix) {\n  // prepare the object to return\n  const attrs = {};\n\n  // grab all the attributes off the element\n  const map = element.attributes;\n\n  // get a count of the number of attributes\n  const length = map.length;\n\n  // get the prefix's length\n  const prefixLength = prefix.length;\n\n  // loop through the attributes\n  for (let i = 0; i < length; i++) {\n    // get each attribute key\n    const key = map[i].name;\n\n    // continue if the key begins with supplied prefix\n    if (key.substr(0, prefixLength) === prefix) {\n      // slice off the prefix to get the bare field key\n      const field = key.slice(prefixLength);\n\n      // grab the value associated with the key\n      let value = map[i].value;\n\n      if (booleans.indexOf(field) > -1) {\n        value = true;\n      }\n\n      // add matching key to object\n      attrs[field] = value;\n    }\n  }\n\n  return attrs;\n}\n\nfunction extend(obj, props) {\n  for (let i in props) obj[i] = props[i];\n  return obj;\n}\n\nexport { extend, getMatchingAttributes };\n","const EMBED_SIZE = 'embed-size';\nconst AMP_SENTINEL = 'amp';\nconst FRAME_PREFIX = 'data-frame-';\nconst FRAME_AUTO_INITIALIZED_ATTRIBUTE = `${FRAME_PREFIX}auto-initialized`;\nconst FRAME_SRC_ATTRIBUTE = `${FRAME_PREFIX}src`;\n\nexport {\n  AMP_SENTINEL,\n  EMBED_SIZE,\n  FRAME_PREFIX,\n  FRAME_AUTO_INITIALIZED_ATTRIBUTE,\n  FRAME_SRC_ATTRIBUTE,\n};\n","import { extend, getMatchingAttributes } from './utils.mjs';\nimport {\n  AMP_SENTINEL,\n  EMBED_SIZE,\n  FRAME_PREFIX,\n  FRAME_AUTO_INITIALIZED_ATTRIBUTE,\n  FRAME_SRC_ATTRIBUTE,\n} from './constants.mjs';\n\n/**\n * The Framer object to be called in the host page. Effectively a wrapper around\n * interactions with an embedded iframe.\n *\n * @param {object} options options used to prepare the iframe\n * @param {Element} options.container the containing DOM element for the iframe\n * @param {string} options.src the URL to set as the `src` of the iframe\n * @param {boolean} [options.allowfullscreen] toggles the `allowfullscreen` attribute\n * @param {string} [options.name] sets the `name` attribute\n * @param {string} [options.referrerpolicy] sets the `referrerpolicy` attribute\n * @param {string} [options.sandbox] sets the `sandbox` attribute\n * @param {string} [options.title] sets the `title` attribute\n */\nclass Framer {\n  constructor({\n    allowfullscreen = false,\n    container,\n    name,\n    referrerpolicy,\n    sandbox = 'allow-scripts',\n    src,\n    title,\n  }) {\n    this.container = container;\n    this.src = src;\n    this.allowfullscreen = allowfullscreen;\n    this.name = name;\n    this.referrerpolicy = referrerpolicy;\n    this.sandbox = sandbox;\n    this.title = title;\n\n    this.processMessage_ = this.processMessage_.bind(this);\n    window.addEventListener('message', this.processMessage_, false);\n\n    this.createIframe_();\n  }\n\n  /**\n   * Removes event listeners and removes the iframe from the container.\n   *\n   * @returns {void}\n   * @example\n   *\n   * const framer = new Framer(...);\n   * // tears down the Framer\n   * framer.remove();\n   */\n  remove() {\n    window.removeEventListener('message', this.processMessage_, false);\n    this.container.removeChild(this.iframe);\n    // important to de-reference the iframe so it can be GC'ed\n    this.iframe = null;\n  }\n\n  /**\n   * Creates the iframe element and sets the source of the iframe.\n   *\n   * @private\n   * @returns {void}\n   */\n  createIframe_() {\n    const iframe = (this.iframe = document.createElement('iframe'));\n\n    iframe.setAttribute('src', this.src);\n    iframe.setAttribute('width', '100%');\n    iframe.setAttribute('scrolling', 'no');\n    iframe.setAttribute('marginheight', '0');\n    iframe.setAttribute('frameborder', '0');\n\n    if (this.allowfullscreen) {\n      iframe.setAttribute('allowfullscreen', '');\n    }\n\n    if (this.name) {\n      iframe.setAttribute('name', name);\n    }\n\n    if (this.referrerpolicy) {\n      iframe.setAttribute('referrerpolicy', this.referrerpolicy);\n    }\n\n    iframe.setAttribute('sandbox', this.sandbox);\n\n    if (this.title) {\n      iframe.setAttribute('title', this.title);\n    }\n\n    this.container.appendChild(iframe);\n  }\n\n  /**\n   * Receives a message from the frame. Checks to make sure it is only listening\n   * to the iframe it created, and that the sentinel value and type matches.\n   *\n   * @private\n   * @param {Event} event\n   * @returns {void}\n   */\n  processMessage_(event) {\n    // this message isn't from our created frame, stop here\n    if (event.source !== this.iframe.contentWindow) return;\n\n    const { data } = event;\n\n    // if the sentinel and type matches, update our height\n    if (data.sentinel === AMP_SENTINEL && data.type === EMBED_SIZE) {\n      this.setIframeHeight_(data.height);\n    }\n  }\n\n  /**\n   * Sets the iframe's height.\n   *\n   * @private\n   * @param {number} height\n   * @returns {void}\n   */\n  setIframeHeight_(height) {\n    this.iframe.setAttribute('height', height);\n  }\n}\n\n/**\n * Automatically initializes any frames that have not already been\n * auto-activated.\n *\n * @returns {Array} An array of all the created Framers\n * @example\n *\n * // sets up all frames that have not been initialized yet\n * autoInitFrames();\n */\nfunction autoInitFrames() {\n  const elements = document.querySelectorAll(\n    `[${FRAME_SRC_ATTRIBUTE}]:not([${FRAME_AUTO_INITIALIZED_ATTRIBUTE}])`\n  );\n\n  const activated = [];\n\n  for (let i = 0; i < elements.length; i++) {\n    const container = elements[i];\n\n    const attributes = getMatchingAttributes(container, FRAME_PREFIX);\n    container.setAttribute(FRAME_AUTO_INITIALIZED_ATTRIBUTE, '');\n\n    activated.push(\n      new Framer(\n        extend(\n          {\n            container,\n          },\n          attributes\n        )\n      )\n    );\n  }\n\n  return activated;\n}\n\nexport { autoInitFrames, Framer };\n","// internal\nimport { AMP_SENTINEL, EMBED_SIZE } from './constants.mjs';\nimport { extend } from './utils.mjs';\n\n/**\n * A wrapper around postMessage to normalize the message body. Automatically\n * includes the AMP sentinel value.\n *\n * @private\n * @param {string} type Type of message being sent\n * @param {Object} [data] Any additional data to send\n * @returns {void}\n */\nfunction sendMessage(type, data = {}) {\n  window.parent.postMessage(\n    extend({ sentinel: AMP_SENTINEL, type }, data),\n    '*'\n  );\n}\n\n/**\n * Gets the height of the current document's body. Uses offsetHeight to ensure\n * that margins are accounted for.\n *\n * @private\n * @returns {number}\n */\nfunction getDocumentHeight() {\n  return document.documentElement.offsetHeight;\n}\n\n/**\n * Sends the current document's height or provided value to the host window\n * using postMessage.\n *\n * @param {number} [height] The height to pass to the host page, is determined automatically if not passed\n * @returns {void}\n * @example\n *\n * // Uses the document's height to tell the host page\n * sendFrameHeight();\n *\n * // Pass a height you've determined in another way\n * sendFrameHeight(500);\n *\n */\nfunction sendFrameHeight(height = getDocumentHeight()) {\n  sendMessage(EMBED_SIZE, { height });\n}\n\n/**\n * Sets up an event listener for the load event that sends the new frame\n * height to the host. Automatically removes itself once fired.\n *\n * @returns {void}\n * @example\n *\n * // once the frame's load event is fired, tell the host page its new height\n * sendHeightOnLoad();\n */\nfunction sendHeightOnLoad() {\n  window.addEventListener('load', function cb() {\n    sendFrameHeight();\n\n    window.removeEventListener('load', cb);\n  });\n}\n\n/**\n * Sets up an event listener for the resize event that sends the new frame\n * height to the host.\n *\n * @returns {void}\n * @example\n *\n * // every time the frame is resized, tell the host page what its new height is\n * sendHeightOnResize();\n */\nfunction sendHeightOnResize() {\n  window.addEventListener('resize', () => sendFrameHeight());\n}\n\n/**\n * Sends height updates to the host page on an interval.\n *\n * @param {number} [delay] How long to set the interval\n * @returns {void}\n * @example\n *\n * // will call sendFrameHeight every 300ms\n * sendHeightOnPoll();\n *\n * // will call sendFrameHeight every 150ms\n * sendHeightOnPoll(150);\n */\nfunction sendHeightOnPoll(delay = 300) {\n  setInterval(sendFrameHeight, delay);\n}\n\n/**\n * A helper for running the standard functions for setting up a frame.\n *\n * Automatically calls an sendFrameHeight, sendHeightOnLoad and sendHeightOnResize.\n *\n * @returns {void}\n * @example\n *\n * initFrame();\n */\nfunction initFrame() {\n  sendFrameHeight();\n  sendHeightOnLoad();\n  sendHeightOnResize();\n}\n\n/**\n * Initializes a frame, then sets up a poll to continue to update on an interval.\n *\n * @param {number} [delay] An optional custom delay to pass to sendHeightOnPoll\n * @returns {void}\n * @example\n *\n * // calls initFrame, then calls sendHeightOnPoll\n * initFrameAndPoll();\n */\nfunction initFrameAndPoll(delay) {\n  initFrame();\n  sendHeightOnPoll(delay);\n}\n\nexport {\n  initFrame,\n  initFrameAndPoll,\n  sendFrameHeight,\n  sendHeightOnLoad,\n  sendHeightOnPoll,\n  sendHeightOnResize,\n};\n","// packages\nimport cx from 'classnames';\nimport { capfirst } from 'journalize';\nimport memoize from 'lodash.memoize';\nimport { h } from 'preact';\n\ntype Props = {\n  excludeInitial?: boolean;\n  party: string;\n  style: string;\n};\n\nfunction PartyPill({ excludeInitial, party, style }: Props) {\n  const partyPrefix = party.slice(0, 3).toLowerCase();\n  const partyInitial = party[0].toUpperCase();\n\n  const classes = cx('circle-pill', `pill--${partyPrefix}`);\n\n  return (\n    <span class={classes} style={style} title={capfirst(party)}>\n      {!excludeInitial && partyInitial}\n    </span>\n  );\n}\n\nPartyPill.defaultProps = {\n  excludeInitial: false,\n};\n\nexport default memoize(PartyPill, ({ party, style }) => ({\n  party: party,\n  style: style,\n}));\n"],"sourceRoot":""}