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" | "multiWinnerAllowOnlyOneWinnerPerRound" | "multiWinnerAllowMultipleWinnersPerRound" | "bottomsUp" | "bottomsUpUsingPercentageThreshold" | "multiPassIrv" "singleWinnerMajority": no special process (only valid when numberOfWinners = 1) "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