///|
pub type Tag = String

///|
pub const DEFAULT_TAG_LENGTH : Int = 4

///|
pub const TAG_BASE : Int = 35

///|
pub const DEFAULT_TAG_CAPACITY : Int = 1500625

///|
pub fn is_valid_tag(tag : Tag, length? : Int = DEFAULT_TAG_LENGTH) -> Bool {
  tag_rank(tag, length~) is Some(_)
}

///|
pub fn tag_capacity(length? : Int = DEFAULT_TAG_LENGTH) -> Int? {
  guard length > 0 else { return None }
  let mut capacity = 1
  for _ in 0.. Int? {
  guard length > 0 else { return None }
  guard tag.length() == length else { return None }
  let mut accumulator = 0
  for i in 0.. Tag? {
  guard tag_capacity(length~) is Some(capacity) else { return None }
  guard rank >= 0 && rank < capacity else { return None }
  let chars = Array::make(length, '0')
  let mut rest = rank
  for offset in 0.. Tag? {
  guard last is Some(tag) else { return tag_at(0, length~) }
  guard tag_rank(tag, length~) is Some(rank) else { return None }
  tag_at(rank + 1, length~)
}