///|
fn is_alpha(c : UInt16) -> Bool {
  (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
}

///|
fn is_digit(c : UInt16) -> Bool {
  c >= '0' && c <= '9'
}

///|
fn is_alphanum(c : UInt16) -> Bool {
  is_alpha(c) || is_digit(c)
}

///|
fn all_alpha(s : String) -> Bool {
  if s.length() == 0 {
    return false
  }
  let mut i = 0
  while i < s.length() {
    if !is_alpha(s[i]) {
      return false
    }
    i += 1
  }
  true
}

///|
fn all_digit(s : String) -> Bool {
  if s.length() == 0 {
    return false
  }
  let mut i = 0
  while i < s.length() {
    if !is_digit(s[i]) {
      return false
    }
    i += 1
  }
  true
}

///|
fn all_alphanum(s : String) -> Bool {
  if s.length() == 0 {
    return false
  }
  let mut i = 0
  while i < s.length() {
    if !is_alphanum(s[i]) {
      return false
    }
    i += 1
  }
  true
}

///|
fn unit_at(s : String, i : Int) -> String {
  s[i:i + 1].to_owned()
}

///|
fn lower_ascii(s : String) -> String {
  let mut out = ""
  let mut i = 0
  while i < s.length() {
    let c = s[i]
    if c >= 'A' && c <= 'Z' {
      let mut k = 0
      let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      while k < 26 {
        if upper[k] == c {
          out = out + "abcdefghijklmnopqrstuvwxyz"[k:k + 1].to_owned()
          break
        }
        k += 1
      }
    } else {
      out = out + unit_at(s, i)
    }
    i += 1
  }
  out
}

///|
fn upper_ascii(s : String) -> String {
  let mut out = ""
  let mut i = 0
  while i < s.length() {
    let c = s[i]
    if c >= 'a' && c <= 'z' {
      let mut k = 0
      let lower = "abcdefghijklmnopqrstuvwxyz"
      while k < 26 {
        if lower[k] == c {
          out = out + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[k:k + 1].to_owned()
          break
        }
        k += 1
      }
    } else {
      out = out + unit_at(s, i)
    }
    i += 1
  }
  out
}

///|
fn title_ascii(s : String) -> String {
  if s.length() == 0 {
    return ""
  }
  upper_ascii(unit_at(s, 0)) + lower_ascii(s[1:s.length()].to_owned())
}

///|
fn eq_ignore_ascii(a : String, b : String) -> Bool {
  lower_ascii(a) == lower_ascii(b)
}

///|
fn join_dash(parts : Array[String]) -> String {
  if parts.length() == 0 {
    return ""
  }
  let mut out = parts[0]
  let mut i = 1
  while i < parts.length() {
    out = out + "-" + parts[i]
    i += 1
  }
  out
}

///|
fn contains_string(xs : Array[String], item : String) -> Bool {
  let mut i = 0
  while i < xs.length() {
    if xs[i] == item {
      return true
    }
    i += 1
  }
  false
}

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