/**
   * Finds all files in folder and in it's sub-tree of specified depth.
   *
   * @param file Starting folder
   * @param maxDepth Depth of the tree. If 1 - just look in the folder, no sub-folders.
   * @param filter file filter.
   * @return List of found files.
   */
  public static List<VisorLogFile> fileTree(File file, int maxDepth, @Nullable FileFilter filter) {
    if (file.isDirectory()) {
      File[] files = (filter == null) ? file.listFiles() : file.listFiles(filter);

      if (files == null) return Collections.emptyList();

      List<VisorLogFile> res = new ArrayList<>(files.length);

      for (File f : files) {
        if (f.isFile() && f.length() > 0) res.add(new VisorLogFile(f));
        else if (maxDepth > 1) res.addAll(fileTree(f, maxDepth - 1, filter));
      }

      return res;
    }

    return F.asList(new VisorLogFile(file));
  }
 /** @return Near keys. */
 public List<byte[]> nearKeyBytes() {
   return nearKeyBytes != null ? nearKeyBytes : Collections.<byte[]>emptyList();
 }
 /** @return Collection of keys that did not pass the filter. */
 public Collection<IgniteTxKey> filterFailedKeys() {
   return filterFailedKeys == null ? Collections.<IgniteTxKey>emptyList() : filterFailedKeys;
 }
 /**
  * Gets pending versions that are less than {@link #version()}.
  *
  * @return Pending versions.
  */
 public Collection<GridCacheVersion> pending() {
   return pending == null ? Collections.<GridCacheVersion>emptyList() : pending;
 }