text: import sys
  import re
  from collections import namedtuple
  from typing import Optional, List
  
  Claim = namedtuple("Claim", ["id", "left", "top", "width", "height"])
  
  Grid = List[List[Optional[str]]]
  
  claim_re = re.compile(r"#(\d+) @ (\d+),(\d+): (\d+)x(\d+)")
  
  _overlap = "X"
  
  
  def parse_claim(line: str) -> Claim:
      match = claim_re.match(line)
      if match is None:
          raise ValueError
      return Claim(
          id=match.group(1),
          left=int(match.group(2)),
          top=int(match.group(3)),
          width=int(match.group(4)),
          height=int(match.group(5)),
      )
  
  
  def apply_claim(c: Claim, grid: Grid):
      for y in range(c.top, c.top + c.height):
          for x in range(c.left, c.left + c.width):
              if grid[y][x] is None:
                  grid[y][x] = c.id
              else:
                  grid[y][x] = _overlap
  
  
  def count_overlaps(grid: Grid) -> int:
      return sum(row.count(_overlap) for row in grid)
  
  
  def print_grid(grid: Grid):
      for row in grid:
          print(["." if p is None else p for p in row])
  
  
  if __name__ == "__main__":
      file_name = "input.txt"
      if len(sys.argv) >= 2:
          file_name = sys.argv[1]
  
      with open(file_name, "rU") as f:
          lines = f.read().strip().split("\n")
  
      claims = [parse_claim(line) for line in lines]
  
      width = max(c.left + c.width for c in claims)
      height = max(c.top + c.height for c in claims)
  
      # NB: producing the grid as [[None] * width] * height
      # caused [None] * width to be copied by reference
      grid: Grid = [[None for x in range(width)] for y in range(height)]
  
      for c in claims:
          apply_claim(c, grid)
  
      result = count_overlaps(grid)
      print(result)
  