@Nullable
  private static GraphFragment getFragment(int startNode,
                                           Function<? super Integer, ? extends List<Integer>> getNextNodes,
                                           Function<? super Integer, ? extends List<Integer>> getPrevNodes,
                                           Set<Integer> thisNodeCantBeInMiddle, boolean isDown) {
    Set<Integer> blackNodes = new HashSet<>();
    blackNodes.add(startNode);

    Set<Integer> grayNodes = new HashSet<>(getNextNodes.apply(startNode));

    int endNode = -1;
    while (blackNodes.size() < SHORT_FRAGMENT_MAX_SIZE) {
      int nextBlackNode = -1;
      for (int grayNode : grayNodes) {
        if (blackNodes.containsAll(getPrevNodes.apply(grayNode))) {
          nextBlackNode = grayNode;
          break;
        }
      }

      if (nextBlackNode == -1) return null;

      if (grayNodes.size() == 1) {
        endNode = nextBlackNode;
        break;
      }

      List<Integer> nextGrayNodes = getNextNodes.apply(nextBlackNode);
      if (nextGrayNodes.isEmpty() || thisNodeCantBeInMiddle.contains(nextBlackNode)) return null;

      blackNodes.add(nextBlackNode);
      grayNodes.remove(nextBlackNode);
      grayNodes.addAll(nextGrayNodes);
    }

    if (endNode != -1) {
      return isDown ? GraphFragment.create(startNode, endNode) : GraphFragment.create(endNode, startNode);
    }
    else {
      return null;
    }
  }
@Nullable
  private static GraphFragment getFragment(int startNode,
                                           Function<? super Integer, ? extends List<Integer>> getNextNodes,
                                           Function<? super Integer, ? extends List<Integer>> getPrevNodes,
                                           Set<Integer> thisNodeCantBeInMiddle, boolean isDown)