// Path: src/main/java/pl/sdadas/fsbrowser/exception/FsAccessException.java
// public class FsAccessException extends FsException {
// 
//     public FsAccessException() {
//     }
// 
//     public FsAccessException(String message) {
//         super(message);
//     }
// 
//     public FsAccessException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public FsAccessException(Throwable cause) {
//         super(cause);
//     }
// 
//     public FsAccessException(String message, Throwable cause, boolean suppression, boolean writableStackTrace) {
//         super(message, cause, suppression, writableStackTrace);
//     }
// }
// 
// Path: src/main/java/pl/sdadas/fsbrowser/exception/FsException.java
// public class FsException extends Exception {
// 
//     public FsException() {
//     }
// 
//     public FsException(String message) {
//         super(message);
//     }
// 
//     public FsException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public FsException(Throwable cause) {
//         super(cause);
//     }
// 
//     public FsException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
//         super(message, cause, enableSuppression, writableStackTrace);
//     }
// }
// 
// Path: src/main/java/pl/sdadas/fsbrowser/utils/FileSystemUtils.java
// public class FileSystemUtils {
// 
//     public static boolean isSameFileSystem(FsConnection first, FsConnection second) {
//         String firstName = getDefaultFs(first);
//         String secondName = getDefaultFs(second);
//         return StringUtils.equals(firstName, secondName);
//     }
// 
//     public static String getDefaultFs(FsConnection connection) {
//         Configuration config = connection.getConfig();
//         return ObjectUtils.firstNonNull(config.get("fs.defaultFS"), config.get("fs.default.name"));
//     }
// 
//     public static String formatByteCount(long bytes) {
//         return formatByteCount(bytes, false);
//     }
// 
//     public static String formatByteCount(long bytes, boolean si) {
//         int unit = getMetricUnit(si);
//         if (bytes < unit) return bytes + " B";
//         int exp = (int) (Math.log(bytes) / Math.log(unit));
//         String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "i" : "");
//         return String.format("%.2f %sB", bytes / Math.pow(unit, exp), pre);
//     }
// 
//     public static boolean checkNativeLibraries() {
//         if(Shell.WINDOWS && StringUtils.isBlank(Shell.WINUTILS)) {
//             return false;
//         }
//         return true;
//     }
// 
//     public static boolean isParentPath(Path parent, Path child) {
//         String parentPath = parent.toUri().getPath();
//         String childPath = child.toUri().getPath();
//         return childPath.startsWith(parentPath);
//     }
// 
//     public static String[] pathsToStrings(Path... paths) {
//         return Arrays.stream(paths).map(path -> path.toUri().getPath()).toArray(String[]::new);
//     }
// 
//     private static int getMetricUnit(boolean si) {
//         return si ? 1000 : 1024;
//     }
// 
//     private FileSystemUtils() {
//     }
// }
// 
// Path: src/main/java/pl/sdadas/fsbrowser/view/common/loading/Progress.java
// public class Progress {
// 
//     private Supplier<String> supplier;
// 
//     public String getValue() {
//         return supplier != null ? supplier.get() : null;
//     }
// 
//     public Supplier<String> getSupplier() {
//         return supplier;
//     }
// 
//     public void setSupplier(Supplier<String> supplier) {
//         this.supplier = supplier;
//     }
// }


import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.AccessControlException;
import org.apache.hadoop.security.UserGroupInformation;
import org.springframework.data.hadoop.fs.DistCp;
import org.springframework.data.hadoop.fs.FsShell;
import pl.sdadas.fsbrowser.exception.FsAccessException;
import pl.sdadas.fsbrowser.exception.FsException;
import pl.sdadas.fsbrowser.fs.action.*;
import pl.sdadas.fsbrowser.utils.FileSystemUtils;
import pl.sdadas.fsbrowser.view.common.loading.Progress;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.util.*;
import java.util.stream.Collectors;
        execute((shell, fs) -> {
            String uri = fsPath(path).toUri().getPath();
            FsShellPermissions.changePermissions(fs, fs.getConf(), FsShellPermissions.Op.CHGRP, recursive, group, uri);
            return null;
        });
    }

    @Override
    public void close() throws IOException {
        IOUtils.closeQuietly(fs);
        IOUtils.closeQuietly(shell);
    }

    protected Path fsPath(Path path) {
        return path;
    }

    protected Path[] fsPath(Path[] paths) {
        return Arrays.stream(paths).map(this::fsPath).toArray(Path[]::new);
    }

    protected List<Path> fsPath(List<Path> paths) {
        return paths.stream().map(this::fsPath).collect(Collectors.toList());
    }

    protected ConnectionConfig getConnectionConfig() {
        return this.config;
    }

    protected FileSystem getFileSystem() {
// Path: src/main/java/pl/sdadas/fsbrowser/exception/FsAccessException.java
// public class FsAccessException extends FsException {
// 
//     public FsAccessException() {
//     }
// 
//     public FsAccessException(String message) {
//         super(message);
//     }
// 
//     public FsAccessException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public FsAccessException(Throwable cause) {
//         super(cause);
//     }
// 
//     public FsAccessException(String message, Throwable cause, boolean suppression, boolean writableStackTrace) {
//         super(message, cause, suppression, writableStackTrace);
//     }
// }
// 
// Path: src/main/java/pl/sdadas/fsbrowser/exception/FsException.java
// public class FsException extends Exception {
// 
//     public FsException() {
//     }
// 
//     public FsException(String message) {
//         super(message);
//     }
// 
//     public FsException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public FsException(Throwable cause) {
//         super(cause);
//     }
// 
//     public FsException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
//         super(message, cause, enableSuppression, writableStackTrace);
//     }
// }
// 
// Path: src/main/java/pl/sdadas/fsbrowser/utils/FileSystemUtils.java
// public class FileSystemUtils {
// 
//     public static boolean isSameFileSystem(FsConnection first, FsConnection second) {
//         String firstName = getDefaultFs(first);
//         String secondName = getDefaultFs(second);
//         return StringUtils.equals(firstName, secondName);
//     }
// 
//     public static String getDefaultFs(FsConnection connection) {
//         Configuration config = connection.getConfig();
//         return ObjectUtils.firstNonNull(config.get("fs.defaultFS"), config.get("fs.default.name"));
//     }
// 
//     public static String formatByteCount(long bytes) {
//         return formatByteCount(bytes, false);
//     }
// 
//     public static String formatByteCount(long bytes, boolean si) {
//         int unit = getMetricUnit(si);
//         if (bytes < unit) return bytes + " B";
//         int exp = (int) (Math.log(bytes) / Math.log(unit));
//         String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "i" : "");
//         return String.format("%.2f %sB", bytes / Math.pow(unit, exp), pre);
//     }
// 
//     public static boolean checkNativeLibraries() {
//         if(Shell.WINDOWS && StringUtils.isBlank(Shell.WINUTILS)) {
//             return false;
//         }
//         return true;
//     }
// 
//     public static boolean isParentPath(Path parent, Path child) {
//         String parentPath = parent.toUri().getPath();
//         String childPath = child.toUri().getPath();
//         return childPath.startsWith(parentPath);
//     }
// 
//     public static String[] pathsToStrings(Path... paths) {
//         return Arrays.stream(paths).map(path -> path.toUri().getPath()).toArray(String[]::new);
//     }
// 
//     private static int getMetricUnit(boolean si) {
//         return si ? 1000 : 1024;
//     }
// 
//     private FileSystemUtils() {
//     }
// }
// 
// Path: src/main/java/pl/sdadas/fsbrowser/view/common/loading/Progress.java
// public class Progress {
// 
//     private Supplier<String> supplier;
// 
//     public String getValue() {
//         return supplier != null ? supplier.get() : null;
//     }
// 
//     public Supplier<String> getSupplier() {
//         return supplier;
//     }
// 
//     public void setSupplier(Supplier<String> supplier) {
//         this.supplier = supplier;
//     }
// }


// Path: src/main/java/pl/sdadas/fsbrowser/fs/connection/FsConnection.java
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.AccessControlException;
import org.apache.hadoop.security.UserGroupInformation;
import org.springframework.data.hadoop.fs.DistCp;
import org.springframework.data.hadoop.fs.FsShell;
import pl.sdadas.fsbrowser.exception.FsAccessException;
import pl.sdadas.fsbrowser.exception.FsException;
import pl.sdadas.fsbrowser.fs.action.*;
import pl.sdadas.fsbrowser.utils.FileSystemUtils;
import pl.sdadas.fsbrowser.view.common.loading.Progress;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.util.*;
import java.util.stream.Collectors;

        execute((shell, fs) -> {
            String uri = fsPath(path).toUri().getPath();
            FsShellPermissions.changePermissions(fs, fs.getConf(), FsShellPermissions.Op.CHGRP, recursive, group, uri);
            return null;
        });
    }

    @Override
    public void close() throws IOException {
        IOUtils.closeQuietly(fs);
        IOUtils.closeQuietly(shell);
    }

    protected Path fsPath(Path path) {
        return path;
    }

    protected Path[] fsPath(Path[] paths) {
        return Arrays.stream(paths).map(this::fsPath).toArray(Path[]::new);
    }

    protected List<Path> fsPath(List<Path> paths) {
        return paths.stream().map(this::fsPath).collect(Collectors.toList());
    }

    protected ConnectionConfig getConnectionConfig() {
        return this.config;
    }

    protected FileSystem getFileSystem() {
        return this.fs;