# Path: dividebatur/common.py
# def make_logger(name: str) -> logging.Logger:
# 
# Path: dividebatur/aecdata/utils.py
# def int_or_none(s):
#     if s == '':
#         return None
#     try:
#         return int(s)
#     except ValueError:
#         return None
# 
# def named_tuple_iter(name, reader, header, **kwargs):
#     field_names = [t for t in [t.strip().replace('-', '_')
#                                for t in header] if t]
#     typ = namedtuple(name, field_names)
#     mappings = []
#     for field_name in kwargs:
#         idx = field_names.index(field_name)
#         mappings.append((idx, kwargs[field_name]))
#     for row in reader:
#         for idx, map_fn in mappings:
#             row[idx] = map_fn(row[idx])
#         yield typ(*row)
# 
# def ticket_sort_key(ticket):
#     "sort key for an ATL ticket, eg. A..Z, AA..ZZ"
#     return (len(ticket), ticket)


import itertools
import gzip
import csv
from collections import defaultdict
from ..common import logger
from .utils import int_or_none, named_tuple_iter, ticket_sort_key
        self.state_name = state_name
        self.gvt = defaultdict(list)
        self.ticket_votes = []
        self.btl_firstprefs = {}
        self.load_tickets(gvt_csv)
        self.load_first_preferences(state_name, firstprefs_csv)

    def load_tickets(self, gvt_csv):
        with open(gvt_csv, 'rt') as fd:
            reader = csv.reader(fd)
            # skip introduction line
            next(reader)
            header = next(reader)
            # note - this assume the GVT data is formal. FIXME: add a check for this.
            it = sorted(
                named_tuple_iter('GvtRow', reader, header, PreferenceNo=int, TicketNo=int, CandidateID=int, OwnerTicket=lambda t: t.strip()),
                key=lambda gvt: (gvt.State, ticket_sort_key(gvt.OwnerTicket), gvt.TicketNo, gvt.PreferenceNo))
            for (state_ab, ticket, ticket_no), g in itertools.groupby(
                    it, lambda gvt: (gvt.State, gvt.OwnerTicket, gvt.TicketNo)):
                if state_ab != self.state_name:
                    continue
                prefs = []
                for ticket_entry in g:
                    prefs.append(ticket_entry.CandidateID)
                self.gvt[ticket].append(tuple(prefs))

    def load_first_preferences(self, state_name, firstprefs_csv):
        with open(firstprefs_csv, 'rt') as fd:
            reader = csv.reader(fd)
            next(reader)  # skip the version

# Path: dividebatur/common.py
# def make_logger(name: str) -> logging.Logger:
# 
# Path: dividebatur/aecdata/utils.py
# def int_or_none(s):
#     if s == '':
#         return None
#     try:
#         return int(s)
#     except ValueError:
#         return None
# 
# def named_tuple_iter(name, reader, header, **kwargs):
#     field_names = [t for t in [t.strip().replace('-', '_')
#                                for t in header] if t]
#     typ = namedtuple(name, field_names)
#     mappings = []
#     for field_name in kwargs:
#         idx = field_names.index(field_name)
#         mappings.append((idx, kwargs[field_name]))
#     for row in reader:
#         for idx, map_fn in mappings:
#             row[idx] = map_fn(row[idx])
#         yield typ(*row)
# 
# def ticket_sort_key(ticket):
#     "sort key for an ATL ticket, eg. A..Z, AA..ZZ"
#     return (len(ticket), ticket)


# Path: dividebatur/aecdata/pre2015.py
import itertools
import gzip
import csv
from collections import defaultdict
from ..common import logger
from .utils import int_or_none, named_tuple_iter, ticket_sort_key

        self.state_name = state_name
        self.gvt = defaultdict(list)
        self.ticket_votes = []
        self.btl_firstprefs = {}
        self.load_tickets(gvt_csv)
        self.load_first_preferences(state_name, firstprefs_csv)

    def load_tickets(self, gvt_csv):
        with open(gvt_csv, 'rt') as fd:
            reader = csv.reader(fd)
            # skip introduction line
            next(reader)
            header = next(reader)
            # note - this assume the GVT data is formal. FIXME: add a check for this.
            it = sorted(
                named_tuple_iter('GvtRow', reader, header, PreferenceNo=int, TicketNo=int, CandidateID=int, OwnerTicket=lambda t: t.strip()),
                key=lambda gvt: (gvt.State, ticket_sort_key(gvt.OwnerTicket), gvt.TicketNo, gvt.PreferenceNo))
            for (state_ab, ticket, ticket_no), g in itertools.groupby(
                    it, lambda gvt: (gvt.State, gvt.OwnerTicket, gvt.TicketNo)):
                if state_ab != self.state_name:
                    continue
                prefs = []
                for ticket_entry in g:
                    prefs.append(ticket_entry.CandidateID)
                self.gvt[ticket].append(tuple(prefs))

    def load_first_preferences(self, state_name, firstprefs_csv):
        with open(firstprefs_csv, 'rt') as fd:
            reader = csv.reader(fd)
            next(reader)  # skip the version

            header = next(reader)