diff --git a/README.md b/README.md
index 55e2c9e..ce25fe3 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,26 @@
# HCP (Hulpmiddel ControleProtocol)
[](https://github.com/kiesraad/HCP/actions/workflows/test.yml?query=branch%3Amain)
-Deze repository bevat scripts die als hulpmiddel dienen voor het uitvoeren van Onderdeel A van het [Controleprotocol Centraal Stembureau](https://www.kiesraad.nl/binaries/kiesraad/documenten/publicaties/2025/08/21/controleprotocol-centraal-stembureau/Controleprotocol_Centraal_Stembureau.pdf). De scripts worden door Wonderbit op het platform teluitslagen uitgevoerd, waarbij een geüploadde `.zip` met tellingsbestanden (`.eml`) en proces verbalen in `.odt` formaat de trigger zijn.
+Deze repository bevat scripts die als hulpmiddel dienen voor het uitvoeren van Onderdeel A van het [Controleprotocol Centraal Stembureau](https://www.kiesraad.nl/binaries/kiesraad/documenten/publicaties/2025/12/16/gr26-controleprotocol-centraal-stembureau/Kiesraad+GR26+Controleprotocol+CSB.pdf). De scripts worden door Wonderbit op het platform teluitslagen uitgevoerd, waarbij een geüploadde `.zip` met daarin het tellingsbestand (`.eml`) de trigger zijn.
## Hoe voer ik het controleprotocol uit?
-De gemakkelijkste manier is met behulp van [`uv`](https://docs.astral.sh/uv/getting-started/installation/). Als `uv` geinstalleerd is, is `hcp` te draaien vanuit de root directory. Hiermee wordt automatisch de `.odt` en het `.eml.xml` bestand uit het zip bestand gehaald dat door OSV-2020 geproduceerd wordt gebruikt om `hcp` over te draaien. Bijvoorbeeld:
+De gemakkelijkste manier is met behulp van [`uv`](https://docs.astral.sh/uv/getting-started/installation/). Als `uv` geinstalleerd is, is `hcp` te draaien vanuit de root directory. Hiermee wordt automatisch het `.eml.xml` bestand uit het zip bestand gehaald dat door OSV2020-U of Abacus geproduceerd wordt om `hcp` over te draaien. Bijvoorbeeld:
```
uv run hcp definitieve-documenten_tk2060_gemeente_juinen-20600607-152117.zip
```
De output wordt weggeschreven in de directory van waaruit `hcp` aangeroepen is als `a.csv`, `b.csv` en `c.csv`.
+Het is ook mogelijk om `hcp` direct op een uitgepakt EML bestand te draaien. Bijvoorbeeld:
+
+```
+uv run hcp Telling_GR2026_Juinen_DSO.eml.xml
+```
+
---
De code is ook direct vanuit Python aan te roepen. De functie `create_csv_files` in `main.py` is het ingangspunt voor de code. Parameters voor het aanroepen van deze functie zijn:
- `path_to_xml`: het pad naar het `.eml.xml` bestand waarover je de controle uit wilt voeren. Dit is dus een EML tellingsbestand (`id=510[a-dqrs]`)
- `dest_a`, `dest_b`, `dest_c`: paden waar respectievelijk controlebestanden `a`, `b` en `c` weggeschreven moeten worden. De precieze inhoud van deze bestanden wordt hieronder beschreven
-- `path_to_odt`: optionele parameter, pad naar een proces verbaal in `.odt` formaat. Geldige bestanden zijn `Model_Na31-1.odt` voor een decentrale- en `Model_Na31-2.odt` voor een centrale stemopneming.
- `path_to_neighbourhood_data`: optionele parameter, pad naar wijkdata in `.parquet` of `.csv` formaat. In `data/` staat het meest recente beschikbare bestand. (CBS update deze eens in de zoveel tijd, dus deze zal niet altijd 100% up-to-date zijn).
## Lijst met controles
@@ -24,20 +29,8 @@ Hieronder een korte beschrijving van de controles die onderdeel zijn van HCP. De
| Naam controle | Beschrijving | Output |
|---------------|--------------|--------|
| `check_zero_votes` | Controleert of het totaal aantal stemmen (getelde + ongeldige + blanco stemmen) gelijk is aan 0 | In `b.csv` een "ja" in de kolom "Stembureau met nul stemmen" bij stembureaus waar dit het geval is |
-| `check_inexplicable_difference` | Geeft de waarde terug die ingevuld is onder 'geen verklaring' in de EML | In `a.csv` een waarde in de kolom "Aantal geen verklaring voor verschil" bij stembureaus *mits deze ongelijk is aan 0* |
-| `check_explanation_sum_difference` | Geeft het verschil tussen (het totaal aantal stemmen en het aantal toegelaten kiezers) en de som van de ingevulde verklaringen. Dus bij 6 stemmen, 5 toegelaten kiezers en een som van verklaringen van 0 is deze waarde 1 (`(6-5) - 0`) | In `a.csv` het aantal dat uit deze verschilberekening komt in de kolom "Aantal ontbrekende verklaringen voor verschil" *mits deze ongelijk is aan 0*
+| `check_vote_difference` | Berekent het verschil tussen het aantal toegelaten kiezers en het aantal uitgebrachte stemmen in de EML en geeft deze waarde terug | In `a.csv` het resultaat van deze berekening in de kolom `Niet onderzocht telverschil` *mits het GSB niet heeft aangevinkt dat dat stembureau is onderzocht vanwege een onverklaard verschil (DSO) of dat de toegelaten kiezers opnieuw zijn vastgesteld (CSO)* |
| `check_too_many_rejected_votes` | Controleert of het *percentage* blanco of ongeldige stemmen ten opzichte van het totaal aantal *uitgebrachte* stemmen groter of gelijk is aan een in te stellen percentage. | In `b.csv` een "ja (`{percentage}`%)" in de bijbehorende kolom bij stembureaus waar dit het geval is
| `check_too_many_differences` | Controleert of het absolute verschil tussen toegelaten kiezers ten het totaal aantal uitgebrachte stemmen groter of gelijk is aan een in te stellen percentage *of* absoluuut aantal. | In `b.csv` een "ja (`{percentage}`%)" of "ja (`{aantal}`)" in de bijbehorende kolom bij stembureaus waar dit het geval is
| `check_parties_with_large_percentage_difference` | Controleert of er partijen zijn die bij een stembureau een percentage stemmen heeft behaald dat ten minste een in te stellen aantal percentagepunten verschilt van het gemiddelde in die *gemeente*. Voor de berekening van het gemiddelde in die gemeente wordt het betreffende stembureau niet meegenomen | In `b.csv` de namen van de partijen waarvoor dit het geval is, gescheiden door een komma bij de stembureaus waar dit het geval is
-| `check_potentially_switched_candidates` | Controleert of voorkeursstemmen tussen twee kandidaten op dezelfde lijst mogelijk verwisseld zijn. Dat wil zeggen dat een van de kandidaten veel meer (in te stellen hoeveel) stemmen heeft gekregen dan verwacht terwijl een ander veel minder gekregen heeft dan verwacht. | In `b.csv` de paren kandidaten waarvoor dit het geval is, gescheiden door een `, ` in het formaat: *"Mogelijke verwisseling op lijst `i` (`lijstnaam`). Kandidaat `j` had `v_j` stemmen maar verwachting was `e_j`. Kandidaat `k` had `v_k` stemmen maar verwachting was `e_k`"*
-
-## .odt verwerking
-Naast de checks die hierboven beschreven zijn, kan ook het proces-verbaal dat bij een telbestand meegeleverd wordt geparsed worden. Het doel hiervan is om stembureau's te identificeren die al een hertelling uitgevoerd hebben. Als dit het geval is, dan wordt in `a.csv` de waarde "x of ja" toegevoegd aan de kolom "Al herteld". In alle gevallen moet zowel het nummer als de naam van het stembureau genoteerd staan om zeker te weten dat we deze koppelen aan het juiste stembureau in de EML. Is deze koppeling om welke reden dan ook niet mogelijk, dan gaat dit script er van uit dat er **niet** herteld is.
-
-De informatie is afkomstig uit:
-#### [Model_Na31-1.odt](https://www.rijksoverheid.nl/onderwerpen/verkiezingen/documenten/publicaties/2022/11/18/model-na-31-1)
-Stembureaus die onder **3b.** of **3c.** genoteerd staan.
-
-#### [Model_Na31-2.odt](https://www.rijksoverheid.nl/onderwerpen/verkiezingen/documenten/publicaties/2022/11/18/model-na-31-2)
-Stembureaus die onder **7.** genoteerd staan.
-
+| `check_potentially_switched_candidates` | Controleert of voorkeursstemmen tussen twee kandidaten op dezelfde lijst mogelijk verwisseld zijn. Dat wil zeggen dat een van de kandidaten veel meer (in te stellen hoeveel) stemmen heeft gekregen dan verwacht terwijl een ander veel minder gekregen heeft dan verwacht. Hierbij kunnen stembureaus welke in de voorspelling te veel ruis hebben om een goede controle te doen uitgesloten worden (in te stellen in `eml_types::SwitchedCandidateConfig`) | In `b.csv` de paren kandidaten waarvoor dit het geval is, gescheiden door een `, ` in het formaat: *"Mogelijke verwisseling op lijst `i` (`lijstnaam`). Kandidaat `j` had `v_j` stemmen maar verwachting was `e_j`. Kandidaat `k` had `v_k` stemmen maar verwachting was `e_k`"*
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 500d13e..b6f4d2c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "hcp"
-version = "1.0"
+version = "1.1"
description = "Hulpmiddel controle protocol. Scripts ter ondersteuning van onderdeel A van het Controleprotocol Centraal Stembureau."
requires-python = "~= 3.12.0"
readme = "README.md"
diff --git a/src/hcp/cli.py b/src/hcp/cli.py
index 8fee72f..801adf6 100644
--- a/src/hcp/cli.py
+++ b/src/hcp/cli.py
@@ -8,12 +8,16 @@
CURRENT_NEIGHBOURHOOD_FILE = "zip_to_neighbourhood_2024.parquet"
p = argparse.ArgumentParser()
-p.add_argument("data_source", help="The election result to run HCP on.")
+p.add_argument(
+ "data_source",
+ help="The election result to run HCP on. Can be a path to either a .zip file as output by OSV-2020U/Abacus or directly to a .eml.xml file.",
+)
p.add_argument("--neighbourhoods", required=False)
def start():
- """Helper CLI tool to run HCP on either a .zip file as output by OSV-2020U"""
+ """Helper CLI tool to run HCP on either a .zip file as output by OSV-2020U/Abacus
+ or directly on an .eml.xml file"""
args = p.parse_args()
extract_path = Path() / "tmp"
@@ -49,14 +53,11 @@ def start():
return
file_suffix = Path(args.data_source).suffix
- # If we were supplied a zip file we unpack it and use the supplied odt
+ # If we were supplied a zip file we unpack it so we can access the xml
if file_suffix == ".zip":
with ZipFile(args.data_source, "r") as outer_zipfile:
try:
# Find and extract the .eml.xml and .odt file
- odt_zipinfo = next(
- f for f in outer_zipfile.filelist if f.filename.endswith(".odt")
- )
inner_zipinfo = next(
f for f in outer_zipfile.filelist if f.filename.endswith(".zip")
)
@@ -67,7 +68,6 @@ def start():
if f.filename.endswith(".eml.xml")
)
inner_zipfile.extract(eml_zipinfo, extract_path)
- outer_zipfile.extract(odt_zipinfo, extract_path)
except StopIteration:
print(
"""Zip file did not contain expected files! Make sure to specify the direct OSV-2020U output.
@@ -81,7 +81,6 @@ def start():
# Run HCP
create_csv_files(
path_to_xml=str(extract_path / eml_zipinfo.filename),
- path_to_odt=str(extract_path / odt_zipinfo.filename),
path_to_neighbourhood_data=str(neighbourhood_file),
dest_a="a.csv",
dest_b="b.csv",
@@ -90,7 +89,6 @@ def start():
# Clean up after ourselves
remove(extract_path / eml_zipinfo.filename)
- remove(extract_path / odt_zipinfo.filename)
try:
rmdir(extract_path)
except OSError as error:
@@ -102,7 +100,6 @@ def start():
elif file_suffix == ".xml":
create_csv_files(
path_to_xml=args.data_source,
- path_to_odt=None,
path_to_neighbourhood_data=str(neighbourhood_file),
dest_a="a.csv",
dest_b="b.csv",
diff --git a/src/hcp/csv_write.py b/src/hcp/csv_write.py
index b93aa3f..658bd9b 100644
--- a/src/hcp/csv_write.py
+++ b/src/hcp/csv_write.py
@@ -21,7 +21,7 @@
"Stembureaunummer",
"Stembureaunaam",
]
-PROTOCOL_VERSION = "TK2025"
+PROTOCOL_VERSION = "GR2026"
ZIP_CODE_PATTERN = re.compile(r"\(\s*postcode:\s*\d{4}\s*[A-Z]{2}\s*\)")
STEMBUREAU_PREFIX_PATTERN = re.compile(r"^(Stembureau\s)+")
@@ -100,7 +100,6 @@ def _id_cols(
def write_csv_a(
check_results: Dict[str, CheckResult],
eml_metadata: EmlMetadata,
- odt_used: bool,
csv_destination,
) -> None:
with open(csv_destination, "w", newline="", encoding="utf-8") as csvfile:
@@ -108,32 +107,27 @@ def write_csv_a(
_write_header(
writer,
eml_metadata,
- f"Stembureaus met geen verklaring voor telverschillen (odt {("gebruikt" if odt_used else "niet gebruikt")})",
+ "Stembureaus met niet onderzochte telverschillen",
)
writer.writerow(
HEADER_COLS
+ [
- "Aantal geen verklaring voor verschil",
- "Aantal ontbrekende verklaringen voor verschil",
+ "Niet onderzocht telverschil",
"Al herteld",
"Samenvatting",
]
)
for id, results in check_results.items():
- inexplicable_difference = results.inexplicable_difference or None
- explanation_sum_difference = results.explanation_sum_difference or None
+ difference = results.vote_difference
already_recounted = "ja" if results.already_recounted else None
- if (
- inexplicable_difference or explanation_sum_difference
- ) and not results.already_recounted:
+ if (difference > 0) and not results.already_recounted:
writer.writerow(
_id_cols(eml_metadata, id, "A")
+ [
- inexplicable_difference,
- explanation_sum_difference,
+ difference,
already_recounted,
results.summarise(SummaryType.A),
]
diff --git a/src/hcp/eml.py b/src/hcp/eml.py
index 1dd13ff..935360e 100644
--- a/src/hcp/eml.py
+++ b/src/hcp/eml.py
@@ -32,7 +32,7 @@ class EML:
DIFF_VOTE_THRESHOLD_PCT: ClassVar[float] = 2.0
DIFF_VOTE_THRESHOLD: ClassVar[int] = 15
- PARTY_DIFFERENCE_THRESHOLD_PCT: ClassVar[float] = 50.0
+ PARTY_DIFFERENCE_THRESHOLD_PCT: ClassVar[float] = 60.0
SWITCHED_CANDIDATE_CONFIG: ClassVar[SwitchedCandidateConfig] = (
SwitchedCandidateConfig(
@@ -40,6 +40,7 @@ class EML:
minimum_reporting_units_neighbourhood=5,
minimum_deviation_factor=5,
minimum_votes=15,
+ maximum_rmse=4.0,
)
)
# ---
@@ -70,12 +71,7 @@ def run_protocol(
for polling_station_id, polling_station in self.reporting_units_info.items():
check_result = CheckResult(
zero_votes=protocol_checks.check_zero_votes(polling_station),
- inexplicable_difference=protocol_checks.check_inexplicable_difference(
- polling_station
- ),
- explanation_sum_difference=protocol_checks.check_explanation_sum_difference(
- polling_station
- ),
+ vote_difference=protocol_checks.check_vote_difference(polling_station),
high_invalid_vote_percentage=protocol_checks.check_too_many_rejected_votes(
polling_station, "ongeldig", EML.INVALID_VOTE_THRESHOLD_PCT
),
@@ -103,7 +99,7 @@ def run_protocol(
reporting_neighbourhoods,
EML.SWITCHED_CANDIDATE_CONFIG,
),
- already_recounted=False,
+ already_recounted=polling_station.has_recounted,
)
protocol_results[polling_station_id] = check_result
diff --git a/src/hcp/eml_types.py b/src/hcp/eml_types.py
index 65368d2..d1c108c 100644
--- a/src/hcp/eml_types.py
+++ b/src/hcp/eml_types.py
@@ -53,6 +53,7 @@ class ReportingUnitInfo:
uncounted_votes: Dict[str, int]
votes_per_party: Dict[PartyIdentifier, int]
votes_per_candidate: Dict[CandidateIdentifier, int]
+ has_recounted: bool = False
@dataclass
@@ -114,6 +115,7 @@ class SwitchedCandidateConfig:
minimum_reporting_units_neighbourhood: int
minimum_deviation_factor: int
minimum_votes: int
+ maximum_rmse: Optional[float]
class SummaryType(Enum):
@@ -128,8 +130,7 @@ class CheckResult:
"""
zero_votes: bool
- inexplicable_difference: int
- explanation_sum_difference: int
+ vote_difference: int
high_invalid_vote_percentage: Optional[float]
high_blank_vote_percentage: Optional[float]
high_vote_difference: Optional[VoteDifference]
@@ -162,33 +163,18 @@ def render(self, recounted: bool, summary_type: SummaryType) -> str:
result = "".join(self.content)
# Only add if we've recounted for type A (differences)
- if summary_type == SummaryType.A:
- result += f" Er is {'wel' if recounted else 'niet'} herteld."
+ if summary_type == SummaryType.A and not recounted:
+ result += """ Volgens het GSB is dit niet herteld of onderzocht."""
return result
sentence = Sentence()
if summary_type == SummaryType.A:
- if self.inexplicable_difference and not self.explanation_sum_difference:
- sentence.add(
- "een onverklaard verschil tussen het aantal toegelaten kiezers en "
- f"het aantal getelde stembiljetten van {self.inexplicable_difference}"
- )
- elif self.explanation_sum_difference and not self.inexplicable_difference:
- sentence.add(
- "een onverklaard verschil tussen het aantal toegelaten kiezers en het "
- f"aantal getelde stembiljetten van {self.explanation_sum_difference}. "
- "In het proces-verbaal tellen de verklaringen die gegeven zijn niet op tot "
- "het verschil tussen het aantal toegelaten kiezers en het aantal getelde stembiljetten"
- )
- elif self.explanation_sum_difference and self.inexplicable_difference:
- sentence.add(
- "een onverklaard verschil tussen het aantal toegelaten kiezers en het aantal "
- f"getelde stembiljetten van {self.inexplicable_difference + self.explanation_sum_difference}. "
- f"In het proces-verbaal is ingevuld dat er {self.inexplicable_difference} keer geen verklaring "
- "is voor het verschil. De verklaringen die gegeven zijn tellen niet op tot het totale verschil"
- )
+ sentence.add(
+ "een verschil tussen het aantal toegelaten kiezers en "
+ f"het aantal getelde stembiljetten van {self.vote_difference}"
+ )
elif summary_type == SummaryType.B:
if self.zero_votes:
diff --git a/src/hcp/main.py b/src/hcp/main.py
index 3b71494..46c5351 100644
--- a/src/hcp/main.py
+++ b/src/hcp/main.py
@@ -3,7 +3,6 @@
from . import csv_write
from .eml import EML
from .neighbourhood import NeighbourhoodData
-from .odt import ODT
def create_csv_files(
@@ -11,7 +10,6 @@ def create_csv_files(
dest_a: str,
dest_b: str,
dest_c: str,
- path_to_odt: Optional[str] = None,
path_to_neighbourhood_data: Optional[str] = None,
) -> None:
"""Main entry point for running HCP on a given .eml.xml file. We can optionally specify
@@ -41,34 +39,7 @@ def create_csv_files(
check_results = eml.run_protocol(neighbourhood_data=neighbourhood_data)
eml_metadata = eml.metadata
- # If odt_path is specified we try to read the file and extract the relevant
- # parts, as a precaution we will not fail if anything goes wrong here, but
- # simply return 'None' for the odt object and then the empty list for the
- # already recounted variable
- odt = ODT.from_path(path_to_odt)
- if odt:
- recounted_polling_stations = odt.get_already_recounted_polling_stations()
- for polling_station in recounted_polling_stations:
- # Reconstruct the full polling station identifier
- full_id = f"{eml_metadata.authority_id}::SB{polling_station.id}"
-
- # Make sure that the name of the polling station matches so that
- # we are absolutely sure that the polling station in the eml
- # matches with the one in the odt.
- polling_station_name_eml = eml_metadata.reporting_unit_names.get(full_id)
- polling_station_name_odt = (
- f"Stembureau {polling_station.name} {polling_station.zip}"
- if polling_station.zip
- else f"Stembureau {polling_station.name}"
- )
-
- if (
- full_id in check_results.keys()
- and polling_station_name_eml == polling_station_name_odt
- ):
- check_results[full_id].already_recounted = True
-
- csv_write.write_csv_a(check_results, eml_metadata, odt is not None, dest_a)
+ csv_write.write_csv_a(check_results, eml_metadata, dest_a)
csv_write.write_csv_b(
check_results, eml_metadata, neighbourhood_data is not None, dest_b
)
diff --git a/src/hcp/odt.py b/src/hcp/odt.py
deleted file mode 100644
index 336a268..0000000
--- a/src/hcp/odt.py
+++ /dev/null
@@ -1,150 +0,0 @@
-from dataclasses import dataclass
-from enum import Enum, auto
-from typing import List, Optional
-from xml.etree.ElementTree import Element as XmlElement
-from zipfile import ZipFile
-
-from . import xml_parser
-
-NAMESPACE = {
- "office": "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
- "table": "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
- "text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
-}
-
-
-class ODT_TYPE(Enum):
- """Enumeration of the different types of PV (Proces verbaal)"""
-
- na31_1 = auto()
- na31_2 = auto()
-
-
-@dataclass(frozen=True)
-class PollingStation:
- """Polling station identifier used for comparing different polling stations"""
-
- id: int
- name: str
- zip: Optional[str]
-
-
-@dataclass
-class ODT:
- """Container for an ODT file (proces verbaal) which specifies the type of PV
- and the XML `ElementTree` of the contents of the ODT file.
- """
-
- type: ODT_TYPE
- odt_xml: XmlElement
-
- @staticmethod
- def from_path(odt_path: Optional[str]) -> Optional["ODT"]:
- """Constrcuts an `ODT` instance from a given file path.
-
- Returns:
- ODT class instance with all needed fields set for running methods.
- """
- if not odt_path:
- return None
-
- try:
- if "Model_Na31-1.odt" in odt_path:
- return ODT(
- type=ODT_TYPE.na31_1, odt_xml=_extract_odt_xml_root(odt_path)
- )
- elif "Model_Na31-2.odt" in odt_path:
- return ODT(
- type=ODT_TYPE.na31_2, odt_xml=_extract_odt_xml_root(odt_path)
- )
- except Exception:
- return None
-
- def get_already_recounted_polling_stations(self) -> List[PollingStation]:
- """Get a list of polling stations which according to the ODT (PV)
- have already recounted.
-
- Returns:
- List of polling stations, list is empty if either no polling stations recounted
- or some exception occurred when parsing the XML DOM-tree
- """
- try:
- if self.type == ODT_TYPE.na31_1:
- return _get_polling_stations_with_recounts_na31_1(self.odt_xml)
- elif self.type == ODT_TYPE.na31_2:
- return _get_polling_stations_with_recounts_na31_2(self.odt_xml)
- else:
- raise RuntimeError("Unreachable code path")
- except Exception:
- return []
-
-
-def _extract_odt_xml_root(odt_file):
- with ZipFile(odt_file) as odt_zip:
- with odt_zip.open("content.xml") as odt_xml:
- return xml_parser.parse_xml(odt_xml)
-
-
-def _table_rows_to_polling_stations(
- table_rows: List[XmlElement],
-) -> List[PollingStation]:
- polling_stations = set()
-
- for table_row in table_rows:
- # Get three different span elements which describe the polling station
- # the first contains the id, the second the name and the third optionally
- # the zip code
- polling_station_descriptors = table_row.findall(
- ".//text:span[@text:description]", NAMESPACE
- )
-
- polling_station_id = xml_parser._get_text(polling_station_descriptors[0])
- polling_station_name = xml_parser._get_text(polling_station_descriptors[1])
- polling_station_zip = xml_parser._get_text(polling_station_descriptors[2])
-
- # Polling station id and name is *required* to be sure that a polling station
- # can be matched. Thus if these are not present we skip this polling station.
- if polling_station_id is None or polling_station_name is None:
- continue
-
- polling_stations.add(
- PollingStation(
- id=int(polling_station_id),
- name=polling_station_name,
- zip=polling_station_zip,
- )
- )
-
- return list(polling_stations)
-
-
-def _get_polling_stations_with_recounts_na31_1(
- odt_root: XmlElement,
-) -> List[PollingStation]:
- polling_stations_3b_a = odt_root.findall(
- "./office:body/office:text/table:table[@table:name='NieuweTelling']/table:table-row",
- NAMESPACE,
- )
- polling_stations_3b_b = odt_root.findall(
- "./office:body/office:text/table:table[@table:name='CorrigendumGeenVerklaring']/table:table-row",
- NAMESPACE,
- )
- polling_stations_3c = odt_root.findall(
- "./office:body/office:text/table:table[@table:name='Tabelle3']/table:table-row",
- NAMESPACE,
- )
-
- return _table_rows_to_polling_stations(
- polling_stations_3b_a + polling_stations_3b_b + polling_stations_3c
- )
-
-
-def _get_polling_stations_with_recounts_na31_2(
- odt_root: XmlElement,
-) -> List[PollingStation]:
- polling_stations = odt_root.findall(
- "./office:body/office:text/table:table[@table:name='NieuweTelling']/table:table-row",
- NAMESPACE,
- )
-
- return _table_rows_to_polling_stations(polling_stations)
diff --git a/src/hcp/protocol_checks.py b/src/hcp/protocol_checks.py
index e31fcce..5ca3f8f 100644
--- a/src/hcp/protocol_checks.py
+++ b/src/hcp/protocol_checks.py
@@ -1,4 +1,5 @@
from itertools import product as cartesian_product
+from math import sqrt
from typing import Dict, List, Literal, Optional, TypeVar
from .eml_types import (
@@ -29,57 +30,8 @@ def check_zero_votes(reporting_unit: ReportingUnitInfo) -> bool:
return _get_total_votes(reporting_unit) == 0
-def check_inexplicable_difference(reporting_unit: ReportingUnitInfo) -> int:
- """Returns the amount of **specified** inexplicable differences.
-
- Args:
- reporting_unit: The reporting unit to check.
-
- Returns:
- Integer representing the amount of specified inexplicable differences.
- """
- return reporting_unit.uncounted_votes["geen verklaring"]
-
-
-def check_explanation_sum_difference(reporting_unit: ReportingUnitInfo) -> int:
- """Calculates the difference between the total valid votes and the
- admitted voters. If the specified explanations do not sum up to this
- difference between amount of votes and admitted voters, then these are
- seen as inexplicable differences as well.
-
- Args:
- reporting_unit: The reporting unit to check.
-
- Returns:
- Integer representing the implicit inexplicable votes.
- """
- vote_metadata = reporting_unit.uncounted_votes
-
- vote_difference = (
- _get_total_votes(reporting_unit) - vote_metadata["toegelaten kiezers"]
- )
-
- if vote_difference > 0:
- return abs(
- vote_difference
- - (vote_metadata.get("te veel uitgereikte stembiljetten") or 0)
- - (vote_metadata.get("te veel briefstembiljetten") or 0)
- - (vote_metadata.get("geen verklaring") or 0)
- - (vote_metadata.get("andere verklaring") or 0)
- )
-
- if vote_difference < 0:
- return abs(
- vote_difference
- + (vote_metadata.get("meegenomen stembiljetten") or 0)
- + (vote_metadata.get("te weinig uitgereikte stembiljetten") or 0)
- + (vote_metadata.get("geen briefstembiljetten") or 0)
- + (vote_metadata.get("kwijtgeraakte stembiljetten") or 0)
- + (vote_metadata.get("geen verklaring") or 0)
- + (vote_metadata.get("andere verklaring") or 0)
- )
-
- return 0
+def check_vote_difference(reporting_unit: ReportingUnitInfo) -> int:
+ return _get_differences(reporting_unit)
def check_too_many_rejected_votes(
@@ -263,6 +215,7 @@ def check_potentially_switched_candidates(
minimum_reporting_units=config.minimum_reporting_units_municipality,
minimum_deviation_factor=config.minimum_deviation_factor,
minimum_votes=config.minimum_votes,
+ max_rmse=config.maximum_rmse,
)
potentially_switched_neighbourhood_candidates = (
@@ -275,6 +228,7 @@ def check_potentially_switched_candidates(
minimum_reporting_units=config.minimum_reporting_units_neighbourhood,
minimum_deviation_factor=config.minimum_deviation_factor,
minimum_votes=config.minimum_votes,
+ max_rmse=config.maximum_rmse,
)
if neighbourhood_reference_group and reporting_neighbourhoods
else None
@@ -336,10 +290,11 @@ def _get_potentially_switched_candidates(
minimum_reporting_units: int,
minimum_deviation_factor: int,
minimum_votes: int,
-) -> List[SwitchedCandidate]:
+ max_rmse: Optional[float],
+) -> Optional[List[SwitchedCandidate]]:
# Not enough reporting units to do a good check
if amount_of_reporting_units < minimum_reporting_units:
- return []
+ return None
received_votes = reporting_unit.votes_per_candidate
expected_votes = _get_expected_candidate_votes(main_unit, reporting_unit)
@@ -369,6 +324,20 @@ def _get_potentially_switched_candidates(
cands_with_more_votes, cands_with_less_votes
):
if cand_with_more.party == cand_with_less.party:
+ if max_rmse is not None:
+ # Do RMSE calculation to see if reporting unit is sufficiently 'non-noisy'
+ # to do a proper check.
+ se = 0
+ exclude = [cand_with_less, cand_with_more]
+ for cand_id in received_votes.keys():
+ # Do not use the suspected switch in calculating the RMSE, since this
+ # is 'expected noise'.
+ if cand_id not in exclude:
+ se += (received_votes[cand_id] - expected_votes[cand_id]) ** 2
+ # RMSE exceeds threshold, do not add candidate pair to result
+ if sqrt(se / (len(received_votes) - len(exclude))) > max_rmse:
+ continue
+
result.append(
SwitchedCandidate(
candidate_with_fewer=cand_with_less,
@@ -413,13 +382,16 @@ def _get_candidate_ratios(
def _get_switched_candidate_combination(
- municipality_switched: List[SwitchedCandidate],
+ municipality_switched: Optional[List[SwitchedCandidate]],
neighbourhood_switched: Optional[List[SwitchedCandidate]],
) -> List[SwitchedCandidate]:
# If there are no neighbourhood results (i.e. the neighbourhood check did not run)
# then we just return the municipality results
if neighbourhood_switched is None:
- return municipality_switched
+ return municipality_switched if municipality_switched is not None else []
+
+ if municipality_switched is None:
+ return []
# Otherwise, we only return those for which there was a neighbourhood result
# Construct lookup tables
diff --git a/src/hcp/xml_parser.py b/src/hcp/xml_parser.py
index 431c579..6fe6c46 100644
--- a/src/hcp/xml_parser.py
+++ b/src/hcp/xml_parser.py
@@ -50,7 +50,10 @@ def get_eml_type(root: XmlElement) -> Optional[str]:
The ID of the EML file (e.g. `"510b"` for municipality counts).
"""
root_element = root.find(".")
- if root_element is not None and root_element.tag == f"{{{NAMESPACE.get('eml')}}}EML":
+ if (
+ root_element is not None
+ and root_element.tag == f"{{{NAMESPACE.get('eml')}}}EML"
+ ):
return _get_attrib(root_element, "Id")
return None
@@ -207,6 +210,10 @@ def get_reporting_unit_info(reporting_unit: XmlElement) -> ReportingUnitInfo:
# Fetch amount of votes per party
(votes_per_party, votes_per_candidate) = _get_party_and_candvotes(reporting_unit)
+ # Fetch reporting unit investigations (did the reporting unit do a recount
+ # due to unexplained differences)
+ recounted = _get_has_recounted(reporting_unit)
+
return ReportingUnitInfo(
reporting_unit_id=reporting_unit_id,
reporting_unit_name=reporting_unit_name,
@@ -216,6 +223,7 @@ def get_reporting_unit_info(reporting_unit: XmlElement) -> ReportingUnitInfo:
uncounted_votes=uncounted_votes,
votes_per_party=votes_per_party,
votes_per_candidate=votes_per_candidate,
+ has_recounted=recounted,
)
@@ -340,3 +348,22 @@ def _get_party_and_candvotes(
raise InvalidEmlException
return (party_votes_dict, cand_votes_dict)
+
+
+def _get_has_recounted(reporting_unit: XmlElement) -> bool:
+ investigations = reporting_unit.find("./kr:ReportingUnitInvestigations", NAMESPACE)
+ if investigations is not None:
+ for investigation in investigations.findall("./kr:Investigation", NAMESPACE):
+ reason_code = _get_attrib(investigation, "ReasonCode")
+ if (
+ reason_code
+ in [
+ # DSO reason code
+ "onderzocht vanwege onverklaard verschil",
+ # CSO reason code
+ "toegelaten kiezers opnieuw vastgesteld",
+ ]
+ and _get_text(investigation) == "true"
+ ):
+ return True
+ return False
diff --git a/test/data/FAKE_TEST_DATA_TK2023_DORDRECHT/Fake_test_data_Telling_TK2023_gemeente_Dordrecht.eml.xml b/test/data/FAKE_TEST_DATA_TK2023_DORDRECHT/Fake_test_data_Telling_TK2023_gemeente_Dordrecht.eml.xml
index a416770..d37e5f3 100644
--- a/test/data/FAKE_TEST_DATA_TK2023_DORDRECHT/Fake_test_data_Telling_TK2023_gemeente_Dordrecht.eml.xml
+++ b/test/data/FAKE_TEST_DATA_TK2023_DORDRECHT/Fake_test_data_Telling_TK2023_gemeente_Dordrecht.eml.xml
@@ -395,6 +395,9 @@
0
2
0
+
+ true
+
diff --git a/test/data/FAKE_TEST_DATA_TK2023_DORDRECHT/Model_Na31-1.odt b/test/data/FAKE_TEST_DATA_TK2023_DORDRECHT/Model_Na31-1.odt
deleted file mode 100644
index e07b14d..0000000
Binary files a/test/data/FAKE_TEST_DATA_TK2023_DORDRECHT/Model_Na31-1.odt and /dev/null differ
diff --git a/test/data/e2e/FAKE_TEST_DATA_Telling_GR2026_Juinen_CSO.eml.xml b/test/data/e2e/FAKE_TEST_DATA_Telling_GR2026_Juinen_CSO.eml.xml
new file mode 100644
index 0000000..5cc3df8
--- /dev/null
+++ b/test/data/e2e/FAKE_TEST_DATA_Telling_GR2026_Juinen_CSO.eml.xml
@@ -0,0 +1,7844 @@
+
+ 1
+
+ Juinen
+
+
+ 2026-01-16T09:52:35.123
+
+
+
+
+
+ Gemeenteraad Juinen 2026
+ GR
+ GR1
+ Juinen
+ 2026-03-18
+
+
+
+
+
+
+
+ Het Verschil
+
+ 1500
+
+
+
+
+
+ 450
+
+
+
+
+
+ 315
+
+
+
+
+
+ 221
+
+
+
+
+
+ 154
+
+
+
+
+
+ 108
+
+
+
+
+
+ 211
+
+
+
+
+
+ 16
+
+
+
+
+
+ 1
+
+
+
+
+
+ 19
+
+
+
+
+
+ 1
+
+
+
+
+
+ 2
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Kleurenpartij
+
+ 3000
+
+
+
+
+
+ 900
+
+
+
+
+
+ 630
+
+
+
+
+
+ 441
+
+
+
+
+
+ 309
+
+
+
+
+
+ 216
+
+
+
+
+
+ 405
+
+
+
+
+
+ 9
+
+
+
+
+
+ 67
+
+
+
+
+
+ 4
+
+
+
+
+
+ 16
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Nieuw Geluid
+
+ 500
+
+
+
+
+
+ 150
+
+
+
+
+
+ 105
+
+
+
+
+
+ 74
+
+
+
+
+
+ 51
+
+
+
+
+
+ 36
+
+
+
+
+
+ 55
+
+
+
+
+
+ 6
+
+
+
+
+
+ 0
+
+
+
+
+
+ 16
+
+
+
+
+
+ 7
+
+
+
+ Planetenpartij
+
+ 2500
+
+
+
+
+
+ 750
+
+
+
+
+
+ 525
+
+
+
+
+
+ 368
+
+
+
+
+
+ 257
+
+
+
+
+
+ 180
+
+
+
+
+
+ 6
+
+
+
+
+
+ 250
+
+
+
+
+
+ 73
+
+
+
+
+
+ 16
+
+
+
+
+
+ 39
+
+
+
+
+
+ 11
+
+
+
+
+
+ 20
+
+
+
+
+
+ 5
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Planten voor het Volk
+
+ 1300
+
+
+
+
+
+ 390
+
+
+
+
+
+ 273
+
+
+
+
+
+ 191
+
+
+
+
+
+ 134
+
+
+
+
+
+ 94
+
+
+
+
+
+ 74
+
+
+
+
+
+ 59
+
+
+
+
+
+ 55
+
+
+
+
+
+ 6
+
+
+
+
+
+ 16
+
+
+
+
+
+ 1
+
+
+
+
+
+ 5
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Prozen en Poëzie
+
+ 1000
+
+
+
+
+
+ 300
+
+
+
+
+
+ 210
+
+
+
+
+
+ 147
+
+
+
+
+
+ 103
+
+
+
+
+
+ 72
+
+
+
+
+
+ 16
+
+
+
+
+
+ 147
+
+
+
+
+
+ 2
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Smaak
+
+ 800
+
+
+
+
+
+ 240
+
+
+
+
+
+ 168
+
+
+
+
+
+ 118
+
+
+
+
+
+ 82
+
+
+
+
+
+ 58
+
+
+
+
+
+ 19
+
+
+
+
+
+ 54
+
+
+
+
+
+ 9
+
+
+
+
+
+ 33
+
+
+
+
+
+ 13
+
+
+
+
+
+ 3
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Sportpartij
+
+ 700
+
+
+
+
+
+ 210
+
+
+
+
+
+ 147
+
+
+
+
+
+ 103
+
+
+
+
+
+ 72
+
+
+
+
+
+ 50
+
+
+
+
+
+ 5
+
+
+
+
+
+ 76
+
+
+
+
+
+ 27
+
+
+
+
+
+ 10
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Weermannen
+
+ 400
+
+
+
+
+
+ 120
+
+
+
+
+
+ 84
+
+
+
+
+
+ 59
+
+
+
+
+
+ 41
+
+
+
+
+
+ 29
+
+
+
+
+
+ 38
+
+
+
+
+
+ 2
+
+
+
+
+
+ 14
+
+
+
+
+
+ 7
+
+
+
+
+
+ 5
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 300
+
+
+
+
+
+ 90
+
+
+
+
+
+ 63
+
+
+
+
+
+ 44
+
+
+
+
+
+ 31
+
+
+
+
+
+ 22
+
+
+
+
+
+ 2
+
+
+
+
+
+ 3
+
+
+
+
+
+ 1
+
+
+
+
+
+ 17
+
+
+
+
+
+ 17
+
+
+
+
+
+ 9
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+ 18500
+ 12000
+ 39
+ 81
+ 13000
+ 1040
+ 14040
+ 50
+ 1970
+
+
+ Stembureau Purmerland (postcode: 4111 PR)
+
+
+ Het Verschil
+
+ 750
+
+
+
+
+
+ 225
+
+
+
+
+
+ 157
+
+
+
+
+
+ 110
+
+
+
+
+
+ 77
+
+
+
+
+
+ 54
+
+
+
+
+
+ 106
+
+
+
+
+
+ 8
+
+
+
+
+
+ 1
+
+
+
+
+
+ 9
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Kleurenpartij
+
+ 1500
+
+
+
+
+
+ 450
+
+
+
+
+
+ 315
+
+
+
+
+
+ 220
+
+
+
+
+
+ 154
+
+
+
+
+
+ 109
+
+
+
+
+
+ 202
+
+
+
+
+
+ 4
+
+
+
+
+
+ 34
+
+
+
+
+
+ 2
+
+
+
+
+
+ 8
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Nieuw Geluid
+
+ 250
+
+
+
+
+
+ 75
+
+
+
+
+
+ 53
+
+
+
+
+
+ 35
+
+
+
+
+
+ 26
+
+
+
+
+
+ 16
+
+
+
+
+
+ 28
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 10
+
+
+
+
+
+ 4
+
+
+
+ Planetenpartij
+
+ 1250
+
+
+
+
+
+ 375
+
+
+
+
+
+ 262
+
+
+
+
+
+ 184
+
+
+
+
+
+ 128
+
+
+
+
+
+ 90
+
+
+
+
+
+ 3
+
+
+
+
+
+ 125
+
+
+
+
+
+ 37
+
+
+
+
+
+ 8
+
+
+
+
+
+ 19
+
+
+
+
+
+ 6
+
+
+
+
+
+ 10
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Planten voor het Volk
+
+ 650
+
+
+
+
+
+ 195
+
+
+
+
+
+ 136
+
+
+
+
+
+ 95
+
+
+
+
+
+ 67
+
+
+
+
+
+ 47
+
+
+
+
+
+ 37
+
+
+
+
+
+ 29
+
+
+
+
+
+ 28
+
+
+
+
+
+ 3
+
+
+
+
+
+ 8
+
+
+
+
+
+ 1
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Prozen en Poëzie
+
+ 500
+
+
+
+
+
+ 150
+
+
+
+
+
+ 105
+
+
+
+
+
+ 74
+
+
+
+
+
+ 52
+
+
+
+
+
+ 36
+
+
+
+
+
+ 8
+
+
+
+
+
+ 73
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Smaak
+
+ 400
+
+
+
+
+
+ 120
+
+
+
+
+
+ 84
+
+
+
+
+
+ 59
+
+
+
+
+
+ 41
+
+
+
+
+
+ 29
+
+
+
+
+
+ 10
+
+
+
+
+
+ 27
+
+
+
+
+
+ 4
+
+
+
+
+
+ 16
+
+
+
+
+
+ 6
+
+
+
+
+
+ 2
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Sportpartij
+
+ 350
+
+
+
+
+
+ 105
+
+
+
+
+
+ 73
+
+
+
+
+
+ 52
+
+
+
+
+
+ 36
+
+
+
+
+
+ 25
+
+
+
+
+
+ 3
+
+
+
+
+
+ 38
+
+
+
+
+
+ 13
+
+
+
+
+
+ 5
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Weermannen
+
+ 200
+
+
+
+
+
+ 60
+
+
+
+
+
+ 40
+
+
+
+
+
+ 30
+
+
+
+
+
+ 20
+
+
+
+
+
+ 15
+
+
+
+
+
+ 19
+
+
+
+
+
+ 1
+
+
+
+
+
+ 7
+
+
+
+
+
+ 4
+
+
+
+
+
+ 3
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 150
+
+
+
+
+
+ 45
+
+
+
+
+
+ 32
+
+
+
+
+
+ 22
+
+
+
+
+
+ 15
+
+
+
+
+
+ 11
+
+
+
+
+
+ 1
+
+
+
+
+
+ 2
+
+
+
+
+
+ 1
+
+
+
+
+
+ 8
+
+
+
+
+
+ 8
+
+
+
+
+
+ 4
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+ 9500
+ 6000
+ 20
+ 35
+ 5650
+ 355
+ 6005
+ 50
+ 0
+
+ true
+ true
+ true
+
+
+
+ Stembureau Grootschermer (postcode: 4222 BM)
+
+
+ Het Verschil
+
+ 450
+
+
+
+
+
+ 135
+
+
+
+
+
+ 95
+
+
+
+
+
+ 67
+
+
+
+
+
+ 46
+
+
+
+
+
+ 32
+
+
+
+
+
+ 63
+
+
+
+
+
+ 4
+
+
+
+
+
+ 0
+
+
+
+
+
+ 6
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Kleurenpartij
+
+ 900
+
+
+
+
+
+ 270
+
+
+
+
+
+ 188
+
+
+
+
+
+ 132
+
+
+
+
+
+ 93
+
+
+
+
+
+ 65
+
+
+
+
+
+ 122
+
+
+
+
+
+ 3
+
+
+
+
+
+ 20
+
+
+
+
+
+ 1
+
+
+
+
+
+ 5
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Nieuw Geluid
+
+ 150
+
+
+
+
+
+ 45
+
+
+
+
+
+ 31
+
+
+
+
+
+ 24
+
+
+
+
+
+ 15
+
+
+
+
+
+ 12
+
+
+
+
+
+ 16
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 3
+
+
+
+
+
+ 2
+
+
+
+ Planetenpartij
+
+ 750
+
+
+
+
+
+ 225
+
+
+
+
+
+ 158
+
+
+
+
+
+ 110
+
+
+
+
+
+ 77
+
+
+
+
+
+ 54
+
+
+
+
+
+ 2
+
+
+
+
+
+ 75
+
+
+
+
+
+ 22
+
+
+
+
+
+ 5
+
+
+
+
+
+ 12
+
+
+
+
+
+ 3
+
+
+
+
+
+ 6
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Planten voor het Volk
+
+ 390
+
+
+
+
+
+ 117
+
+
+
+
+
+ 82
+
+
+
+
+
+ 59
+
+
+
+
+
+ 40
+
+
+
+
+
+ 28
+
+
+
+
+
+ 22
+
+
+
+
+
+ 17
+
+
+
+
+
+ 16
+
+
+
+
+
+ 2
+
+
+
+
+
+ 5
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Prozen en Poëzie
+
+ 300
+
+
+
+
+
+ 90
+
+
+
+
+
+ 63
+
+
+
+
+
+ 43
+
+
+
+
+
+ 31
+
+
+
+
+
+ 22
+
+
+
+
+
+ 5
+
+
+
+
+
+ 44
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Smaak
+
+ 240
+
+
+
+
+
+ 72
+
+
+
+
+
+ 50
+
+
+
+
+
+ 35
+
+
+
+
+
+ 25
+
+
+
+
+
+ 17
+
+
+
+
+
+ 6
+
+
+
+
+
+ 16
+
+
+
+
+
+ 3
+
+
+
+
+
+ 10
+
+
+
+
+
+ 4
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Sportpartij
+
+ 210
+
+
+
+
+
+ 63
+
+
+
+
+
+ 44
+
+
+
+
+
+ 30
+
+
+
+
+
+ 22
+
+
+
+
+
+ 15
+
+
+
+
+
+ 2
+
+
+
+
+
+ 23
+
+
+
+
+
+ 8
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Weermannen
+
+ 120
+
+
+
+
+
+ 36
+
+
+
+
+
+ 27
+
+
+
+
+
+ 18
+
+
+
+
+
+ 12
+
+
+
+
+
+ 8
+
+
+
+
+
+ 11
+
+
+
+
+
+ 1
+
+
+
+
+
+ 4
+
+
+
+
+
+ 2
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 90
+
+
+
+
+
+ 27
+
+
+
+
+
+ 19
+
+
+
+
+
+ 13
+
+
+
+
+
+ 10
+
+
+
+
+
+ 7
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 4
+
+
+
+
+
+ 5
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+ 5500
+ 3600
+ 12
+ 28
+ 4250
+ 355
+ 4605
+ 0
+ 965
+
+ true
+ true
+ true
+
+
+
+ Stembureau Middenbeemster (postcode: 4333 SB)
+
+
+ Het Verschil
+
+ 300
+
+
+
+
+
+ 90
+
+
+
+
+
+ 63
+
+
+
+
+
+ 44
+
+
+
+
+
+ 31
+
+
+
+
+
+ 22
+
+
+
+
+
+ 42
+
+
+
+
+
+ 4
+
+
+
+
+
+ 0
+
+
+
+
+
+ 4
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Kleurenpartij
+
+ 600
+
+
+
+
+
+ 180
+
+
+
+
+
+ 127
+
+
+
+
+
+ 89
+
+
+
+
+
+ 62
+
+
+
+
+
+ 42
+
+
+
+
+
+ 81
+
+
+
+
+
+ 2
+
+
+
+
+
+ 13
+
+
+
+
+
+ 1
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Nieuw Geluid
+
+ 100
+
+
+
+
+
+ 30
+
+
+
+
+
+ 21
+
+
+
+
+
+ 15
+
+
+
+
+
+ 10
+
+
+
+
+
+ 8
+
+
+
+
+
+ 11
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 3
+
+
+
+
+
+ 1
+
+
+
+ Planetenpartij
+
+ 500
+
+
+
+
+
+ 150
+
+
+
+
+
+ 105
+
+
+
+
+
+ 74
+
+
+
+
+
+ 52
+
+
+
+
+
+ 36
+
+
+
+
+
+ 1
+
+
+
+
+
+ 50
+
+
+
+
+
+ 14
+
+
+
+
+
+ 3
+
+
+
+
+
+ 8
+
+
+
+
+
+ 2
+
+
+
+
+
+ 4
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Planten voor het Volk
+
+ 260
+
+
+
+
+
+ 78
+
+
+
+
+
+ 55
+
+
+
+
+
+ 37
+
+
+
+
+
+ 27
+
+
+
+
+
+ 19
+
+
+
+
+
+ 15
+
+
+
+
+
+ 13
+
+
+
+
+
+ 11
+
+
+
+
+
+ 1
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Prozen en Poëzie
+
+ 200
+
+
+
+
+
+ 60
+
+
+
+
+
+ 42
+
+
+
+
+
+ 30
+
+
+
+
+
+ 20
+
+
+
+
+
+ 14
+
+
+
+
+
+ 3
+
+
+
+
+
+ 30
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Smaak
+
+ 160
+
+
+
+
+
+ 48
+
+
+
+
+
+ 34
+
+
+
+
+
+ 24
+
+
+
+
+
+ 16
+
+
+
+
+
+ 12
+
+
+
+
+
+ 3
+
+
+
+
+
+ 11
+
+
+
+
+
+ 2
+
+
+
+
+
+ 7
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Sportpartij
+
+ 140
+
+
+
+
+
+ 42
+
+
+
+
+
+ 30
+
+
+
+
+
+ 21
+
+
+
+
+
+ 14
+
+
+
+
+
+ 10
+
+
+
+
+
+ 0
+
+
+
+
+
+ 15
+
+
+
+
+
+ 6
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Weermannen
+
+ 80
+
+
+
+
+
+ 24
+
+
+
+
+
+ 17
+
+
+
+
+
+ 11
+
+
+
+
+
+ 9
+
+
+
+
+
+ 6
+
+
+
+
+
+ 8
+
+
+
+
+
+ 0
+
+
+
+
+
+ 3
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 60
+
+
+
+
+
+ 18
+
+
+
+
+
+ 12
+
+
+
+
+
+ 9
+
+
+
+
+
+ 6
+
+
+
+
+
+ 4
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 5
+
+
+
+
+
+ 4
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+ 3500
+ 2400
+ 7
+ 18
+ 3100
+ 330
+ 3430
+ 0
+ 1005
+
+ false
+ true
+ true
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/data/e2e/FAKE_TEST_DATA_Telling_GR2026_Juinen_DSO.eml.xml b/test/data/e2e/FAKE_TEST_DATA_Telling_GR2026_Juinen_DSO.eml.xml
new file mode 100644
index 0000000..b92e245
--- /dev/null
+++ b/test/data/e2e/FAKE_TEST_DATA_Telling_GR2026_Juinen_DSO.eml.xml
@@ -0,0 +1,7844 @@
+
+ 1
+
+ Juinen
+
+
+ 2026-01-16T09:14:34.838
+
+
+
+
+
+ Gemeenteraad Juinen 2026
+ GR
+ GR1
+ Juinen
+ 2026-03-18
+
+
+
+
+
+
+
+ Het Verschil
+
+ 1500
+
+
+
+
+
+ 450
+
+
+
+
+
+ 315
+
+
+
+
+
+ 221
+
+
+
+
+
+ 154
+
+
+
+
+
+ 108
+
+
+
+
+
+ 211
+
+
+
+
+
+ 16
+
+
+
+
+
+ 1
+
+
+
+
+
+ 19
+
+
+
+
+
+ 1
+
+
+
+
+
+ 2
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Kleurenpartij
+
+ 3000
+
+
+
+
+
+ 900
+
+
+
+
+
+ 630
+
+
+
+
+
+ 441
+
+
+
+
+
+ 309
+
+
+
+
+
+ 216
+
+
+
+
+
+ 405
+
+
+
+
+
+ 9
+
+
+
+
+
+ 67
+
+
+
+
+
+ 4
+
+
+
+
+
+ 16
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Nieuw Geluid
+
+ 500
+
+
+
+
+
+ 150
+
+
+
+
+
+ 105
+
+
+
+
+
+ 74
+
+
+
+
+
+ 51
+
+
+
+
+
+ 36
+
+
+
+
+
+ 55
+
+
+
+
+
+ 6
+
+
+
+
+
+ 0
+
+
+
+
+
+ 16
+
+
+
+
+
+ 7
+
+
+
+ Planetenpartij
+
+ 2500
+
+
+
+
+
+ 750
+
+
+
+
+
+ 525
+
+
+
+
+
+ 368
+
+
+
+
+
+ 257
+
+
+
+
+
+ 180
+
+
+
+
+
+ 6
+
+
+
+
+
+ 250
+
+
+
+
+
+ 73
+
+
+
+
+
+ 16
+
+
+
+
+
+ 39
+
+
+
+
+
+ 11
+
+
+
+
+
+ 20
+
+
+
+
+
+ 5
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Planten voor het Volk
+
+ 1300
+
+
+
+
+
+ 390
+
+
+
+
+
+ 273
+
+
+
+
+
+ 191
+
+
+
+
+
+ 134
+
+
+
+
+
+ 94
+
+
+
+
+
+ 74
+
+
+
+
+
+ 59
+
+
+
+
+
+ 55
+
+
+
+
+
+ 6
+
+
+
+
+
+ 16
+
+
+
+
+
+ 1
+
+
+
+
+
+ 5
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Prozen en Poëzie
+
+ 1000
+
+
+
+
+
+ 300
+
+
+
+
+
+ 210
+
+
+
+
+
+ 147
+
+
+
+
+
+ 103
+
+
+
+
+
+ 72
+
+
+
+
+
+ 16
+
+
+
+
+
+ 147
+
+
+
+
+
+ 2
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Smaak
+
+ 800
+
+
+
+
+
+ 240
+
+
+
+
+
+ 168
+
+
+
+
+
+ 118
+
+
+
+
+
+ 82
+
+
+
+
+
+ 58
+
+
+
+
+
+ 19
+
+
+
+
+
+ 54
+
+
+
+
+
+ 9
+
+
+
+
+
+ 33
+
+
+
+
+
+ 13
+
+
+
+
+
+ 3
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Sportpartij
+
+ 700
+
+
+
+
+
+ 210
+
+
+
+
+
+ 147
+
+
+
+
+
+ 103
+
+
+
+
+
+ 72
+
+
+
+
+
+ 50
+
+
+
+
+
+ 5
+
+
+
+
+
+ 76
+
+
+
+
+
+ 27
+
+
+
+
+
+ 10
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Weermannen
+
+ 400
+
+
+
+
+
+ 120
+
+
+
+
+
+ 84
+
+
+
+
+
+ 59
+
+
+
+
+
+ 41
+
+
+
+
+
+ 29
+
+
+
+
+
+ 38
+
+
+
+
+
+ 2
+
+
+
+
+
+ 14
+
+
+
+
+
+ 7
+
+
+
+
+
+ 5
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 300
+
+
+
+
+
+ 90
+
+
+
+
+
+ 63
+
+
+
+
+
+ 44
+
+
+
+
+
+ 31
+
+
+
+
+
+ 22
+
+
+
+
+
+ 2
+
+
+
+
+
+ 3
+
+
+
+
+
+ 1
+
+
+
+
+
+ 17
+
+
+
+
+
+ 17
+
+
+
+
+
+ 9
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+ 18500
+ 12000
+ 39
+ 81
+ 13000
+ 1040
+ 14040
+ 50
+ 1970
+
+
+ Stembureau Purmerland (postcode: 4111 PR)
+
+
+ Het Verschil
+
+ 750
+
+
+
+
+
+ 225
+
+
+
+
+
+ 157
+
+
+
+
+
+ 110
+
+
+
+
+
+ 77
+
+
+
+
+
+ 54
+
+
+
+
+
+ 106
+
+
+
+
+
+ 8
+
+
+
+
+
+ 1
+
+
+
+
+
+ 9
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Kleurenpartij
+
+ 1500
+
+
+
+
+
+ 450
+
+
+
+
+
+ 315
+
+
+
+
+
+ 220
+
+
+
+
+
+ 154
+
+
+
+
+
+ 109
+
+
+
+
+
+ 202
+
+
+
+
+
+ 4
+
+
+
+
+
+ 34
+
+
+
+
+
+ 2
+
+
+
+
+
+ 8
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Nieuw Geluid
+
+ 250
+
+
+
+
+
+ 75
+
+
+
+
+
+ 53
+
+
+
+
+
+ 35
+
+
+
+
+
+ 26
+
+
+
+
+
+ 16
+
+
+
+
+
+ 28
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 10
+
+
+
+
+
+ 4
+
+
+
+ Planetenpartij
+
+ 1250
+
+
+
+
+
+ 375
+
+
+
+
+
+ 262
+
+
+
+
+
+ 184
+
+
+
+
+
+ 128
+
+
+
+
+
+ 90
+
+
+
+
+
+ 3
+
+
+
+
+
+ 125
+
+
+
+
+
+ 37
+
+
+
+
+
+ 8
+
+
+
+
+
+ 19
+
+
+
+
+
+ 6
+
+
+
+
+
+ 10
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Planten voor het Volk
+
+ 650
+
+
+
+
+
+ 195
+
+
+
+
+
+ 136
+
+
+
+
+
+ 95
+
+
+
+
+
+ 67
+
+
+
+
+
+ 47
+
+
+
+
+
+ 37
+
+
+
+
+
+ 29
+
+
+
+
+
+ 28
+
+
+
+
+
+ 3
+
+
+
+
+
+ 8
+
+
+
+
+
+ 1
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Prozen en Poëzie
+
+ 500
+
+
+
+
+
+ 150
+
+
+
+
+
+ 105
+
+
+
+
+
+ 74
+
+
+
+
+
+ 52
+
+
+
+
+
+ 36
+
+
+
+
+
+ 8
+
+
+
+
+
+ 73
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Smaak
+
+ 400
+
+
+
+
+
+ 120
+
+
+
+
+
+ 84
+
+
+
+
+
+ 59
+
+
+
+
+
+ 41
+
+
+
+
+
+ 29
+
+
+
+
+
+ 10
+
+
+
+
+
+ 27
+
+
+
+
+
+ 4
+
+
+
+
+
+ 16
+
+
+
+
+
+ 6
+
+
+
+
+
+ 2
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Sportpartij
+
+ 350
+
+
+
+
+
+ 105
+
+
+
+
+
+ 73
+
+
+
+
+
+ 52
+
+
+
+
+
+ 36
+
+
+
+
+
+ 25
+
+
+
+
+
+ 3
+
+
+
+
+
+ 38
+
+
+
+
+
+ 13
+
+
+
+
+
+ 5
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Weermannen
+
+ 200
+
+
+
+
+
+ 60
+
+
+
+
+
+ 40
+
+
+
+
+
+ 30
+
+
+
+
+
+ 20
+
+
+
+
+
+ 15
+
+
+
+
+
+ 19
+
+
+
+
+
+ 1
+
+
+
+
+
+ 7
+
+
+
+
+
+ 4
+
+
+
+
+
+ 3
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 150
+
+
+
+
+
+ 45
+
+
+
+
+
+ 32
+
+
+
+
+
+ 22
+
+
+
+
+
+ 15
+
+
+
+
+
+ 11
+
+
+
+
+
+ 1
+
+
+
+
+
+ 2
+
+
+
+
+
+ 1
+
+
+
+
+
+ 8
+
+
+
+
+
+ 8
+
+
+
+
+
+ 4
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+ 9500
+ 6000
+ 200
+ 350
+ 5650
+ 355
+ 6005
+ 50
+ 0
+
+ false
+ false
+ false
+
+
+
+ Stembureau Grootschermer (postcode: 4222 BM)
+
+
+ Het Verschil
+
+ 450
+
+
+
+
+
+ 135
+
+
+
+
+
+ 95
+
+
+
+
+
+ 67
+
+
+
+
+
+ 46
+
+
+
+
+
+ 32
+
+
+
+
+
+ 63
+
+
+
+
+
+ 4
+
+
+
+
+
+ 0
+
+
+
+
+
+ 6
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Kleurenpartij
+
+ 900
+
+
+
+
+
+ 270
+
+
+
+
+
+ 188
+
+
+
+
+
+ 132
+
+
+
+
+
+ 93
+
+
+
+
+
+ 65
+
+
+
+
+
+ 122
+
+
+
+
+
+ 3
+
+
+
+
+
+ 20
+
+
+
+
+
+ 1
+
+
+
+
+
+ 5
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Nieuw Geluid
+
+ 150
+
+
+
+
+
+ 45
+
+
+
+
+
+ 31
+
+
+
+
+
+ 24
+
+
+
+
+
+ 15
+
+
+
+
+
+ 12
+
+
+
+
+
+ 16
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 3
+
+
+
+
+
+ 2
+
+
+
+ Planetenpartij
+
+ 750
+
+
+
+
+
+ 225
+
+
+
+
+
+ 158
+
+
+
+
+
+ 110
+
+
+
+
+
+ 77
+
+
+
+
+
+ 54
+
+
+
+
+
+ 2
+
+
+
+
+
+ 75
+
+
+
+
+
+ 22
+
+
+
+
+
+ 5
+
+
+
+
+
+ 12
+
+
+
+
+
+ 3
+
+
+
+
+
+ 6
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Planten voor het Volk
+
+ 390
+
+
+
+
+
+ 117
+
+
+
+
+
+ 82
+
+
+
+
+
+ 59
+
+
+
+
+
+ 40
+
+
+
+
+
+ 28
+
+
+
+
+
+ 22
+
+
+
+
+
+ 17
+
+
+
+
+
+ 16
+
+
+
+
+
+ 2
+
+
+
+
+
+ 5
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Prozen en Poëzie
+
+ 300
+
+
+
+
+
+ 90
+
+
+
+
+
+ 63
+
+
+
+
+
+ 43
+
+
+
+
+
+ 31
+
+
+
+
+
+ 22
+
+
+
+
+
+ 5
+
+
+
+
+
+ 44
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Smaak
+
+ 240
+
+
+
+
+
+ 72
+
+
+
+
+
+ 50
+
+
+
+
+
+ 35
+
+
+
+
+
+ 25
+
+
+
+
+
+ 17
+
+
+
+
+
+ 6
+
+
+
+
+
+ 16
+
+
+
+
+
+ 3
+
+
+
+
+
+ 10
+
+
+
+
+
+ 4
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Sportpartij
+
+ 210
+
+
+
+
+
+ 63
+
+
+
+
+
+ 44
+
+
+
+
+
+ 30
+
+
+
+
+
+ 22
+
+
+
+
+
+ 15
+
+
+
+
+
+ 2
+
+
+
+
+
+ 23
+
+
+
+
+
+ 8
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Weermannen
+
+ 120
+
+
+
+
+
+ 36
+
+
+
+
+
+ 27
+
+
+
+
+
+ 18
+
+
+
+
+
+ 12
+
+
+
+
+
+ 8
+
+
+
+
+
+ 11
+
+
+
+
+
+ 1
+
+
+
+
+
+ 4
+
+
+
+
+
+ 2
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 90
+
+
+
+
+
+ 27
+
+
+
+
+
+ 19
+
+
+
+
+
+ 13
+
+
+
+
+
+ 10
+
+
+
+
+
+ 7
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 4
+
+
+
+
+
+ 5
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+ 5500
+ 0
+ 0
+ 0
+ 4250
+ 355
+ 4605
+ 0
+ 4605
+
+ true
+ true
+ true
+
+
+
+ Stembureau Middenbeemster (postcode: 4333 SB)
+
+
+ Het Verschil
+
+ 3000
+
+
+
+
+
+ 90
+
+
+
+
+
+ 63
+
+
+
+
+
+ 44
+
+
+
+
+
+ 31
+
+
+
+
+
+ 22
+
+
+
+
+
+ 42
+
+
+
+
+
+ 4
+
+
+
+
+
+ 0
+
+
+
+
+
+ 4
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Kleurenpartij
+
+ 600
+
+
+
+
+
+ 180
+
+
+
+
+
+ 127
+
+
+
+
+
+ 89
+
+
+
+
+
+ 62
+
+
+
+
+
+ 42
+
+
+
+
+
+ 81
+
+
+
+
+
+ 2
+
+
+
+
+
+ 13
+
+
+
+
+
+ 1
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Nieuw Geluid
+
+ 100
+
+
+
+
+
+ 30
+
+
+
+
+
+ 21
+
+
+
+
+
+ 15
+
+
+
+
+
+ 10
+
+
+
+
+
+ 8
+
+
+
+
+
+ 11
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 3
+
+
+
+
+
+ 1
+
+
+
+ Planetenpartij
+
+ 500
+
+
+
+
+
+ 150
+
+
+
+
+
+ 105
+
+
+
+
+
+ 74
+
+
+
+
+
+ 52
+
+
+
+
+
+ 36
+
+
+
+
+
+ 1
+
+
+
+
+
+ 50
+
+
+
+
+
+ 14
+
+
+
+
+
+ 3
+
+
+
+
+
+ 8
+
+
+
+
+
+ 2
+
+
+
+
+
+ 4
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Planten voor het Volk
+
+ 260
+
+
+
+
+
+ 78
+
+
+
+
+
+ 55
+
+
+
+
+
+ 37
+
+
+
+
+
+ 27
+
+
+
+
+
+ 19
+
+
+
+
+
+ 15
+
+
+
+
+
+ 13
+
+
+
+
+
+ 11
+
+
+
+
+
+ 1
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Prozen en Poëzie
+
+ 200
+
+
+
+
+
+ 60
+
+
+
+
+
+ 42
+
+
+
+
+
+ 30
+
+
+
+
+
+ 20
+
+
+
+
+
+ 14
+
+
+
+
+
+ 3
+
+
+
+
+
+ 30
+
+
+
+
+
+ 0
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Smaak
+
+ 160
+
+
+
+
+
+ 48
+
+
+
+
+
+ 34
+
+
+
+
+
+ 24
+
+
+
+
+
+ 16
+
+
+
+
+
+ 12
+
+
+
+
+
+ 3
+
+
+
+
+
+ 11
+
+
+
+
+
+ 2
+
+
+
+
+
+ 7
+
+
+
+
+
+ 3
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Sportpartij
+
+ 140
+
+
+
+
+
+ 42
+
+
+
+
+
+ 30
+
+
+
+
+
+ 21
+
+
+
+
+
+ 14
+
+
+
+
+
+ 10
+
+
+
+
+
+ 0
+
+
+
+
+
+ 15
+
+
+
+
+
+ 6
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+ Weermannen
+
+ 80
+
+
+
+
+
+ 24
+
+
+
+
+
+ 17
+
+
+
+
+
+ 11
+
+
+
+
+
+ 9
+
+
+
+
+
+ 6
+
+
+
+
+
+ 8
+
+
+
+
+
+ 0
+
+
+
+
+
+ 3
+
+
+
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 60
+
+
+
+
+
+ 18
+
+
+
+
+
+ 12
+
+
+
+
+
+ 9
+
+
+
+
+
+ 6
+
+
+
+
+
+ 4
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+
+
+
+
+ 5
+
+
+
+
+
+ 4
+
+
+
+
+
+ 2
+
+
+
+
+
+ 0
+
+
+
+
+
+ 0
+
+ 3500
+ 2400
+ 7
+ 18
+ 3100
+ 330
+ 3430
+ 0
+ 1005
+
+ true
+ true
+ true
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/data/e2e/Fake_test_data_Telling_EP2024_gemeente_Steenwijkerland.eml.xml b/test/data/e2e/Fake_test_data_Telling_EP2024_gemeente_Steenwijkerland.eml.xml
deleted file mode 100644
index be024f8..0000000
--- a/test/data/e2e/Fake_test_data_Telling_EP2024_gemeente_Steenwijkerland.eml.xml
+++ /dev/null
@@ -1,3239 +0,0 @@
-
-
- 1
-
- Steenwijkerland
-
-
- 2024-03-13T12:37:25.756
-
-
-
-
-
- Europees Parlement 2024
- EP
- EP
- 2024-06-06
-
-
-
-
-
-
-
- Het Verschil
-
- 20000
-
-
-
-
-
- 3600
-
-
-
-
-
- 3300
-
-
-
-
-
- 2700
-
-
-
-
-
- 2400
-
-
-
-
-
- 2100
-
-
-
-
-
- 1800
-
-
-
-
-
- 1500
-
-
-
-
-
- 1100
-
-
-
-
-
- 900
-
-
-
-
-
- 600
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
- Kleurenpartij
-
- 27000
-
-
-
-
-
- 3000
-
-
-
-
-
- 2700
-
-
-
-
-
- 2400
-
-
-
-
-
- 2400
-
-
-
-
-
- 2100
-
-
-
-
-
- 2100
-
-
-
-
-
- 1800
-
-
-
-
-
- 1800
-
-
-
-
-
- 1500
-
-
-
-
-
- 1500
-
-
-
-
-
- 1200
-
-
-
-
-
- 1200
-
-
-
-
-
- 900
-
-
-
-
-
- 900
-
-
-
-
-
- 600
-
-
-
-
-
- 500
-
-
-
-
-
- 200
-
-
-
-
-
- 200
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
- Proze / Poezie
-
- 4950
-
-
-
-
-
- 1800
-
-
-
-
-
- 1500
-
-
-
-
-
- 1050
-
-
-
-
-
- 600
-
-
-
-
-
- 300
-
-
-
-
-
- 120
-
-
-
-
-
- 90
-
-
-
-
-
- 60
-
-
-
-
-
- 30
-
- 90000
- 52250
- 7
- 1
- 52640
- 20
- 15
- 52675
- 0
- 417
- 6
- 2
- 0
- 1
- 3
-
-
- Stembureau Holterberg (postcode: 7451 AA)
-
-
- Het Verschil
-
- 20000
-
-
-
-
-
- 3600
-
-
-
-
-
- 3300
-
-
-
-
-
- 2700
-
-
-
-
-
- 2400
-
-
-
-
-
- 2100
-
-
-
-
-
- 1800
-
-
-
-
-
- 1500
-
-
-
-
-
- 1100
-
-
-
-
-
- 900
-
-
-
-
-
- 600
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
- Kleurenpartij
-
- 27000
-
-
-
-
-
- 3000
-
-
-
-
-
- 2700
-
-
-
-
-
- 2400
-
-
-
-
-
- 2400
-
-
-
-
-
- 2100
-
-
-
-
-
- 2100
-
-
-
-
-
- 1800
-
-
-
-
-
- 1800
-
-
-
-
-
- 1500
-
-
-
-
-
- 1500
-
-
-
-
-
- 1200
-
-
-
-
-
- 1200
-
-
-
-
-
- 900
-
-
-
-
-
- 900
-
-
-
-
-
- 600
-
-
-
-
-
- 500
-
-
-
-
-
- 200
-
-
-
-
-
- 200
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
- Proze / Poezie
-
- 4950
-
-
-
-
-
- 1800
-
-
-
-
-
- 1500
-
-
-
-
-
- 1050
-
-
-
-
-
- 600
-
-
-
-
-
- 300
-
-
-
-
-
- 120
-
-
-
-
-
- 90
-
-
-
-
-
- 60
-
-
-
-
-
- 30
-
- 90000
- 52250
- 7
- 1
- 52640
- 20
- 15
- 52675
- 0
- 417
- 6
- 2
- 0
- 1
- 3
-
-
- Stembureau Lege boel (postcode: 1234 AA)
-
-
- Het Verschil
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
- Kleurenpartij
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
- Proze / Poezie
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
- 90000
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
-
-
- Stembureau "De Waarschuwing"
-
-
- Het Verschil
-
- 25
-
-
-
-
-
- 25
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
- Kleurenpartij
-
- 25
-
-
-
-
-
- 25
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
- Proze / Poezie
-
- 25
-
-
-
-
-
- 0
-
-
-
-
-
- 25
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 25
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 25
-
-
-
-
-
- 0
-
- 90000
- 100
- 4
- 4
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 108
- 0
-
-
- Stembureau Stembureau Schoolstraat
-
-
- Het Verschil
-
- 10
-
-
-
-
-
- 2
-
-
-
-
-
- 2
-
-
-
-
-
- 6
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
- Kleurenpartij
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
- Proze / Poezie
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
-
-
-
-
- 0
-
- 90000
- 10
- 0
- 0
- 0
- 0
- 0
- 12
- 0
- 0
- 0
- 0
- 0
- 0
- 2
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/data/emls/recounted_info_eml/not_recounted_cso.eml.xml b/test/data/emls/recounted_info_eml/not_recounted_cso.eml.xml
new file mode 100644
index 0000000..9b246e9
--- /dev/null
+++ b/test/data/emls/recounted_info_eml/not_recounted_cso.eml.xml
@@ -0,0 +1,408 @@
+
+
+ 1
+
+ Juinen
+
+
+ 2023-08-28T13:53:27.193
+
+
+
+
+
+ Tweede Kamer der Staten-Generaal 1980
+ TK
+ TK
+ 1980-01-01
+
+
+
+
+ Juinen
+
+
+
+
+ Het Verschil
+
+ 25205
+
+
+
+
+
+ 7080
+
+
+
+
+
+ 6480
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 485
+
+
+
+
+
+ 240
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1680
+
+
+
+ Kleurenpartij
+
+ 32460
+
+
+
+
+
+ 5880
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 4680
+
+
+
+
+
+ 4080
+
+
+
+
+
+ 3480
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 2280
+
+
+
+
+
+ 1680
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1140
+
+
+
+ Prozen en Poëzie
+
+ 9000
+
+
+
+
+
+ 3600
+
+
+
+
+
+ 3000
+
+
+
+
+
+ 2400
+
+
+
+ Sportpartij
+
+ 5400
+
+
+
+
+
+ 2400
+
+
+
+
+
+ 1800
+
+
+
+
+
+ 1200
+
+ 72100
+ 72065
+ 3
+ 2
+ 72095
+ 3
+ 0
+ 72098
+ 0
+ 28
+ 23
+ 3
+ 0
+ 2
+ 0
+
+
+ Stembureau Binnenstad (postcode: 3331 DA)
+
+
+ Het Verschil
+
+ 25205
+
+
+
+
+
+ 7080
+
+
+
+
+
+ 6480
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 485
+
+
+
+
+
+ 240
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1680
+
+
+
+ Kleurenpartij
+
+ 32460
+
+
+
+
+
+ 5880
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 4680
+
+
+
+
+
+ 4080
+
+
+
+
+
+ 3480
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 2280
+
+
+
+
+
+ 1680
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1140
+
+
+
+ Prozen en Poëzie
+
+ 9000
+
+
+
+
+
+ 3600
+
+
+
+
+
+ 3000
+
+
+
+
+
+ 2400
+
+
+
+ Sportpartij
+
+ 5400
+
+
+
+
+
+ 2400
+
+
+
+
+
+ 1800
+
+
+
+
+
+ 1200
+
+ 72100
+ 72065
+ 3
+ 2
+ 72095
+ 3
+ 0
+ 72098
+ 0
+ 28
+ 23
+ 3
+ 0
+ 2
+ 0
+
+ false
+ true
+ true
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/data/emls/recounted_info_eml/not_recounted_dso.eml.xml b/test/data/emls/recounted_info_eml/not_recounted_dso.eml.xml
new file mode 100644
index 0000000..f1def9a
--- /dev/null
+++ b/test/data/emls/recounted_info_eml/not_recounted_dso.eml.xml
@@ -0,0 +1,408 @@
+
+
+ 1
+
+ Juinen
+
+
+ 2023-08-28T13:53:27.193
+
+
+
+
+
+ Tweede Kamer der Staten-Generaal 1980
+ TK
+ TK
+ 1980-01-01
+
+
+
+
+ Juinen
+
+
+
+
+ Het Verschil
+
+ 25205
+
+
+
+
+
+ 7080
+
+
+
+
+
+ 6480
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 485
+
+
+
+
+
+ 240
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1680
+
+
+
+ Kleurenpartij
+
+ 32460
+
+
+
+
+
+ 5880
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 4680
+
+
+
+
+
+ 4080
+
+
+
+
+
+ 3480
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 2280
+
+
+
+
+
+ 1680
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1140
+
+
+
+ Prozen en Poëzie
+
+ 9000
+
+
+
+
+
+ 3600
+
+
+
+
+
+ 3000
+
+
+
+
+
+ 2400
+
+
+
+ Sportpartij
+
+ 5400
+
+
+
+
+
+ 2400
+
+
+
+
+
+ 1800
+
+
+
+
+
+ 1200
+
+ 72100
+ 72065
+ 3
+ 2
+ 72095
+ 3
+ 0
+ 72098
+ 0
+ 28
+ 23
+ 3
+ 0
+ 2
+ 0
+
+
+ Stembureau Binnenstad (postcode: 3331 DA)
+
+
+ Het Verschil
+
+ 25205
+
+
+
+
+
+ 7080
+
+
+
+
+
+ 6480
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 485
+
+
+
+
+
+ 240
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1680
+
+
+
+ Kleurenpartij
+
+ 32460
+
+
+
+
+
+ 5880
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 4680
+
+
+
+
+
+ 4080
+
+
+
+
+
+ 3480
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 2280
+
+
+
+
+
+ 1680
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1140
+
+
+
+ Prozen en Poëzie
+
+ 9000
+
+
+
+
+
+ 3600
+
+
+
+
+
+ 3000
+
+
+
+
+
+ 2400
+
+
+
+ Sportpartij
+
+ 5400
+
+
+
+
+
+ 2400
+
+
+
+
+
+ 1800
+
+
+
+
+
+ 1200
+
+ 72100
+ 72065
+ 3
+ 2
+ 72095
+ 3
+ 0
+ 72098
+ 0
+ 28
+ 23
+ 3
+ 0
+ 2
+ 0
+
+ false
+ false
+ false
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/data/emls/recounted_info_eml/recounted_cso.eml.xml b/test/data/emls/recounted_info_eml/recounted_cso.eml.xml
new file mode 100644
index 0000000..d70033c
--- /dev/null
+++ b/test/data/emls/recounted_info_eml/recounted_cso.eml.xml
@@ -0,0 +1,408 @@
+
+
+ 1
+
+ Juinen
+
+
+ 2023-08-28T13:53:27.193
+
+
+
+
+
+ Tweede Kamer der Staten-Generaal 1980
+ TK
+ TK
+ 1980-01-01
+
+
+
+
+ Juinen
+
+
+
+
+ Het Verschil
+
+ 25205
+
+
+
+
+
+ 7080
+
+
+
+
+
+ 6480
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 485
+
+
+
+
+
+ 240
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1680
+
+
+
+ Kleurenpartij
+
+ 32460
+
+
+
+
+
+ 5880
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 4680
+
+
+
+
+
+ 4080
+
+
+
+
+
+ 3480
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 2280
+
+
+
+
+
+ 1680
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1140
+
+
+
+ Prozen en Poëzie
+
+ 9000
+
+
+
+
+
+ 3600
+
+
+
+
+
+ 3000
+
+
+
+
+
+ 2400
+
+
+
+ Sportpartij
+
+ 5400
+
+
+
+
+
+ 2400
+
+
+
+
+
+ 1800
+
+
+
+
+
+ 1200
+
+ 72100
+ 72065
+ 3
+ 2
+ 72095
+ 3
+ 0
+ 72098
+ 0
+ 28
+ 23
+ 3
+ 0
+ 2
+ 0
+
+
+ Stembureau Binnenstad (postcode: 3331 DA)
+
+
+ Het Verschil
+
+ 25205
+
+
+
+
+
+ 7080
+
+
+
+
+
+ 6480
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 485
+
+
+
+
+
+ 240
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1680
+
+
+
+ Kleurenpartij
+
+ 32460
+
+
+
+
+
+ 5880
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 4680
+
+
+
+
+
+ 4080
+
+
+
+
+
+ 3480
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 2280
+
+
+
+
+
+ 1680
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1140
+
+
+
+ Prozen en Poëzie
+
+ 9000
+
+
+
+
+
+ 3600
+
+
+
+
+
+ 3000
+
+
+
+
+
+ 2400
+
+
+
+ Sportpartij
+
+ 5400
+
+
+
+
+
+ 2400
+
+
+
+
+
+ 1800
+
+
+
+
+
+ 1200
+
+ 72100
+ 72065
+ 3
+ 2
+ 72095
+ 3
+ 0
+ 72098
+ 0
+ 28
+ 23
+ 3
+ 0
+ 2
+ 0
+
+ true
+ false
+ false
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/data/emls/recounted_info_eml/recounted_dso.eml.xml b/test/data/emls/recounted_info_eml/recounted_dso.eml.xml
new file mode 100644
index 0000000..75f6044
--- /dev/null
+++ b/test/data/emls/recounted_info_eml/recounted_dso.eml.xml
@@ -0,0 +1,408 @@
+
+
+ 1
+
+ Juinen
+
+
+ 2023-08-28T13:53:27.193
+
+
+
+
+
+ Tweede Kamer der Staten-Generaal 1980
+ TK
+ TK
+ 1980-01-01
+
+
+
+
+ Juinen
+
+
+
+
+ Het Verschil
+
+ 25205
+
+
+
+
+
+ 7080
+
+
+
+
+
+ 6480
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 485
+
+
+
+
+
+ 240
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1680
+
+
+
+ Kleurenpartij
+
+ 32460
+
+
+
+
+
+ 5880
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 4680
+
+
+
+
+
+ 4080
+
+
+
+
+
+ 3480
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 2280
+
+
+
+
+
+ 1680
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1140
+
+
+
+ Prozen en Poëzie
+
+ 9000
+
+
+
+
+
+ 3600
+
+
+
+
+
+ 3000
+
+
+
+
+
+ 2400
+
+
+
+ Sportpartij
+
+ 5400
+
+
+
+
+
+ 2400
+
+
+
+
+
+ 1800
+
+
+
+
+
+ 1200
+
+ 72100
+ 72065
+ 3
+ 2
+ 72095
+ 3
+ 0
+ 72098
+ 0
+ 28
+ 23
+ 3
+ 0
+ 2
+ 0
+
+
+ Stembureau Binnenstad (postcode: 3331 DA)
+
+
+ Het Verschil
+
+ 25205
+
+
+
+
+
+ 7080
+
+
+
+
+
+ 6480
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 485
+
+
+
+
+
+ 240
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1680
+
+
+
+ Kleurenpartij
+
+ 32460
+
+
+
+
+
+ 5880
+
+
+
+
+
+ 5280
+
+
+
+
+
+ 4680
+
+
+
+
+
+ 4080
+
+
+
+
+
+ 3480
+
+
+
+
+
+ 2880
+
+
+
+
+
+ 2280
+
+
+
+
+
+ 1680
+
+
+
+
+
+ 1080
+
+
+
+
+
+ 1140
+
+
+
+ Prozen en Poëzie
+
+ 9000
+
+
+
+
+
+ 3600
+
+
+
+
+
+ 3000
+
+
+
+
+
+ 2400
+
+
+
+ Sportpartij
+
+ 5400
+
+
+
+
+
+ 2400
+
+
+
+
+
+ 1800
+
+
+
+
+
+ 1200
+
+ 72100
+ 72065
+ 3
+ 2
+ 72095
+ 3
+ 0
+ 72098
+ 0
+ 28
+ 23
+ 3
+ 0
+ 2
+ 0
+
+ true
+ false
+ true
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/data/odts/1ru_ep/Model_Na31-1.odt b/test/data/odts/1ru_ep/Model_Na31-1.odt
deleted file mode 100644
index 8f06c0b..0000000
Binary files a/test/data/odts/1ru_ep/Model_Na31-1.odt and /dev/null differ
diff --git a/test/data/odts/1ru_ep/Model_Na31-2.odt b/test/data/odts/1ru_ep/Model_Na31-2.odt
deleted file mode 100644
index 7ba0e93..0000000
Binary files a/test/data/odts/1ru_ep/Model_Na31-2.odt and /dev/null differ
diff --git a/test/data/odts/3ru/Model_Na31-1.odt b/test/data/odts/3ru/Model_Na31-1.odt
deleted file mode 100644
index cc63e49..0000000
Binary files a/test/data/odts/3ru/Model_Na31-1.odt and /dev/null differ
diff --git a/test/data/odts/3ru/Model_Na31-2.odt b/test/data/odts/3ru/Model_Na31-2.odt
deleted file mode 100644
index 48b916f..0000000
Binary files a/test/data/odts/3ru/Model_Na31-2.odt and /dev/null differ
diff --git a/test/data/odts/3ru_spread/Model_Na31-1.odt b/test/data/odts/3ru_spread/Model_Na31-1.odt
deleted file mode 100644
index f894af1..0000000
Binary files a/test/data/odts/3ru_spread/Model_Na31-1.odt and /dev/null differ
diff --git a/test/data/odts/3ru_tk25/Model_Na31-2.odt b/test/data/odts/3ru_tk25/Model_Na31-2.odt
deleted file mode 100644
index e02d661..0000000
Binary files a/test/data/odts/3ru_tk25/Model_Na31-2.odt and /dev/null differ
diff --git a/test/data/odts/3ru_zipless/Model_Na31-1.odt b/test/data/odts/3ru_zipless/Model_Na31-1.odt
deleted file mode 100644
index 26934fd..0000000
Binary files a/test/data/odts/3ru_zipless/Model_Na31-1.odt and /dev/null differ
diff --git a/test/data/odts/3ru_zipless/Model_Na31-2.odt b/test/data/odts/3ru_zipless/Model_Na31-2.odt
deleted file mode 100644
index 4d3e47f..0000000
Binary files a/test/data/odts/3ru_zipless/Model_Na31-2.odt and /dev/null differ
diff --git a/test/data/odts/empty_fields/Model_Na31-1.odt b/test/data/odts/empty_fields/Model_Na31-1.odt
deleted file mode 100644
index 221cb63..0000000
Binary files a/test/data/odts/empty_fields/Model_Na31-1.odt and /dev/null differ
diff --git a/test/data/odts/tk25/Model_Na31-1.odt b/test/data/odts/tk25/Model_Na31-1.odt
deleted file mode 100644
index 2dad000..0000000
Binary files a/test/data/odts/tk25/Model_Na31-1.odt and /dev/null differ
diff --git a/test/data/odts/tk25/Model_Na31-2.odt b/test/data/odts/tk25/Model_Na31-2.odt
deleted file mode 100644
index e02d661..0000000
Binary files a/test/data/odts/tk25/Model_Na31-2.odt and /dev/null differ
diff --git a/test/protocol_checks/test_protocol_checks.py b/test/protocol_checks/test_protocol_checks.py
index 48e4bfa..499e2e1 100644
--- a/test/protocol_checks/test_protocol_checks.py
+++ b/test/protocol_checks/test_protocol_checks.py
@@ -40,24 +40,35 @@ def test_check_zero_votes(data: ReportingUnitInfo, expected: bool) -> None:
assert protocol_checks.check_zero_votes(data) == expected
-ru_two_inexplicable_difference = ReportingUnitInfo(
+ru_two_difference = ReportingUnitInfo(
reporting_unit_id=None,
reporting_unit_name=None,
cast=0,
total_counted=1_000_000,
rejected_votes={"ongeldig": 1, "blanco": 2},
- uncounted_votes={"geen verklaring": 2},
+ uncounted_votes={"toegelaten kiezers": 1_000_005},
votes_per_party={},
votes_per_candidate={},
)
-ru_zero_inexplicable_difference = ReportingUnitInfo(
+ru_two_difference_less = ReportingUnitInfo(
reporting_unit_id=None,
reporting_unit_name=None,
cast=0,
total_counted=1_000_000,
rejected_votes={"ongeldig": 1, "blanco": 2},
- uncounted_votes={"geen verklaring": 0},
+ uncounted_votes={"toegelaten kiezers": 1_000_001},
+ votes_per_party={},
+ votes_per_candidate={},
+)
+
+ru_zero_difference = ReportingUnitInfo(
+ reporting_unit_id=None,
+ reporting_unit_name=None,
+ cast=0,
+ total_counted=1_000_000,
+ rejected_votes={"ongeldig": 1, "blanco": 2},
+ uncounted_votes={"toegelaten kiezers": 1_000_003},
votes_per_party={},
votes_per_candidate={},
)
@@ -65,10 +76,10 @@ def test_check_zero_votes(data: ReportingUnitInfo, expected: bool) -> None:
@pytest.mark.parametrize(
"data, expected",
- [(ru_two_inexplicable_difference, 2), (ru_zero_inexplicable_difference, 0)],
+ [(ru_two_difference, 2), (ru_two_difference_less, 2), (ru_zero_difference, 0)],
)
def test_check_inexplicable_difference(data: ReportingUnitInfo, expected: int) -> None:
- assert protocol_checks.check_inexplicable_difference(data) == expected
+ assert protocol_checks.check_vote_difference(data) == expected
ru_3pc_invalid_votes = ReportingUnitInfo(
@@ -261,87 +272,3 @@ def test_check_parties_with_large_percentage_difference(
)
== expected
)
-
-
-sum_difference_testcases = [
- (
- ReportingUnitInfo(
- reporting_unit_id=None,
- reporting_unit_name=None,
- cast=100,
- total_counted=97,
- rejected_votes={"ongeldig": 1, "blanco": 2},
- uncounted_votes={
- "toegelaten kiezers": 90,
- "minder getelde stembiljetten": 0,
- "meer getelde stembiljetten": 10,
- "te veel uitgereikte stembiljetten": 1,
- "te veel briefstembiljetten": 1,
- "geen verklaring": 1,
- "andere verklaring": 2,
- },
- votes_per_party={},
- votes_per_candidate={},
- ),
- 5,
- ),
- (
- ReportingUnitInfo(
- reporting_unit_id=None,
- reporting_unit_name=None,
- cast=100,
- total_counted=97,
- rejected_votes={"ongeldig": 1, "blanco": 2},
- uncounted_votes={
- "toegelaten kiezers": 110,
- "minder getelde stembiljetten": 10,
- "meer getelde stembiljetten": 0,
- "meegenomen stembiljetten": 1,
- "te weinig uitgereikte stembiljetten": 1,
- "geen briefstembiljetten": 1,
- "kwijtgeraakte stembiljetten": 1,
- "geen verklaring": 2,
- "andere verklaring": 1,
- },
- votes_per_party={},
- votes_per_candidate={},
- ),
- 3,
- ),
- (
- ReportingUnitInfo(
- reporting_unit_id=None,
- reporting_unit_name=None,
- cast=100,
- total_counted=97,
- rejected_votes={"ongeldig": 1, "blanco": 2},
- uncounted_votes={
- "toegelaten kiezers": 100,
- "minder getelde stembiljetten": 1,
- "meer getelde stembiljetten": 1,
- "meegenomen stembiljetten": 0,
- "te weinig uitgereikte stembiljetten": 0,
- "te veel uitgereikte stembiljetten": 0,
- "geen briefstembiljetten": 0,
- "kwijtgeraakte stembiljetten": 0,
- "geen verklaring": 0,
- "andere verklaring": 0,
- },
- votes_per_party={},
- votes_per_candidate={},
- ),
- 0,
- ),
-]
-
-
-@pytest.mark.parametrize(
- "reporting_unit, expected_difference", sum_difference_testcases
-)
-def test_check_explanation_sum_difference(
- reporting_unit: ReportingUnitInfo, expected_difference: int
-) -> None:
- assert (
- protocol_checks.check_explanation_sum_difference(reporting_unit)
- == expected_difference
- )
diff --git a/test/protocol_checks/test_switched_candidates.py b/test/protocol_checks/test_switched_candidates.py
index cba9e07..0e8a3d8 100644
--- a/test/protocol_checks/test_switched_candidates.py
+++ b/test/protocol_checks/test_switched_candidates.py
@@ -30,7 +30,7 @@ def _create_candidate_votes(
def _create_party_votes(
- cand_votes: Dict[CandidateIdentifier, int]
+ cand_votes: Dict[CandidateIdentifier, int],
) -> Dict[PartyIdentifier, int]:
result = defaultdict(int)
for cand_id, votes in cand_votes.items():
@@ -86,6 +86,7 @@ def _create_mu(reporting_units: List[ReportingUnitInfo]) -> ReportingUnitInfo:
minimum_reporting_units_neighbourhood=1,
minimum_deviation_factor=2,
minimum_votes=5,
+ maximum_rmse=None,
)
case_1_expected = [
SwitchedCandidate(
@@ -129,6 +130,7 @@ def test_case_1():
minimum_reporting_units_neighbourhood=1,
minimum_deviation_factor=2,
minimum_votes=5,
+ maximum_rmse=None,
)
reporting_neighbourhoods = ReportingNeighbourhoods(
@@ -187,3 +189,67 @@ def test_case_2():
candidate_with_more_expected=10,
)
]
+
+
+### Check if the max rmse works as intended. This test case is slightly
+### changed from case 1 where we added some noise adding up to an RMSE
+### of 1.333
+case_3_1_ru = [
+ _create_ru("1", [1, 1, 2, 2], [20, 10, 9, 22]),
+ _create_ru("2", [1, 1, 2, 2], [11, 19, 10, 20]),
+ _create_ru("3", [1, 1, 2, 2], [9, 24, 10, 20]),
+ _create_ru("4", [1, 1, 2, 2], [120, 250, 10, 20]),
+]
+case_3_1_mu = _create_mu(case_3_1_ru)
+case_3_1_config = SwitchedCandidateConfig(
+ minimum_reporting_units_municipality=4,
+ minimum_reporting_units_neighbourhood=1,
+ minimum_deviation_factor=2,
+ minimum_votes=5,
+ maximum_rmse=1.35,
+)
+case_3_1_expected = [
+ SwitchedCandidate(
+ candidate_with_fewer=CandidateIdentifier(PartyIdentifier(1, None), 2),
+ candidate_with_fewer_expected=20,
+ candidate_with_fewer_received=10,
+ candidate_with_more=CandidateIdentifier(PartyIdentifier(1, None), 1),
+ candidate_with_more_expected=10,
+ candidate_with_more_received=20,
+ )
+]
+
+
+def test_case_3():
+ assert (
+ protocol_checks.check_potentially_switched_candidates(
+ polling_station_id="1",
+ main_unit=case_3_1_mu,
+ polling_station=case_3_1_ru[0],
+ reporting_unit_amount=len(case_3_1_ru),
+ reporting_neighbourhoods=None,
+ config=case_3_1_config,
+ )
+ == case_3_1_expected
+ )
+
+ # Now we lower the RMSE threshold, no longer consider this a switch
+ case_3_2_config = SwitchedCandidateConfig(
+ minimum_reporting_units_municipality=4,
+ minimum_reporting_units_neighbourhood=1,
+ minimum_deviation_factor=2,
+ minimum_votes=5,
+ maximum_rmse=1.2,
+ )
+
+ assert (
+ protocol_checks.check_potentially_switched_candidates(
+ polling_station_id="1",
+ main_unit=case_3_1_mu,
+ polling_station=case_3_1_ru[0],
+ reporting_unit_amount=len(case_3_1_ru),
+ reporting_neighbourhoods=None,
+ config=case_3_2_config,
+ )
+ == []
+ )
diff --git a/test/protocol_checks/test_switched_candidates_implementation.py b/test/protocol_checks/test_switched_candidates_implementation.py
index be9dc8d..84aad00 100644
--- a/test/protocol_checks/test_switched_candidates_implementation.py
+++ b/test/protocol_checks/test_switched_candidates_implementation.py
@@ -101,17 +101,17 @@ def test_get_expected_candidate_votes(
zip(
repeat(switched_main_unit),
repeat(switched_reporting_unit),
- [expected_switched_candidates, [], [], []],
+ [expected_switched_candidates, None, [], []],
[10, 4, 10, 10],
[1, 5, 5, 5],
[4, 4, 5, 4],
[4, 4, 4, 5],
+ [None, None, None, None]
)
)
-
@pytest.mark.parametrize(
- "main_unit, reporting_unit, expected, amount_of_reporting_units, minimum_reporting_units, minimum_deviation_factor, minimum_votes",
+ "main_unit, reporting_unit, expected, amount_of_reporting_units, minimum_reporting_units, minimum_deviation_factor, minimum_votes, max_rmse",
switched_test_cases,
)
def test_get_switched_candidate(
@@ -122,6 +122,7 @@ def test_get_switched_candidate(
minimum_reporting_units,
minimum_deviation_factor,
minimum_votes,
+ max_rmse
) -> None:
assert (
protocol_checks._get_potentially_switched_candidates(
@@ -131,10 +132,80 @@ def test_get_switched_candidate(
minimum_reporting_units,
minimum_deviation_factor,
minimum_votes,
+ max_rmse
)
== expected
)
+#### High RMSE test case
+high_rmse_switched_main_unit = ReportingUnitInfo(
+ reporting_unit_id=None,
+ reporting_unit_name=None,
+ cast=0,
+ total_counted=0,
+ rejected_votes={},
+ uncounted_votes={},
+ votes_per_party={PartyIdentifier(1, None): 2350},
+ votes_per_candidate={
+ CandidateIdentifier(PartyIdentifier(1, None), 1): 1000,
+ CandidateIdentifier(PartyIdentifier(1, None), 2): 200,
+ CandidateIdentifier(PartyIdentifier(1, None), 3): 50,
+ CandidateIdentifier(PartyIdentifier(1, None), 4): 300,
+ CandidateIdentifier(PartyIdentifier(1, None), 5): 800,
+ },
+)
+
+high_rmse_switched_reporting_unit = ReportingUnitInfo(
+ reporting_unit_id=None,
+ reporting_unit_name=None,
+ cast=0,
+ total_counted=0,
+ rejected_votes={},
+ uncounted_votes={},
+ votes_per_party={PartyIdentifier(1, None): 233},
+ votes_per_candidate={
+ CandidateIdentifier(PartyIdentifier(1, None), 1): 95,
+ CandidateIdentifier(PartyIdentifier(1, None), 2): 80,
+ CandidateIdentifier(PartyIdentifier(1, None), 3): 6,
+ CandidateIdentifier(PartyIdentifier(1, None), 4): 32,
+ CandidateIdentifier(PartyIdentifier(1, None), 5): 20,
+ },
+)
+
+def test_high_rmse_switched_candidate():
+ no_rmse_filter = protocol_checks._get_potentially_switched_candidates(
+ high_rmse_switched_main_unit,
+ high_rmse_switched_reporting_unit,
+ 20,
+ 10,
+ 4,
+ 20,
+ None
+ )
+ assert no_rmse_filter == [SwitchedCandidate(
+ candidate_with_fewer=CandidateIdentifier(PartyIdentifier(1, None), 5),
+ candidate_with_fewer_expected=86,
+ candidate_with_fewer_received=20,
+ candidate_with_more=CandidateIdentifier(PartyIdentifier(1, None), 2),
+ candidate_with_more_expected=13,
+ candidate_with_more_received=80,
+ )]
+
+ rmse_filter = protocol_checks._get_potentially_switched_candidates(
+ high_rmse_switched_main_unit,
+ high_rmse_switched_reporting_unit,
+ 20,
+ 10,
+ 4,
+ 20,
+ 3.0
+ )
+
+ # Actual RMSE of this test case is 3.1, so the check did run, but returned no results
+ # since we set an upper limit of 3.0.
+ assert(rmse_filter == [])
+
+###
combine_switched_testcases = [
(
diff --git a/test/test_e2e.py b/test/test_e2e.py
index c779cf1..dc2bc92 100644
--- a/test/test_e2e.py
+++ b/test/test_e2e.py
@@ -6,67 +6,10 @@
def test_create_csv_files_a_b():
"""Tests the controlprotocol from front to back, including reading all files from disk and writing result files.
- This test case only includes one polling station with two inexplicable differences, which does show up in the .odt
- """
- path_to_eml = "./test/data/FAKE_TEST_DATA_TK2023_DORDRECHT/Fake_test_data_Telling_TK2023_gemeente_Dordrecht.eml.xml"
- path_to_odt = "./test/data/FAKE_TEST_DATA_TK2023_DORDRECHT/Model_Na31-1.odt"
-
- temp_out_a = "./test/data/a.csv"
- temp_out_b = "./test/data/b.csv"
- temp_out_c = "./test/data/c.csv"
-
- create_csv_files(
- path_to_eml,
- temp_out_a,
- temp_out_b,
- temp_out_c,
- path_to_odt,
- )
-
- # No result since it has been recounted
- with open(temp_out_a) as file:
- # We skip the first few lines since the version can and will change
- content = "".join(file.readlines()[3:])
- expected = (
- "EML datum/tijd;2023-08-28T13:53:27.193\n"
- "Verkiezing;Tweede Kamer der Staten-Generaal 2023\n"
- "Datum;2023-11-22\n"
- "Kieskringnummer;14\n"
- "Gemeentenummer;0505\n"
- "\n"
- "Verkiezingnummer;Type;Kieskringnummer;Gemeentenummer;Gemeentenaam;Stembureaunummer;Stembureaunaam;Aantal geen verklaring voor verschil;Aantal ontbrekende verklaringen voor verschil;Al herteld;Samenvatting\n"
- )
- assert content == expected
-
- # Result since we show this even if there has been a recount
- with open(temp_out_b) as file:
- # We skip the first few lines since the version can and will change
- content = "".join(file.readlines()[3:])
- expected = (
- "EML datum/tijd;2023-08-28T13:53:27.193\n"
- "Verkiezing;Tweede Kamer der Staten-Generaal 2023\n"
- "Datum;2023-11-22\n"
- "Kieskringnummer;14\n"
- "Gemeentenummer;0505\n"
- "\n"
- "Verkiezingnummer;Type;Kieskringnummer;Gemeentenummer;Gemeentenaam;Stembureaunummer;Stembureaunaam;Stembureau met nul stemmen;Stembureau >=3.0% ongeldig;Stembureau >=3.0% blanco;Stembureau >=15 of >=2.0% verschil tussen toegelaten kiezers en uitgebrachte stemmen;Stembureau met lijst >=50.0% afwijking;Mogelijk verwisselde kandidaten;Al herteld;Samenvatting\n"
- "TK2023;B;14;0505;Dordrecht;1;Binnenstad;;;;ja (28);;;ja;Er is een groot verschil tussen het aantal toegelaten kiezers en het aantal uitgebrachte stemmen (28).\n"
- )
- assert content == expected
-
- for temp_file in [temp_out_a, temp_out_b, temp_out_c]:
- os.remove(temp_file)
-
-
-def test_create_csv_files_a_b_2():
- """Tests the controlprotocol from front to back, including reading all files from disk and writing result files.
-
This test case is slightly more involved and tries to trigger each warning at least once,
except for the switched candidates.
"""
- path_to_eml = (
- "./test/data/e2e/Fake_test_data_Telling_EP2024_gemeente_Steenwijkerland.eml.xml"
- )
+ path_to_eml = "./test/data/e2e/FAKE_TEST_DATA_Telling_GR2026_Juinen_DSO.eml.xml"
temp_out_a = "./test/data/a.csv"
temp_out_b = "./test/data/b.csv"
@@ -84,15 +27,14 @@ def test_create_csv_files_a_b_2():
# We skip the first few lines since the version can and will change
content = "".join(file.readlines()[3:])
expected = (
- "EML datum/tijd;2024-03-13T12:37:25.756\n"
- "Verkiezing;Europees Parlement 2024\n"
- "Datum;2024-06-06\n"
- "Kieskringnummer;alle\n"
- "Gemeentenummer;1708\n"
+ "EML datum/tijd;2026-01-16T09:14:34.838\n"
+ "Verkiezing;Gemeenteraad Juinen 2026\n"
+ "Datum;2026-03-18\n"
+ "Kieskringnummer;geen\n"
+ "Gemeentenummer;9999\n"
"\n"
- "Verkiezingnummer;Type;Kieskringnummer;Gemeentenummer;Gemeentenaam;Stembureaunummer;Stembureaunaam;Aantal geen verklaring voor verschil;Aantal ontbrekende verklaringen voor verschil;Al herteld;Samenvatting\n"
- "EP2024;A;alle;1708;Steenwijkerland;1;Holterberg;1;405;;Er is een onverklaard verschil tussen het aantal toegelaten kiezers en het aantal getelde stembiljetten van 406. In het proces-verbaal is ingevuld dat er 1 keer geen verklaring is voor het verschil. De verklaringen die gegeven zijn tellen niet op tot het totale verschil. Er is niet herteld.\n"
- 'EP2024;A;alle;1708;Steenwijkerland;3;"""De Waarschuwing""";108;;;Er is een onverklaard verschil tussen het aantal toegelaten kiezers en het aantal getelde stembiljetten van 108. Er is niet herteld.\n'
+ "Verkiezingnummer;Type;Kieskringnummer;Gemeentenummer;Gemeentenaam;Stembureaunummer;Stembureaunaam;Niet onderzocht telverschil;Al herteld;Samenvatting\n"
+ "GR2026_Juinen;A;geen;9999;Juinen;1;Purmerland;545;;Er is een verschil tussen het aantal toegelaten kiezers en het aantal getelde stembiljetten van 545. Volgens het GSB is dit niet herteld of onderzocht.\n"
)
assert content == expected
@@ -100,17 +42,16 @@ def test_create_csv_files_a_b_2():
# We skip the first few lines since the version can and will change
content = "".join(file.readlines()[3:])
expected = (
- "EML datum/tijd;2024-03-13T12:37:25.756\n"
- "Verkiezing;Europees Parlement 2024\n"
- "Datum;2024-06-06\n"
- "Kieskringnummer;alle\n"
- "Gemeentenummer;1708\n"
+ "EML datum/tijd;2026-01-16T09:14:34.838\n"
+ "Verkiezing;Gemeenteraad Juinen 2026\n"
+ "Datum;2026-03-18\n"
+ "Kieskringnummer;geen\n"
+ "Gemeentenummer;9999\n"
"\n"
- "Verkiezingnummer;Type;Kieskringnummer;Gemeentenummer;Gemeentenaam;Stembureaunummer;Stembureaunaam;Stembureau met nul stemmen;Stembureau >=3.0% ongeldig;Stembureau >=3.0% blanco;Stembureau >=15 of >=2.0% verschil tussen toegelaten kiezers en uitgebrachte stemmen;Stembureau met lijst >=50.0% afwijking;Mogelijk verwisselde kandidaten;Al herteld;Samenvatting\n"
- "EP2024;B;alle;1708;Steenwijkerland;1;Holterberg;;;;ja (417);Kleurenpartij (51.7%);;;Er is een groot verschil tussen het aantal toegelaten kiezers en het aantal uitgebrachte stemmen (417). Daarnaast is er een opmerkelijk grote afwijking ten opzichte van het gemeentegemiddelde bij de volgende partijen: Kleurenpartij (51.7%).\n"
- "EP2024;B;alle;1708;Steenwijkerland;2;Lege boel;ja;;;;Kleurenpartij (-51.7%);;;Er is een aantal uitgebrachte stemmen van 0. Daarnaast is er een opmerkelijk grote afwijking ten opzichte van het gemeentegemiddelde bij de volgende partijen: Kleurenpartij (-51.7%).\n"
- 'EP2024;B;alle;1708;Steenwijkerland;3;"""De Waarschuwing""";;ja (3.7%);ja (3.7%);ja (108);;;;Er is een hoog percentage ongeldige stemmen (3.7%). Daarnaast is er een hoog percentage blanco stemmen (3.7%). Ook is er een groot verschil tussen het aantal toegelaten kiezers en het aantal uitgebrachte stemmen (108).\n'
- "EP2024;B;alle;1708;Steenwijkerland;4;Schoolstraat;;;;ja (20.0%);Het Verschil (61.7%), Kleurenpartij (-51.7%);;;Er is een groot verschil tussen het aantal toegelaten kiezers en het aantal uitgebrachte stemmen (20.0%). Daarnaast is er een opmerkelijk grote afwijking ten opzichte van het gemeentegemiddelde bij de volgende partijen: Het Verschil (61.7%), Kleurenpartij (-51.7%).\n"
+ "Verkiezingnummer;Type;Kieskringnummer;Gemeentenummer;Gemeentenaam;Stembureaunummer;Stembureaunaam;Stembureau met nul stemmen;Stembureau >=3.0% ongeldig;Stembureau >=3.0% blanco;Stembureau >=15 of >=2.0% verschil tussen toegelaten kiezers en uitgebrachte stemmen;Stembureau met lijst >=60.0% afwijking;Mogelijk verwisselde kandidaten;Al herteld;Samenvatting\n"
+ "GR2026_Juinen;B;geen;9999;Juinen;1;Purmerland;;ja (3.1%);ja (5.3%);ja (545);;;;Er is een hoog percentage ongeldige stemmen (3.1%). Daarnaast is er een hoog percentage blanco stemmen (5.3%). Ook is er een groot verschil tussen het aantal toegelaten kiezers en het aantal uitgebrachte stemmen (545).\n"
+ "GR2026_Juinen;B;geen;9999;Juinen;2;Grootschermer;ja;;;ja (4605);;;ja;Er is een aantal uitgebrachte stemmen van 0. Daarnaast is er een groot verschil tussen het aantal toegelaten kiezers en het aantal uitgebrachte stemmen (4605).\n"
+ "GR2026_Juinen;B;geen;9999;Juinen;3;Middenbeemster;;;;ja (1005);Het Verschil (140.6%);;ja;Er is een groot verschil tussen het aantal toegelaten kiezers en het aantal uitgebrachte stemmen (1005). Daarnaast is er een opmerkelijk grote afwijking ten opzichte van het gemeentegemiddelde bij de volgende partijen: Het Verschil (140.6%).\n"
)
assert content == expected
diff --git a/test/test_eml.py b/test/test_eml.py
index 45735ce..dd38394 100644
--- a/test/test_eml.py
+++ b/test/test_eml.py
@@ -217,6 +217,7 @@
party=PartyIdentifier(4, "Sportpartij"), cand_id=3
): 1200,
},
+ has_recounted=True,
)
},
metadata=EmlMetadata(
diff --git a/test/test_eml_recount_info.py b/test/test_eml_recount_info.py
new file mode 100644
index 0000000..b3044c4
--- /dev/null
+++ b/test/test_eml_recount_info.py
@@ -0,0 +1,22 @@
+import pytest
+
+from hcp.eml import EML
+
+test_cases = [
+ ("./test/data/emls/recounted_info_eml/not_recounted_cso.eml.xml", False),
+ ("./test/data/emls/recounted_info_eml/recounted_cso.eml.xml", True),
+ ("./test/data/emls/recounted_info_eml/not_recounted_dso.eml.xml", False),
+ ("./test/data/emls/recounted_info_eml/recounted_dso.eml.xml", True),
+]
+
+
+@pytest.mark.parametrize("eml_path, expected_recounted_result", test_cases)
+def test_eml_recounted_parsing(eml_path: str, expected_recounted_result: bool) -> None:
+ parsed_eml = EML.from_xml(eml_path)
+ # Each test case has exactly one reporting unit, so we can get it by index
+ assert (
+ expected_recounted_result
+ == [value for value in parsed_eml.reporting_units_info.values()][
+ 0
+ ].has_recounted
+ )
diff --git a/test/test_odt.py b/test/test_odt.py
deleted file mode 100644
index c2fd6cc..0000000
--- a/test/test_odt.py
+++ /dev/null
@@ -1,92 +0,0 @@
-import pytest
-
-from hcp.odt import ODT, PollingStation
-
-expected_polling_stations_3ru = [
- PollingStation(id=1, name="Hoornes West", zip="(postcode: 2221 LA)"),
- PollingStation(id=2, name="Hoge Mors", zip="(postcode: 2222 LB)"),
- PollingStation(id=3, name="Valkenburg", zip="(postcode: 2222 LC)"),
-]
-
-expected_polling_stations_3ru_1_3_zipless = [
- PollingStation(id=1, name="Hoornes West", zip=None),
- PollingStation(id=2, name="Hoge Mors", zip="(postcode: 2222 LB)"),
- PollingStation(id=3, name="Valkenburg", zip=None),
-]
-
-expected_polling_stations_1ru_ep = [
- PollingStation(id=1, name="Park Sallandse", zip="(postcode: 7451 BB)")
-]
-
-expected_polling_stations_3ru_tk25 = [
- PollingStation(id=1, name="Hoornes West", zip="(postcode: 2221 LA)"),
- PollingStation(id=2, name="Hoge Mors", zip="(postcode: 2222 LB)"),
- PollingStation(id=3, name="Valkenburg", zip="(postcode: 2222 LC)"),
-]
-
-expected_polling_stations_1ru_tk25 = [
- PollingStation(id=1, name="Tera Korá", zip="(postcode: 0000 BQ)")
-]
-
-test_cases_3ru = [
- ("./test/data/odts/3ru/Model_Na31-1.odt", expected_polling_stations_3ru),
- ("./test/data/odts/3ru/Model_Na31-2.odt", expected_polling_stations_3ru),
- ("./test/data/odts/3ru_spread/Model_Na31-1.odt", expected_polling_stations_3ru),
- (
- "./test/data/odts/3ru_zipless/Model_Na31-1.odt",
- expected_polling_stations_3ru_1_3_zipless,
- ),
- (
- "./test/data/odts/3ru_zipless/Model_Na31-2.odt",
- expected_polling_stations_3ru_1_3_zipless,
- ),
-]
-
-test_cases_1ru_ep = [
- ("./test/data/odts/1ru_ep/Model_Na31-1.odt", expected_polling_stations_1ru_ep),
- ("./test/data/odts/1ru_ep/Model_Na31-2.odt", expected_polling_stations_1ru_ep),
-]
-
-test_cases_tk25 = [
- ("./test/data/odts/tk25/Model_Na31-1.odt", expected_polling_stations_1ru_tk25),
- ("./test/data/odts/tk25/Model_Na31-2.odt", expected_polling_stations_3ru_tk25),
-]
-
-test_cases_invalid = [
- "./test/data/odts/THIS_FILE_DOES_NOT_EXIST.odt",
- "./test/data/odts/THIS_FOLDER_DOES_NOT_EXIST/Model_Na31-1.odt",
- "./test/data/odts/THIS_FOLDER_DOES_NOT_EXIST/Model_Na31-2.odt",
-]
-
-
-@pytest.mark.parametrize(
- "odt_path, expected", test_cases_3ru + test_cases_1ru_ep + test_cases_tk25
-)
-def test_na31_3ru(odt_path, expected) -> None:
- odt_object = ODT.from_path(odt_path)
- assert odt_object is not None
-
- recounted = odt_object.get_already_recounted_polling_stations()
- assert len(recounted) == len(expected)
- assert len(set(recounted)) == len(expected)
-
- for polling_station in recounted:
- assert polling_station in expected
-
-
-@pytest.mark.parametrize("odt_path", test_cases_invalid)
-def test_odt_invalid(odt_path):
- odt_object = ODT.from_path(odt_path)
- assert odt_object is None
-
-
-def test_odt_incomplete_polling_stations():
- odt_object = ODT.from_path("./test/data/odts/empty_fields/Model_Na31-1.odt")
- expected_polling_stations = [
- PollingStation(id=3, name="Valkenburg", zip="(postcode: 2222 LC)")
- ]
-
- assert odt_object is not None
- recounted = odt_object.get_already_recounted_polling_stations()
-
- assert expected_polling_stations == recounted
diff --git a/uv.lock b/uv.lock
index 5e72599..9588655 100644
--- a/uv.lock
+++ b/uv.lock
@@ -42,7 +42,7 @@ wheels = [
[[package]]
name = "hcp"
-version = "1.0"
+version = "1.1"
source = { editable = "." }
dependencies = [
{ name = "defusedxml" },