function tarjan(g) {
  if (!g.isDirected()) {
    throw new Error("tarjan can only be applied to a directed graph. Bad input: " + g);
  }

  var index = 0,
      stack = [],
      visited = {}, // node id -> { onStack, lowlink, index }
      results = [];

  function dfs(u) {
    var entry = visited[u] = {
      onStack: true,
      lowlink: index,
      index: index++
    };
    stack.push(u);

    g.successors(u).forEach(function(v) {
      if (!(v in visited)) {
        dfs(v);
        entry.lowlink = Math.min(entry.lowlink, visited[v].lowlink);
      } else if (visited[v].onStack) {
        entry.lowlink = Math.min(entry.lowlink, visited[v].index);
      }
    });

    if (entry.lowlink === entry.index) {
      var cmpt = [],
          v;
      do {
        v = stack.pop();
        visited[v].onStack = false;
        cmpt.push(v);
      } while (u !== v);
      results.push(cmpt);
    }
  }

  g.nodes().forEach(function(u) {
    if (!(u in visited)) {
      dfs(u);
    }
  });

  return results;
}
This function is an implementation of [Tarjan's algorithm][] which finds
all [strongly connected components][] in the directed graph **g**. Each
strongly connected component is composed of nodes that can reach all other
nodes in the component via directed edges. A strongly connected component
can consist of a single node if that node cannot both reach and be reached
by any other specific node in the graph. Components of more than one node
are guaranteed to have at least one cycle.

This function returns an array of components. Each component is itself an
array that contains the ids of all nodes in the component.

[Tarjan's algorithm]: http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
[strongly connected components]: http://en.wikipedia.org/wiki/Strongly_connected_component

@param {Digraph} g the graph to search for strongly connected components