///|
pub fn ascii_lower(input : String) -> String {
  let builder = StringBuilder::new()
  for ch in input.iter() {
    if ch >= 'A' && ch <= 'Z' {
      builder.write_char((ch.to_int() + 32).unsafe_to_char())
    } else {
      builder.write_char(ch)
    }
  }
  builder.to_string()
}

///|
pub fn trim_ascii(input : String) -> String {
  let mut start = 0
  let mut ending = input.length()
  while start < ending && is_ascii_space(input.unsafe_get(start)) {
    start = start + 1
  }
  while ending > start && is_ascii_space(input.unsafe_get(ending - 1)) {
    ending = ending - 1
  }
  input[start:ending].to_owned()
}

///|
fn is_ascii_space(unit : UInt16) -> Bool {
  unit == (32).to_uint16() ||
  unit == (9).to_uint16() ||
  unit == (10).to_uint16() ||
  unit == (13).to_uint16()
}

///|
pub fn parse_positive_int(input : String) -> Int {
  let trimmed = trim_ascii(input)
  let mut value = 0
  for ch in trimmed.iter() {
    if ch >= '0' && ch <= '9' {
      value = value * 10 + (ch.to_int() - '0'.to_int())
    } else {
      return 0
    }
  }
  value
}

///|
pub fn abs_int(value : Int) -> Int {
  if value < 0 {
    0 - value
  } else {
    value
  }
}

///|
pub fn starts_with(input : String, prefix : String) -> Bool {
  if prefix.length() > input.length() {
    false
  } else {
    input[:prefix.length()].to_owned() == prefix
  }
}

///|
pub fn strip_prefix(input : String, prefix : String) -> String {
  if starts_with(input, prefix) {
    input[prefix.length():].to_owned()
  } else {
    input
  }
}

///|
pub fn contains_string(items : Array[String], value : String) -> Bool {
  for i in 0.. String {
  let builder = StringBuilder::new()
  for i in 0.. 0 {
      builder.write_string("\n")
    }
    builder.write_string(lines[i])
  }
  builder.to_string()
}

///|
pub fn mask_secret(secret : String) -> String {
  if secret.length() <= 4 {
    "****"
  } else {
    secret[:2].to_owned() + "****" + secret[secret.length() - 2:].to_owned()
  }
}