///|
// Iterative Kosaraju condensation keeps deep and cyclic scopes off the call stack.
fn ranks(members : ArrayView[Int], links : ArrayView[(Int,Int)], budget : Budget) -> Map[Int,Int] {
  let outgoing : Map[Int,Array[Int]]=Map([]); let incoming : Map[Int,Array[Int]]=Map([])
  for (a,b) in links {
    if !budget.charge(1) { return Map([]) }
    match outgoing.get(a) { Some(values) => values.push(b); None => outgoing[a]=[b] }
    match incoming.get(b) { Some(values) => values.push(a); None => incoming[b]=[a] }
  }
  let seen=Map([]); let order=[]
  for start in members {
    let stack=[(start,false)]
    while stack.pop() is Some((node,leave)) {
      if !budget.charge(1) { return Map([]) }
      if leave { order.push(node); continue }
      if seen.contains(node) { continue }; seen[node]=true; stack.push((node,true))
      let neighbors=outgoing.get(node).unwrap_or([])
      for i in 0.. [])
  let indegree=Array::make(count.length(),0); let rank=Array::make(count.length(),0)
  for (a,b) in links {
    if !budget.charge(1) { return Map([]) }
    let a=components[a]; let b=components[b]
    if a != b && !edges.contains((a,b)) { edges[(a,b)]=true; next[a].push(b); indegree[b]+=1 }
  }
  let queue=[]
  for i in 0..