///|
pub fn BinaryMask::BinaryMask(width~ : Int, height~ : Int) -> BinaryMask {
  {
    width: width.max(0),
    height: height.max(0),
    values: Array::make(width.max(0) * height.max(0), false),
  }
}

///|
pub fn BinaryMask::inside(mask : BinaryMask, x : Int, y : Int) -> Bool {
  x >= 0 && y >= 0 && x < mask.width && y < mask.height
}

///|
fn mask_index(mask : BinaryMask, x : Int, y : Int) -> Int {
  y * mask.width + x
}

///|
pub fn BinaryMask::at(mask : BinaryMask, x : Int, y : Int) -> Bool {
  if mask.inside(x, y) {
    mask.values[mask_index(mask, x, y)]
  } else {
    false
  }
}

///|
pub fn BinaryMask::set(
  mask : BinaryMask,
  x : Int,
  y : Int,
  value : Bool,
) -> Unit {
  if mask.inside(x, y) {
    mask.values[mask_index(mask, x, y)] = value
  }
}

///|
pub fn BinaryMask::count(mask : BinaryMask) -> Int {
  let mut result = 0
  for value in mask.values {
    if value {
      result += 1
    }
  }
  result
}

///|
pub fn BinaryMask::clear(mask : BinaryMask) -> Unit {
  for i in 0.. Unit {
  for i in 0.. BinaryMask {
  let result = BinaryMask(width=mask.width, height=mask.height)
  for i in 0.. BinaryMask {
  let result = BinaryMask(width=mask.width, height=mask.height)
  for i in 0.. BinaryMask {
  let width = a.width.min(b.width)
  let height = a.height.min(b.height)
  let result = BinaryMask(width~, height~)
  for y in 0.. BinaryMask {
  let width = a.width.min(b.width)
  let height = a.height.min(b.height)
  let result = BinaryMask(width~, height~)
  for y in 0.. BinaryMask {
  let result = a.clone()
  for y in 0.. Bounds {
  let mut min_x = mask.width
  let mut min_y = mask.height
  let mut max_x = -1
  let mut max_y = -1
  for y in 0.. Array[Int] {
  let result = Array::make(mask.height, 0)
  for y in 0.. Array[Int] {
  let result = Array::make(mask.width, 0)
  for y in 0.. BinaryMask {
  let result = BinaryMask(width=mask.width, height=mask.height)
  let safe_radius = radius.max(0)
  for y in 0.. BinaryMask {
  let result = BinaryMask(width=mask.width, height=mask.height)
  let safe_radius = radius.max(0)
  for y in 0.. BinaryMask {
  mask.erode(radius).dilate(radius)
}

///|
pub fn BinaryMask::closing(mask : BinaryMask, radius : Int) -> BinaryMask {
  mask.dilate(radius).erode(radius)
}

///|
pub fn BinaryMask::boundary(mask : BinaryMask) -> BinaryMask {
  mask.difference(mask.erode(1))
}

///|
pub fn has_true_neighbor(
  mask : BinaryMask,
  x : Int,
  y : Int,
  radius : Int,
) -> Bool {
  let safe_radius = radius.max(0)
  for dy in -safe_radius..<=safe_radius {
    for dx in -safe_radius..<=safe_radius {
      if (dx != 0 || dy != 0) && mask.at(x + dx, y + dy) {
        return true
      }
    }
  }
  false
}

///|
pub fn mask_to_image(
  mask : BinaryMask,
  foreground : Double,
  background : Double,
) -> GrayImage {
  let image = GrayImage(width=mask.width, height=mask.height, fill=background)
  for y in 0.. BinaryMask {
  threshold_image(image, threshold)
}

///|
pub fn fill_mask_holes(mask : BinaryMask) -> BinaryMask {
  let outside = BinaryMask(width=mask.width, height=mask.height)
  let queue : Array[Point] = []
  for x in 0.. 1 && !mask.at(x, mask.height - 1) {
      outside.set(x, mask.height - 1, true)
      queue.push(
        Point(x=Double::from_int(x), y=Double::from_int(mask.height - 1)),
      )
    }
  }
  for y in 0.. 1 && !mask.at(mask.width - 1, y) {
      outside.set(mask.width - 1, y, true)
      queue.push(
        Point(x=Double::from_int(mask.width - 1), y=Double::from_int(y)),
      )
    }
  }
  let mut cursor = 0
  while cursor < queue.length() {
    let point = queue[cursor]
    cursor += 1
    for
      neighbor in [
        Point(x=point.x + 1.0, y=point.y),
        Point(x=point.x - 1.0, y=point.y),
        Point(x=point.x, y=point.y + 1.0),
        Point(x=point.x, y=point.y - 1.0),
      ] {
      let nx = neighbor.x.to_int()
      let ny = neighbor.y.to_int()
      if outside.inside(nx, ny) && !mask.at(nx, ny) && !outside.at(nx, ny) {
        outside.set(nx, ny, true)
        queue.push(neighbor)
      }
    }
  }
  let result = mask.clone()
  for y in 0..