///|
fn digit_int(c : UInt16) -> Int {
  let digits = "0123456789"
  let mut k = 0
  while k < 10 {
    if digits[k] == c {
      return k
    }
    k += 1
  }
  -1
}

///|
fn parse_yymmdd(s : String) -> (Int, Int, Int)? {
  if s.length() != 6 {
    return None
  }
  let mut i = 0
  while i < 6 {
    if digit_int(s[i]) < 0 {
      return None
    }
    i += 1
  }
  let year = digit_int(s[0]) * 10 + digit_int(s[1])
  let month = digit_int(s[2]) * 10 + digit_int(s[3])
  let day = digit_int(s[4]) * 10 + digit_int(s[5])
  Some((year, month, day))
}

///|
fn days_in_month(month : Int) -> Int {
  if month == 1 ||
    month == 3 ||
    month == 5 ||
    month == 7 ||
    month == 8 ||
    month == 10 ||
    month == 12 {
    31
  } else if month == 4 || month == 6 || month == 9 || month == 11 {
    30
  } else if month == 2 {
    29
  } else {
    0
  }
}

///|
fn is_valid_yymmdd(s : String) -> Bool {
  match parse_yymmdd(s) {
    None => false
    Some((_, month, day)) => {
      let max = days_in_month(month)
      month >= 1 && month <= 12 && day >= 1 && day <= max
    }
  }
}

///|
fn is_valid_sex(s : String) -> Bool {
  s == "M" || s == "F" || s == "<"
}

///|
fn is_valid_alpha3(s : String) -> Bool {
  if s.length() != 3 {
    return false
  }
  let mut i = 0
  while i < 3 {
    let c = s[i]
    if !((c >= 'A' && c <= 'Z') || c == '<') {
      return false
    }
    i += 1
  }
  true
}