This document lists the parameters that can be included in a config file suitable for input tabulation.
Config file must be valid JSON format. Examples can be found in the test_data folder.

  "tabulatorVersion" required
    version of the application that created this file
    used for migrating config data between different application versions
    example: "1.0.1"
    value: text string of length [1..1000]

  "outputSettings" required
    list of output settings and their associated parameters
    the "outputSettings" section contains the following parameters:

      "contestName" required
        the name of the contest
        used for naming output files
        example: "Portland Mayoral Race 2017"
        value: text string of length [1..1000]

      "outputDirectory" optional
        directory for output files
        if a relative path is supplied it will be appended to the current working directory
        if an absolute path is supplied it will be used as is
        example: /Path/To/TabulatorResults
        example: output_data/contest1
        value: string of length [1..1000]
        if not supplied: files will be saved to the current working directory

      "contestDate" optional
        date of the contest
        example: "2015-11-03"
        value: text string of length [1..1000]

      "contestJurisdiction" optional
        text description of the jurisdiction of this contest
        example: "Portland, ME"
        value: text string of length [1..1000]

      "contestOffice" optional
        text description of the office being contested
        example: "Mayor"
        value: text string of length [1..1000]

      "tabulateByPrecinct" optional
        tabulator will generate a results spreadsheet for each precinct
        value: true | false
        if not supplied: false

      "generateCdfJson" optional
        tabulator will generate a JSON of cast vote records in the Common Data Format
        value: true | false
        if not supplied: false

  "cvrFileSources" required
    list of input cast vote record (CVR) file paths and their associated parameters
    each "cvrFileSources" list item contains the following parameters:

      "provider" required
        text description of the vendor / machine which generated this file
        value: "cdf" | "clearBallot" | "dominion" | "ess" | "hart"

      "filePath" required
        location of the CVR file (in the case of CDF, Clear Ballot, and ES&S), or the CVR folder (in the case of Dominion and Hart)
        example: /Users/test_data/2015-portland-mayor-cvr.xlsx
        value: string of length [1..1000]

      "contestId" required when CVR source files are from a provider other than ES&S; must be blank otherwise
        the ID of the contest to tabulate, as represented in the CVR file(s)
        example: "b651b997-417a-46d9-a676-a43d4df94ddc"
        value: text string of length [1..1000]

      "firstVoteColumnIndex" required and used if and only if provider is ES&S
        index of the column (starting from 1) that contains the top-ranked candidate for each CVR
        example: 3
        value: [1..1000]

      "firstVoteRowIndex" required and used if and only if provider is ES&S
        index of the row (starting from 1) that contains the rankings for the first CVR
        example: 2
        value: [1..100000]

      "idColumnIndex" optional and can be used only if provider is ES&S
        index of the column (starting from 1) that contains the unique ID for each CVR
        example: 1
        value: [1..1000]

      "precinctColumnIndex" required and used if and only if "tabulateByPrecinct" is enabled and provider is ES&S
        index of the column (starting from 1) that contains the precinct name for each CVR
        example: 2
        value: [1..1000]

      "overvoteDelimiter" optional and can be used only if provider is ES&S; must be blank when overvoteLabel is provided
        string that will be used to split a cell into multiple candidate strings in the case of an overvote
        example: //
        value: any string that contains no backslashes and at least one character that is not a letter, number, hyphen, period, comma, apostrophe, quote, or space

      "overvoteLabel" optional and can be used only if provider is ES&S or CDF
        label used in the CVR to denote an overvote; if this parameter is present overvoteRule must be either "alwaysSkipToNextRank" or "exhaustImmediately" (because the other option, "exhaustIfMultipleContinuing", relies on knowing which specific candidates were involved in each overvote)
        example: "OVERVOTE"
        value: string of length [1..1000]

      "undervoteLabel" optional and can be used only if provider is ES&S
        the special label used in the cast vote records to denote an undervote
        example: "UNDERVOTE"
        value: string of length [1..1000]

      "undeclaredWriteInLabel" optional
        the special label used in the cast vote records to denote a vote for an undeclared write-in (i.e. a candidate who has not notified election officials that they're running for election); note that tabulator always eliminates undeclared write-ins first if present
        example: "UWI"
        value: string of length [1..1000]

      "treatBlankAsUndeclaredWriteIn" optional and can be used only if provider is ES&S
        tabulator will interpret a blank cell in a CVR as a vote for an undeclared write-in
        value: true | false
        if not supplied: false

  "candidates" required
    list of registered candidate names (including declared write-in candidates) and associated optional fields (note: leave this section empty when CVR is in Common Data Format)
    each "candidates" list item has the following parameters:

    "name" required
      full name of the registered candidate
      example: "Duson, Jill C."
      value: string of length [1..1000]

    "aliases" optional
      aliases which may appear in CVRs in addition to candidate name
      example: ["JCD"], or ["Jimmy", "Jim"]
      value: list containing string(s) of length [1..1000]

    "excluded" optional
      candidate should be ignored during tabulation
      value: true | false
      if not supplied: false

  "rules" required
    set of configuration parameters that specify the tabulation rules
    the "rules" section contains the following parameters:

      "tiebreakMode" required
        how the program should decide which candidate to eliminate when multiple candidates are tied for last place
        or which candidate to elect first when:
          1) electionWinnerMode is set to multiWinnerAllowOnlyOneWinnerPerRound, and
          2) multiple candidates exceed the winning threshold in the same round, and
          3) at least two of those candidates are tied for the highest vote total in that round
        value: "random" | "stopCountingAndAsk" | "previousRoundCountsThenRandom" | "previousRoundCountsThenAsk" | "useCandidateOrder" | "generatePermutation"

        we use java.util.random for randomness in our tiebreak implementations
        see: https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Random.html
        compatible methods exist for other languages, e.g. https://pypi.org/project/java-random/
        on tabulation start a java.util.Random object is created if required using the randomSeed value specified in the input config file:
          Random random = new Random(config.getRandomSeed());

        "random"
          during tabulation, in the event of a tie at the end of a round:
          the list of tied candidates is sorted alphabetically
          a randomDouble is generated using the random object:
            double randomDouble = random.nextDouble();
          the randomDouble is mapped to one of the tied candidates in the list:
            int randomCandidateIndex = (int) Math.floor(randomDouble * (double) tiedCandidates.size());
          the selected candidate will be the winner or loser for that round

        "stopCountingAndAsk":
          the user is presented with a list of tied candidates
          the user will input their selection manually

        "previousRoundCountsThenRandom"
          the tied candidate with the highest vote total in the previous round is selected
          if there is a tie for the vote count in the previous round as well, a candidate is selected from the still tying candidates as described under tiebreakMode "Random"

        "previousRoundCountsThenAsk"
          the tied candidate with the highest vote total in the previous round is selected
          if there is a tie for the vote count in the previous round as well, a candidate is selected from the still tying candidates as described under tiebreakMode "Stop counting and ask"

        "useCandidateOrder"
          during tabulation, in the event of a tie at the end of a round the list of candidates from the config file is consulted
          if selecting a winner the tied candidate in this round who appears earliest is selected as a winner
          if selecting a loser the tied candidate who appears latest is selected as the loser

        "generatePermutation"
          on config load candidate names are sorted alphabetically by candidate name
          a randomly ordered candidate permutation is created using Collections.shuffle() with the randomSeed specified
          in the input config file
          during tabulation, in the event of a tie at the end of a round, this permutation is consulted
          if selecting a winner: the tied candidate in this round who appears earliest is selected
          if selecting a loser: the tied candidate who appears latest is selected

      "overvoteRule" required
        how the program should handle an overvote when it encounters one
        value: "alwaysSkipToNextRank" | "exhaustImmediately" | "exhaustIfMultipleContinuing"
        "alwaysSkipToNextRank": when we encounter an overvote, ignore this rank and look at the next rank in the cast vote record
        "exhaustImmediately": exhaust a ballot as soon as we encounter an overvote
        "exhaustIfMultipleContinuing": if more than one candidate in an overvote are continuing, exhaust the ballot; if only one, assign the vote to them; if none, continue to the next rank (not valid with an ES&S source unless overvoteDelimiter is supplied)

      "winnerElectionMode" required
        whether the program should apply a special process for selecting the winner(s)
        value: "singleWinnerMajority" | "singleWinnerAlaska" | "multiWinnerAllowOnlyOneWinnerPerRound" | "multiWinnerAllowMultipleWinnersPerRound" | "bottomsUp" | "bottomsUpUsingPercentageThreshold" | "multiPassIrv"
        "singleWinnerMajority": no special process (only valid when numberOfWinners = 1)
        "singleWinnerAlaska": [ALASKA PATCH, not in stock RCTab] Alaska Statute AS 15.15.350 (only valid when numberOfWinners = 1). A majority of active ballots wins only in round 1; otherwise the last-place candidate is defeated each round until two remain and the one with more votes wins. A ranking that only repeats a candidate already ranked higher on the ballot is treated as blank (skipped) for maxSkippedRanksAllowed. continueUntilTwoCandidatesRemain, batchElimination, exhaustOnDuplicateCandidate and doesFirstRoundDetermineThreshold must be false.
        "multiWinnerAllowOnlyOneWinnerPerRound": elect no more than one winner per round, even when there are multiple candidates exceeding the winning threshold (only valid when numberOfWinners is > 1)
        "multiWinnerAllowMultipleWinnersPerRound": may elect more than one winner per round when there are multiple candidates exceeding the winning threshold (only valid when numberOfWinners is > 1)
        "bottomsUp": instead of running a standard multi-seat contest with single transferable votes, just eliminate candidates until there are numberOfWinners remaining (only valid when numberOfWinners is > 1)
        "bottomsUpUsingPercentageThreshold": instead of running a standard multi-seat contest with single transferable votes, just eliminate candidates until all remaining candidates have vote shares that meet or exceed multiSeatBottomsUpPercentageThreshold (only valid when numberOfWinners is 0)
        "multiPassIrv": instead of running a true multi-seat contest, run a series of single-seat contests and progressively exclude candidates as they win seats (only valid when numberOfWinners is > 1)

      "numberOfWinners" required
        the number of seats to be won in this contest
        note: we use fractional vote transfer to redistribute votes in multi-seat contests
        note: 0 is valid only when winnerElectionMode is set to "bottomsUpUsingPercentageThreshold"
        value: [0..number of declared candidates]

      "decimalPlacesForVoteArithmetic" required
        number of rounding decimal places when computing winning thresholds and fractional vote transfers
        note: only matters when winnerElectionMode is "multiWinnerAllowOnlyOneWinnerPerRound" or "multiWinnerAllowMultipleWinnersPerRound"
        value: [1..20]

      "minimumVoteThreshold" optional
        if a candidate receives fewer than this number of votes in the first round, they are automatically eliminated
        example: 150
        value: [0..1000000]
        if not supplied: no automatic elimination occurs (equivalent to setting it to 0)

      "maxSkippedRanksAllowed" required
        maximum number of skipped ranks (undervotes) on a ballot before the ballot should be considered exhausted; if "unlimited" is entered, a ballot will never be considered exhausted due to skipped ranks
        example: 1
        value: [unlimited, 0..1000000]

      "maxRankingsAllowed" required
        maximum number of candidates that a ballot is allowed to rank; if "max" is entered, this will default to the total number of declared candidates
        example: 15
        values: [max, 1..1000000]

      "randomSeed" required if tiebreakMode is "random", "previousRoundCountsThenRandom", or "generatePermutation"
        the integer seed for the application's pseudorandom number generator
        value: [-140737488355328..140737488355327]

      "multiSeatBottomsUpPercentageThreshold" required if winnerElectionMode is "bottomsUpUsingPercentageThreshold" and numberOfWinners is 0
        the percentage threshold used to determine when to stop the tabulation and declare winners
        note: only valid when winnerElectionMode is "bottomsUpUsingPercentageThreshold" and numberOfWinners is 0
        value: [1..100]

      "rulesDescription" optional
        text description of this rules configuration for organizing your config files -- not used by the tabulator
        Example "Maine Rules"
        value: string of length [1..1000]

      "nonIntegerWinningThreshold" optional
        the vote threshold used to determine winners can be a non-integer
        if true, threshold = V/(S+1) + 10^-d
        if false, threshold = floor(V/(S+1)) + 1
        where V = total number of votes (in the current round for single-seat or in the first round for multi-seat); S = numberOfWinners; and d = decimalPlacesForVoteArithmetic
        (note that S+1 in the formulas above becomes just S if hareQuota is set to true)
        note: only valid for multi-seat contests
        value: true | false
        if not supplied: false

      "hareQuota" optional
        the winning threshold should be computed using the Hare quota (votes divided by seats) instead of the preferred Droop quota (votes divided by (seats+1))
        note: only valid for multi-seat contests
        value: true | false
        if not supplied: false

      "batchElimination" optional
        tabulator will use batch elimination
        note: only valid for single-winner contests
        value: true | false
        if not supplied: false

      "continueUntilTwoCandidatesRemain" optional
        tabulator will keep tabulating (beyond winning round) until only two candidates remain (only valid when numberOfWinners is 1)
        value: true | false
        if not supplied: false

      "exhaustOnDuplicateCandidate" optional
        tabulator will exhaust a ballot when it encounters a duplicate candidate (instead of just skipping the duplicate)
        value: true | false
        if not supplied: false
