{"version":3,"sources":["webpack:///./app/scripts/components/OtherCandidate.js","webpack:///./app/scripts/components/Contest.tsx","webpack:///../src/utils.mjs","webpack:///../src/constants.mjs","webpack:///../src/framer.mjs","webpack:///../src/frames.mjs","webpack:///./app/scripts/components/FramesChild.js","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/components/CandidateRow.tsx","webpack:///./app/scripts/constants.ts","webpack:///./app/scripts/EmbedApp.tsx","webpack:///./app/scripts/packs/embed.tsx","webpack:///./app/scripts/utils/parse-query-string.js","webpack:///./app/scripts/election-utils.ts","webpack:///./app/scripts/utils/get-json.js","webpack:///./app/scripts/components/PartyPill.tsx"],"names":["OtherCandidate","isViewable","candidateCount","embedType","onClick","classes","cx","class","xlinkHref","converter","process","PreactHTMLConverter","Contest","Component","constructor","super","this","state","viewAllCandidates","onViewableToggle","bind","setState","prevState","render","totalVotes","candidates","winner_found","pct_votes","pct_votes_turnout","directory_slug","contest","flags","annotations","columnCount","contestTitle","isShowcaseRace","asOf","includeCountyRundown","renderCandidate","visibleCandidatesCount","isHomepage","tableHeader","broadcastHeaderImage","activeContestId","props","shouldDisplayResult","contest_result","IsFlagged","length","hasTurnoutmodel","value","rep_target","dem_target","office","IsAnnotations","get_directory_slug","sumValues","candidacies","sort_candidates_by_party","filter","item","is_winner","map","name","formatPercent","estimated_votes_high","embedTypeUsable","isPartner","rowClass","seat__races","seat__races__partner","seat__highlight_races","disclaimerClass","contestMetricsClass","homepage__metrics","precinctsClass","tribcast","turnout_model_district","countdownClass","includes","href","target","rel","src","alt","title","source","isCanvass","aria-hidden","convert","prose","candidate","idx","showPrecinctsReporting","intcomma","pollinglocationsreporting","total_pollinglocations","pollinglocations_reporting_percent","toFixed","hasManualoverride","showCountdown","defaultProps","extend","obj","let","i","const","EMBED_SIZE","Framer","ref","container","allowfullscreen","referrerpolicy","sandbox","processMessage_","window","addEventListener","createIframe_","sendFrameHeight","height","data","document","documentElement","offsetHeight","parent","postMessage","sentinel","AMP_SENTINEL","initFrame","cb","removeEventListener","initFrameAndPoll","delay","setInterval","sendHeightOnPoll","remove","removeChild","iframe","createElement","setAttribute","appendChild","event","contentWindow","type","setIframeHeight_","FramesChild","createRef","polling","componentDidMount","componentDidUpdate","klass","children","n","d","require","HOMEPAGE_URL","STORY_API_URL","id","RESULTS_IN_USE","loadJsonScript","elementId","element","getElementById","getAttribute","JSON","parse","textContent","arr","key","reduce","acc","CandidateRow","ballotName","contestIsCalled","isIncumbent","isWinner","party","totalVotesInContest","votes","checkClass","Header","colSpan","countyHeader","LENGTH_OF_CHECK_INTERVAL","App","contests","fetchData","now","Date","selectedContests","lastUpdatedFormat","getJSON","then","activeContests","slug","office_slug","indexOf","startTimer","timer","setTimeout","clearTimer","clearTimeout","componentWillUnmount","embedDMN","isMoreText","context","status_of_race_embed","status_of_race","style","annotation_explain","text","called_races_bullet","yellow_notes_bullet","races_to_watch_bullet","pills_bullet","embed_only_more_bullet","determineContestTitle","candidateId","is_incumbent","qs","location","search","Object","create","trim","replace","split","forEach","p","decodeURIComponent","Array","isArray","push","EmbedApp","partner_dmn","journalize","PARTY_SORT_ORDER","TT_directory_slugs","sort","a","b","callback","ms","lastUpdated","apdate","formatted_time","aptime","apmonth","getDate","countdown_div","querySelectorAll","prototype","call","el","innerHTML","chunk","size","_","slice","determineDistrictTitle","division_type","office_division","capfirst","determineContestTitleYourRaces","jsonResponse","res","ok","Error","status","statusText","json","input","init","fetch","PartyPill","excludeInitial","partyPrefix","toLowerCase","partyInitial","toUpperCase","memoize"],"mappings":"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","file":"embed.de278d7dd4.mjs","sourcesContent":["import cx from 'classnames';\nimport { h } from 'preact';\nimport { apnumber } from 'journalize';\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 { capfirst, intcomma } from 'journalize';\nimport cx from 'classnames';\nimport { Component, h } from 'preact';\nimport { PreactHTMLConverter } from 'preact-html-converter';\nconst BROADCAST_HEADER_IMG = `${process.env.PUBLIC_PATH}assets/images/TT-2020Elections_logo-embed.png`;\nimport OtherCandidate from './OtherCandidate';\n\n// internal\nimport {\n  sort_candidates_by_party,\n  get_directory_slug,\n} from '../election-utils';\nimport { showCountdown, source, showPrecinctsReporting, isCanvass } from '../endpoints';\nimport formatPercent from '../utils/format-percent';\nimport sumValues from '../utils/sum-values';\n\n\nconst converter = PreactHTMLConverter();\n\ntype Props = {\n  contest: { [key: string]: any },\n  flags: { [key: string]: any },\n  annotations: { [key: string]: any },\n  columnCount: number,\n  contestTitle: string,\n  asOf: string,\n  includeCountyRundown?: boolean,\n  isShowcaseRace?: boolean,\n  isHomepage?: boolean,\n  tableHeader: JSX.Element,\n  renderCandidate: any,\n  visibleCandidatesCount?: number,\n  embedType: string,\n  broadcastHeaderImage: string,\n  activeContestId: 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      flags,\n      annotations,\n      columnCount,\n      contestTitle,\n      isShowcaseRace,\n      asOf,\n      includeCountyRundown,\n      renderCandidate,\n      visibleCandidatesCount,\n      isHomepage,\n      tableHeader,\n      embedType,\n      broadcastHeaderImage,\n      activeContestId,\n    } = this.props;\n\n    const { viewAllCandidates } = this.state;\n\n    let totalVotes;\n    let candidates;\n    let winner_found;\n    let pct_votes;\n    let pct_votes_turnout;\n\n\n    const shouldDisplayResult = contest.contest_result !== 'not called';\n\n    const IsFlagged = flags && flags.length > 0 ? true : false;\n\n    const IsRepTarget = IsFlagged && flags[0].value.rep_target ? true : false;\n\n    const IsDemTarget = IsFlagged && flags[0].value.dem_target ? true : false;\n\n    const hasTurnoutmodel =\n      contest.office == 'U.S. House' ||\n      contest.office == 'President' ||\n      contest.office == 'U.S. Senate' ||\n      contest.office == 'Texas Railroad Commission' ||\n      contest.office == 'Texas Supreme Court' ||\n      contest.office == 'Texas Court of Criminal Appeals'\n        ? true\n        : false;\n\n    // const hasManualoverride =\n    // (contest.office == 'U.S. House' && contest.office_division == 4) || (contest.office == 'U.S. House' && contest.office_division == 23) ? true : false;\n    \n    const hasManualoverride = false;\n\n\n    const IsAnnotations =\n      annotations && annotations.length > 0 && annotations[0].value != ''\n        ? true\n        : false;\n\n    // The Republic API slugs don't match the directory url slugs so we need to get them\n\n    let directory_slug;\n\n    if (contest) {\n      directory_slug = get_directory_slug(contest.office);\n      totalVotes = sumValues(contest.candidacies, 'votes');\n      candidates =\n        totalVotes == 0\n          ? sort_candidates_by_party(contest.candidacies)\n          : contest.candidacies;\n      winner_found = candidates\n        .filter(item => item.is_winner === true)\n        .map(item => item.name);\n      pct_votes = formatPercent(\n        totalVotes,\n        contest.estimated_votes_high\n        )\n    \n      pct_votes_turnout = pct_votes < 100 ? `An estimated ${pct_votes}% of votes have already been counted, according to Decision Desk HQ turnout models.` : `An estimated >99% of votes have already been counted, according to Decision Desk HQ turnout models.`\n    }\n    // Uncomment this and put it back to line 334 to put back the polling locations numbers\n    \n\n    const checkmark = '\\u2713';\n\n    let embedTypeUsable = 'none';\n\n    if (typeof embedType !== 'undefined') {\n      embedTypeUsable = embedType;\n    }\n\n    // set the class on the disclaimer, changes between partner embed and the default index page\n    const isPartner =\n      embedTypeUsable && embedTypeUsable == 'partner' ? true : false;\n\n    const rowClass = cx({\n      seat__races: !isShowcaseRace,\n      seat__races__partner: isPartner,\n      seat__highlight_races: isShowcaseRace,\n    });\n\n    const disclaimerClass = cx(\n      'disclaimer-race',\n      {\n        'disclaimer-partner': isPartner,\n        'disclaimer-homepage': isHomepage,\n      } // disclaimer-partner needs to be after disclaimer-race\n    );\n\n    const contestMetricsClass = cx(\n      'contest__metrics',\n      {\n        homepage__metrics: isHomepage,\n        'non-homepage__metrics': !isHomepage,\n      } // disclaimer-partner needs to be after disclaimer-race\n    );\n\n    const precinctsClass = cx('contest__precincts', {\n      tribcast: embedType == 'tribcast',\n      turnout_model_district: hasTurnoutmodel,\n    });\n\n    const countdownClass = cx('countdown', {\n      tribcast: embedType == 'tribcast',\n    });\n\n    return (\n      <div class=\"seat t-sans\">\n        {embedTypeUsable.includes('broadcast') && (\n          <header class=\"embed-logo-container\">\n            <a\n              href=\"https://www.texastribune.org/\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              <img\n                class=\"embed-logo\"\n                src={broadcastHeaderImage}\n                alt=\"Texas 2020 November Election Results presented by The Texas Tribune\"\n              />\n            </a>\n          </header>\n        )}\n        {/* {IsFlagged == true && (\n          <div class=\"seat__flag\">\n            <p class=\"office__flag\">\n              <span class=\"gold-star\">★</span>Race to watch\n            </p>\n          </div>\n        )} */}\n\n        <div class={rowClass}>\n          <div class=\"seat__race\">\n            <div class=\"race\">\n              <h3 class=\"seat__title\">\n                {!isHomepage && <span>{contestTitle}</span>}\n\n                {directory_slug[0] != null && (\n                  <a\n                    href={`https://www.texastribune.org/directory/districts/${directory_slug[0]['directory-slug']}/${contest['office_division']}`}\n                  >\n                    <span\n                      class=\"icon-div\"\n                      title=\"Click to learn more about this district\"\n                    >\n                      <svg class=\"icon icon-info\">\n                        <use xlinkHref=\"#icon-info\"></use>\n                      </svg>\n                    </span>\n                  </a>\n                )}\n              </h3>\n\n              {(IsAnnotations == true ||\n                IsFlagged == true ||\n                (shouldDisplayResult && source == 'Decision Desk HQ')) && (\n                <div class={disclaimerClass}>\n                  {source == 'Decision Desk HQ' && shouldDisplayResult && isCanvass == false && (\n                    <div class=\"anno-text ddhq_winner\">\n                      <span class=\"dd_winner\">{checkmark}</span>\n                      <p class=\"annotations winner-call\">\n                        Decision Desk HQ has declared {winner_found} the winner{contest.office == 'President' && (<span> in Texas</span>)}.\n                      </p>\n                    </div>\n                  )}\n\n                  {IsAnnotations == true && (\n                    <div class=\"anno-text notes\">\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\">\n                        <span class=\"font-weight-bold\">Noteworthy: </span>\n                        {converter.convert(annotations[0].value)}\n                      </p>\n                    </div>\n                  )}\n\n                  {IsFlagged == true && flags[0].value.prose != '' && (\n                    <div class=\"anno-text race_to_watch_note get__flag\">\n                      <span class=\"gold-star\">★</span>\n                      <p class=\"annotations\">\n                        <span class=\"font-weight-bold\">Race to watch: </span>\n                        {converter.convert(flags[0].value.prose)}\n                      </p>\n                    </div>\n                  )}\n                </div>\n              )}\n              <table class=\"race__candidates\">\n                {tableHeader}\n                <tbody>\n                  {isShowcaseRace &&\n                    candidates.map((candidate: any, idx: any) =>\n                      renderCandidate(candidate, idx, 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\n                  {isHomepage && candidates.length > visibleCandidatesCount && (\n                    <OtherCandidate\n                      isViewable={!viewAllCandidates}\n                      candidateCount={candidates.length}\n                      embedType={embedType}\n                      onClick={() => {\n                        this.onViewableToggle();\n                      }}\n                    />\n                  )}\n                </tbody>\n\n                {isHomepage &&\n                  candidates.length > visibleCandidatesCount &&\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 ({visibleCandidatesCount})\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              <div>\n                <div class={contestMetricsClass}>\n                {hasManualoverride == false && showPrecinctsReporting == true  && (\n                  <p class={precinctsClass}>\n                    {hasTurnoutmodel == false || 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}\n\n                    <span class=\"source\">{` Source: ${source}`}</span>\n                  </p>)}\n                  {hasManualoverride == true && (\n                  <p class={precinctsClass}>\n                    <span class=\"source\">{` Source: Texas Secretary of State`}</span>\n                  </p>)}\n                  {showPrecinctsReporting == false && (\n                  <p class={precinctsClass}>\n                    <span class=\"source\">{` Source: ${source}`}</span>\n                  </p>)}\n                </div>\n              </div>\n              {showCountdown == true && hasManualoverride == false && (\n                <div class={countdownClass}>\n                  <span class=\"counter\">Last updated {asOf}</span>\n                </div>\n              )}\n              {isHomepage && (\n                <div class=\"homepage-link__full_results\">\n                  <a href=\"https://apps.texastribune.org/features/2020/general-election-results/\">\n                    View Full Results\n                  </a>\n                </div>\n              )}\n            </div>\n          </div>\n        </div>\n      </div>\n    );\n  }\n}\n\nContest.defaultProps = {\n  isShowcaseRace: false,\n  includeCountyRundown: false,\n  visibleCandidatesCount: 2,\n};\n\nexport default Contest;\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","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","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","// This has emptied out results i.e. is static\nconst STATIC_FLAT_RESULTS_URL =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2020_general/republic_json/results_FLAT_static.json';\n\n// Results from either Decision Desk or Secretary of State (depending on what the cron job is collecting)\nconst FLAT_RESULTS_URL =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2020_general/republic_json/results_FLAT.json';\n\n// Results from the final canvass \nconst FINAL_RESULTS_URL = `https://s3.amazonaws.com/sos-test-2.texastribune.org/2020_general/republic_json/results_FLAT_FINAL.json`\n\n// Includes fake results data for testing\nconst FAKE_RESULTS_URL =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2020_general/republic_json/results_FLAT_dummy_data.json';\nconst FAKE_RESULTS_URL_TWO =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2020_general/republic_json/results_FLAT_TEST_OCT_8.json';\n\n// fake results based on 2018 returns for Senate and Governor\nconst FAKE_RESULTS_2018 =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2020_general/republic_json/results_FLAT_dummy_data_2018.json';\n\n// Used for homepage takeover\nconst HOMEPAGE_URL =\n  'https://s3.amazonaws.com/sos-test-2.texastribune.org/2020_general/homepage_takeover/2020-general.json';\n\n// This is for the other candidates for the hide/show toggle. I turned it off by making it a really high number, you can turn it back on by making it 3\nconst visibleCandidatesCount = 53;\n\n// Show countdown counter, set to true to last updated text\nconst showCountdown = false;\n\n// Show precincts or estimated votes still being counted text\nconst showPrecinctsReporting = false;\n\n// Switches front-end to show either 'Decision Desk HQ' as source or 'Texas Secretary of State'\nconst source = 'Decision Desk HQ';\n\n// Adds the checkmark if this is the final official results from local canvass\nconst isCanvass = true;\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// 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  showCountdown,\n  showPrecinctsReporting,\n  isCanvass,\n  source,\n};\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","import cx from 'classnames';\nimport { capfirst, intcomma } from 'journalize';\nimport { Component, h, VNode } from 'preact';\n\nimport PartyPill from './PartyPill';\nimport PureComponent from './PureComponent';\n\nimport { isCanvass } from '../endpoints';\n\nimport formatPercent from '../utils/format-percent';\n\ninterface Props {\n  ballotName: string;\n  candidateId: string;\n  contestIsCalled: boolean;\n  isIncumbent: boolean;\n  isWinner: boolean;\n  party: string;\n  totalVotesInContest: number;\n  votes: number;\n}\n\nclass CandidateRow extends Component<Props> {\n  static Header: VNode;\n  static countyHeader: VNode;\n  static columnCount: number;\n\n  render() {\n    const {\n      ballotName,\n      contestIsCalled,\n      isIncumbent,\n      isWinner,\n      isViewable,\n      party,\n      totalVotesInContest,\n      votes,\n    } = this.props;\n  \n\n    let rowClass = cx('candidate', 'contest__candidate-row');\n\n    let checkClass = cx('check', {\n      'dem-winner': party == 'Democrat',\n      'rep-winner': party == 'Republican',\n      'lib-winner': party == 'Libertarian',\n      'ind-winner': party == 'Independent',\n      'gre-winner': party == 'Green',\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} />\n        </td>\n        <th class=\"candidate__cell candidate__name\">\n          {isWinner && isCanvass == true && (\n            <span class={checkClass}>{checkmark}</span>\n          )}\n          {isWinner && isCanvass == true ? (\n            <span class={checkClass}>{ballotName}</span>\n          ) : (\n            ballotName\n          )}{' '}\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\nCandidateRow.defaultProps = {\n  contestIsCalled: false,\n  isViewable: true,\n};\n\nCandidateRow.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\nCandidateRow.countyHeader = (\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\nCandidateRow.columnCount = 4;\n\nexport default CandidateRow;\n","const LENGTH_OF_CHECK_INTERVAL = 1000 * 60 * 2; // 2 minutes\nconst TIMERS_SHOULD_RUN = false;\n\n\nexport { LENGTH_OF_CHECK_INTERVAL, TIMERS_SHOULD_RUN };\n","import { Component, h } from 'preact';\n\n// components\nimport CandidateRow from './components/CandidateRow';\nimport Contest from './components/Contest';\nimport FramesChild from './components/FramesChild';\n\n// internal\nimport getJSON from './utils/get-json';\nimport {\n  determineContestTitle,\n  countdown,\n  lastUpdatedFormat,\n} from './election-utils';\nimport { RESULTS_IN_USE, visibleCandidatesCount } from './endpoints';\nimport { LENGTH_OF_CHECK_INTERVAL } from './constants';\nimport { PreactHTMLConverter } from 'preact-html-converter';\n\nimport context from '../../data/text.json';\n\nconst converter = PreactHTMLConverter();\n\nclass App extends Component<{ selectedContests: string[] }, {}> {\n  constructor() {\n    super();\n\n    this.state = { contests: [] };\n\n    this.fetchData = this.fetchData.bind(this);\n  }\n\n  fetchData() {\n    const now = new Date();\n\n    const selectedContests = this.props.selectedContests;\n\n    const asOf = lastUpdatedFormat(now)\n\n    getJSON(RESULTS_IN_USE).then(contests => {\n      const activeContests = contests.filter(contest => {\n        const slug = `${contest.office_slug}`;\n\n        return selectedContests.indexOf(slug) >= 0;\n      });\n\n      this.setState({ contests: activeContests, asOf }, this.startTimer);\n    });\n\n    \n  }\n\n  startTimer() {\n    this.timer = window.setTimeout(this.fetchData, LENGTH_OF_CHECK_INTERVAL);\n  }\n\n  clearTimer() {\n    window.clearTimeout(this.timer);\n  }\n\n  componentDidMount() {\n    this.fetchData();\n  }\n\n  componentWillUnmount() {\n    this.clearTimer();\n  }\n\n  componentDidUpdate() {\n                         // const length = Math.ceil(LENGTH_OF_CHECK_INTERVAL / 60000);\n                         // countdown(length); //where n is the number of minutes required.\n                       }\n\n  render() {\n    const { contests, asOf } = this.state;\n    const { annotations, flags, embedType, embedDMN } = this.props;\n\n    const isMoreText = context.status_of_race_embed == '' ? false : true;\n\n\n    return (\n      <FramesChild class=\"embed\">\n        {embedDMN != true && (\n          <div class='embed-status-boxes'>\n            <div class=\"status-current t-serif t-links-underlined\">\n              <div class=\"inner\">\n                <h3 class=\"t-copy t-copy--subheader\">\n                  Current status of election results\n                </h3>\n\n                <p class=\"t-copy\">\n                  {converter.convert(context.status_of_race[1].value[0])}\n                </p>\n\n                {isMoreText == true && (\n                  <p class=\"t-copy\" style=\"margin-top:1em;\">\n                    {converter.convert(context.status_of_race_embed[0].value)}\n                  </p>\n                )}\n              </div>\n            </div>\n\n            <div class=\"t-links-underlined t-copy disclaimer-race-explain\">\n              <div class=\"inner\">\n                <h3 class=\"t-copy t-copy--subheader\">\n                  {converter.convert(\n                  context.annotation_explain[0].value.text)}\n                </h3>\n\n                <div class=\"anno-text t-copy\">\n              \n                <span class=\"dd_winner\">✓</span>{' '}\n                <span class=\"bullet_text\">\n                  \n                  {converter.convert(\n                    context.annotation_explain[1].value.called_races_bullet\n                  )}\n                </span>\n              </div>\n              \n              <div class=\"anno-text t-copy\">\n                <svg class=\"icon anno-div note-icon\" aria-hidden=\"true\">\n                                <use xlinkHref=\"#note-icon\"></use>\n                              </svg>{' '}\n              {' '}\n                <span class=\"bullet_text\">\n                  \n                  {converter.convert(\n                    context.annotation_explain[1].value.yellow_notes_bullet\n                  )}\n                </span>\n              </div>\n\n              <div class=\"anno-text t-copy\">  \n                <span class=\"gold-star\">★</span>{' '}\n                <span class=\"bullet_text\">\n                  {converter.convert(\n                    context.annotation_explain[1].value.races_to_watch_bullet\n                  )}\n                </span>\n              </div>\n\n              <div class=\"anno-text t-copy\">\n                {converter.convert(\n                  context.annotation_explain[1].value.pills_bullet\n                )}    \n              </div>\n      \n              <div class=\"anno-text t-copy\">\n                {converter.convert(\n                  context.annotation_explain[1].value.embed_only_more_bullet\n                )}\n              </div>\n            </div>\n          </div></div>\n        )}\n        <div class=\"seat__races\">\n          {contests.map(contest => (\n            <Contest\n              key={contest.id}\n              contest={contest}\n              flags={embedDMN ? [] : flags.filter(item => item.type === contest.office_slug)}\n              tableHeader={CandidateRow.Header}\n              columnCount={CandidateRow.columnCount}\n              contestTitle={determineContestTitle(contest, 'isPartner')}\n              annotations={embedDMN ? [] : annotations.filter(item => item.type === contest.office_slug)}\n              asOf={asOf}\n              embedType={embedType}\n              renderCandidate={(\n                candidate,\n                idx,\n                viewAllCandidates,\n                { totalVotes }\n              ) => {\n                return (\n                  <CandidateRow\n                    key={candidate.id}\n                    ballotName={candidate.name}\n                    candidateId={candidate.id}\n                    isIncumbent={candidate.is_incumbent}\n                    isWinner={candidate.is_winner}\n                    isViewable={\n                      viewAllCandidates || idx < visibleCandidatesCount\n                    }\n                    party={candidate.party}\n                    totalVotesInContest={totalVotes}\n                    votes={candidate.votes}\n                  />\n                );\n              }}\n            />\n          ))}\n        </div>\n      </FramesChild>\n    );\n  }\n}\n\nexport default App;\n","import { render, h } from 'preact';\n\nimport loadJsonScript from '../utils/load-json-script';\n\nimport EmbedApp from '../EmbedApp';\nimport parseQueryString from '../utils/parse-query-string';\n\nconst { contest } = parseQueryString(location.search);\n\nconst annotations = loadJsonScript('annotations_data');\nconst flags = loadJsonScript('flag_data');\n\nlet selectedContests;\n\nif (Array.isArray(contest)) {\n  selectedContests = contest;\n} else {\n  if (contest != null) {\n    selectedContests = [contest];\n  } else {\n    selectedContests = [];\n  }\n}\n\nrender(\n  <EmbedApp\n    selectedContests={selectedContests}\n    annotations={annotations}\n    flags={flags}\n    embedType={'partner'}\n    embedDMN={partner_dmn}\n  />,\n  document.getElementById('app')\n);\n","/**\n * Converts a query string into an object, where each provided parameter is\n * turned into a key/value pair. Handles duplicate parameters by adding them\n * to an Array.\n *\n * @param  {String} qs the query string\n * @return {Object}\n */\nexport default function parseQueryString(qs) {\n  const obj = Object.create(null);\n\n  if (!qs) return obj;\n\n  // Remove any leading ?, #, or &\n  qs = qs.trim().replace(/^(\\?|#|&)/, '');\n  qs = qs.split('&');\n\n  qs.forEach(p => {\n    const [key, value] = p.split('=').map(decodeURIComponent);\n\n    if (!obj[key]) {\n      obj[key] = value;\n    } else {\n      if (!Array.isArray(obj[key])) {\n        obj[key] = [obj[key]];\n      }\n\n      obj[key].push(value);\n    }\n  });\n\n  return obj;\n}\n","var journalize = require('journalize');\n\nimport { capfirst, apdate, aptime, apmonth } from 'journalize';\n\nimport { LENGTH_OF_CHECK_INTERVAL } from './constants';\n\nconst PARTY_SORT_ORDER = [\n  'Republican',\n  'Democrat',\n  'Libertarian',\n  'Green',\n  'Independent',\n  'Write-in',\n];\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\nfunction get_directory_slug(office) {\n  return TT_directory_slugs.filter(slug => slug.office == office);\n}\n\nfunction 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\nfunction countdown(minutes) {\n  var seconds = 60;\n\n  var now = new Date().getTime();\n  // target timestamp; we will compute the remaining time\n  // relative to this date.\n  var target = new Date(now + LENGTH_OF_CHECK_INTERVAL);\n  // update frequency; note, this is flexible, and when the tab is\n  // inactive, there are no guarantees that the countdown will update\n  // at this frequency.\n  var update = 500;\n\n  var int = setInterval(function() {\n    var countdown_div = document.querySelectorAll('.countdown');\n    // current timestamp\n    var now = new Date();\n    // remaining time, in seconds\n    var remaining = (target - now) / 1000;\n\n    // if done, alert\n    if (remaining < 1 && remaining > 0) {\n      Array.prototype.forEach.call(countdown_div, function(el) {\n        el.innerHTML = 'Updating';\n      });\n      return;\n    }\n\n    if (remaining < 0) {\n      clearInterval(int);\n      return;\n    }\n\n    // format\n    var minutes = ~~(remaining / 60);\n    var seconds = ~~(remaining % 60);\n\n    // display\n    Array.prototype.forEach.call(countdown_div, function(el) {\n      el.innerHTML =\n        \"Update in <span class='counter'>\" +\n        format(minutes) +\n        ':' +\n        format(seconds) +\n        '</span>';\n    });\n  }, update);\n}\n\nconst delay = (function() {\n  var timer = 0;\n  return function(callback, ms) {\n    clearTimeout(timer);\n    timer = setTimeout(callback, ms);\n  };\n})(); \n\nfunction lastUpdated(now) {\n  // format dates to ap style\n  const formatted_date = journalize.apdate(now),\n    formatted_time = journalize.aptime(now).replace(/\\./g, ''),\n    formatted_month = journalize.apmonth(now),\n    just_day = now.getDate();\n\n  // A delay function so we can give a little time for the div .countdown to exist\n  const delay = (function() {\n    var timer = 0;\n    return function(callback, ms) {\n      clearTimeout(timer);\n      timer = setTimeout(callback, ms);\n    };\n  })(); \n\n  delay(function() {\n    var countdown_div = document.querySelectorAll('.countdown');\n    Array.prototype.forEach.call(countdown_div, function(el) {\n      el.innerHTML =\n        \"Last updated <span class='counter'>\" +\n        // formatted_month + ' ' + just_day + ', ' +\n        formatted_time +\n        '</span>';\n    });\n  }, 600); // end delay\n}\n\nfunction lastUpdatedFormat(now) {\n  // format dates to ap style\n  const formatted_date = journalize.apdate(now),\n    formatted_time = journalize.aptime(now).replace(/\\./g, ''),\n    formatted_month = journalize.apmonth(now),\n    just_day = now.getDate();\n\n  return formatted_time;\n}\n\nfunction format(num) {\n  return num < 10 ? '0' + num : num;\n}\n\nconst 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\nfunction determineDistrictTitle(contest) {\n  return `${contest.office} ${\n    contest.office === 'President' || contest.division_type === 'class'\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\nfunction determineContestTitle(contest, isPartner) {\n  if (\n    (contest.division_type === null ||\n      contest.division_type == 'class' ||\n      contest.division_type === 'seat') &&\n    isPartner !== 'isPartner'\n  )\n    return '';\n  else if (\n    (contest.division_type === null ||\n      contest.division_type == 'class' ||\n      contest.division_type === 'seat') &&\n    isPartner == 'isPartner'\n  )\n    return `${contest.office}`;\n  else return determineDistrictTitle(contest);\n}\n\nfunction determineContestTitleYourRaces(contest) {\n  return determineDistrictTitle(contest);\n}\n\nexport {\n  get_directory_slug,\n  sort_candidates_by_party,\n  countdown,\n  delay,\n  lastUpdated,\n  lastUpdatedFormat,\n  chunk,\n  determineDistrictTitle,\n  determineContestTitle,\n  determineContestTitleYourRaces,\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","// 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":""}