private void strongConnect(@NotNull List<? super List<Node>> sccs, Node[] allNodes) {
      int successor = -1;
      nextNode:
      while (!frames.isEmpty()) {
        TarjanFrame<Node> pair = frames.peekLast();
        int i = pair.nodeI;

        // we have returned to the node
        if (index[i] == -1) {
          // actually, we visit node first time, prepare
          index[i] = dfsIndex;
          lowLink[i] = dfsIndex;
          dfsIndex++;
          nodesOnStack.push(i);
          isOnStack[i] = true;
        }
        if (ArrayUtil.indexOf(pair.out, successor) != -1) {
          lowLink[i] = Math.min(lowLink[i], lowLink[successor]);
        }
        successor = i;

        // if unexplored children left, dfs there
        while (pair.nextUnexploredIndex < pair.out.length) {
          int nextI = pair.out[pair.nextUnexploredIndex++];
          if (index[nextI] == -1) {
            frames.addLast(new TarjanFrame<>(nextI, allNodes, buildOuts(allNodes[nextI])));
            continue nextNode;
          }
          if (isOnStack[nextI]) {
            lowLink[i] = Math.min(lowLink[i], index[nextI]);

            if (myBackEdge == null) {
              myBackEdge = new AbstractMap.SimpleImmutableEntry<>(allNodes[nextI], allNodes[i]);
            }
          }
        }
        frames.removeLast();
        topo.add(i);
        // we are really back, pop a scc
        if (lowLink[i] == index[i]) {
          // found yer
          List<Node> scc = new ArrayList<>();
          int pushedI;
          do {
            pushedI = nodesOnStack.popInt();
            Node pushed = allNodes[pushedI];
            isOnStack[pushedI] = false;
            scc.add(pushed);
          }
          while (pushedI != i);
          sccs.add(scc);
        }
      }
    }
private void strongConnect(@NotNull List<? super List<Node>> sccs, Node[] allNodes)