public static Query<VirtualFile> findFileRecursively(final VirtualFile parentDirectory, final String fileName, final int levels, final long timeout) {
    if (parentDirectory == null) return new EmptyQuery<>();
    final QueryExecutor<VirtualFile, String> executor = (queryParameters, consumer) -> {
      final long endTime = timeout < 0 ? -1L : System.currentTimeMillis() + timeout;
      return processFileRecursively(parentDirectory, 1, levels, file -> {
        if (endTime > 0 && System.currentTimeMillis() > endTime) return false;
        if (file.getName().equals(fileName)) {
          if (!consumer.process(file)) return false;
        }
        return true;
      });
    };
    return new ExecutorsQuery<>(fileName, Collections.singletonList(executor));
  }
public static Query<VirtualFile> findFileRecursively(final VirtualFile parentDirectory, final String fileName, final int levels, final long timeout)