// Path: src/main/java/org/terasology/launcher/util/visitor/ArchiveCopyVisitor.java
// public class ArchiveCopyVisitor extends SimpleFileVisitor<Path> {
// 
//     /**
//      * Directory to which the files are copied.
//      */
//     private final Path targetLocation;
// 
//     public ArchiveCopyVisitor(final Path targetLocation) {
//         this.targetLocation = targetLocation;
//     }
// 
//     @Override
//     public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
//         final Path destFile = Paths.get(targetLocation.toString() + file.toString());
//         Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);
//         return FileVisitResult.CONTINUE;
//     }
// 
//     @Override
//     public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
//         final Path dirToCreate = Paths.get(targetLocation.toString() + dir.toString());
//         if (Files.notExists(dirToCreate)) {
//             Files.createDirectories(dirToCreate);
//         }
//         return FileVisitResult.CONTINUE;
//     }
// }
// 
// Path: src/main/java/org/terasology/launcher/util/visitor/DeleteFileVisitor.java
// public class DeleteFileVisitor extends SimpleFileVisitor<Path> {
// 
//     @Override
//     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
//         Files.delete(file);
//         return FileVisitResult.CONTINUE;
//     }
// 
//     @Override
//     public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
//         Files.delete(dir);
//         return FileVisitResult.CONTINUE;
//     }
// }
// 
// Path: src/main/java/org/terasology/launcher/util/visitor/LocalCopyVisitor.java
// public class LocalCopyVisitor extends SimpleFileVisitor<Path> {
// 
//     /**
//      * Directory to copy from.
//      */
//     private final Path sourceDirectory;
// 
//     /**
//      * Directory to copy to.
//      */
//     private final Path targetDirectory;
// 
//     public LocalCopyVisitor(final Path sourceDirectory, final Path targetDirectory) {
//         this.sourceDirectory = sourceDirectory;
//         this.targetDirectory = targetDirectory;
//     }
// 
//     @Override
//     public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
//         Files.copy(file, targetDirectory.resolve(sourceDirectory.relativize(file)), StandardCopyOption.REPLACE_EXISTING);
//         return FileVisitResult.CONTINUE;
//     }
// 
//     @Override
//     public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
//         final Path dirToCreate = targetDirectory.resolve(sourceDirectory.relativize(dir));
//         if (Files.notExists(dirToCreate)) {
//             Files.createDirectories(dirToCreate);
//         }
//         return FileVisitResult.CONTINUE;
//     }
// }


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.launcher.util.visitor.ArchiveCopyVisitor;
import org.terasology.launcher.util.visitor.DeleteFileVisitor;
import org.terasology.launcher.util.visitor.LocalCopyVisitor;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;

        try {
            if (Files.notExists(outputLocation)) {
                Files.createDirectories(outputLocation);
            }
            try (FileSystem fileSystem = FileSystems.newFileSystem(archive, ((ClassLoader) null))) {
                for (Path rootDirectory : fileSystem.getRootDirectories()) {
                    Files.walkFileTree(rootDirectory, new ArchiveCopyVisitor(outputLocation));
                }
            }
            return true;
        } catch (IOException e) {
            logger.error("Could not extract zip archive '{}' to '{}'!", archive, outputLocation, e);
            return false;
        }
    }

    /**
     * Copy the whole folder recursively to the specified destination.
     *
     * @param source      the folder to copy
     * @param destination where to copy to
     * @throws IOException if copying fails
     */
    public static void copyFolder(final Path source, final Path destination) throws IOException {
        if (Files.notExists(source)) {
            logger.error("Source file doesn't exists! '{}'", source);
            return;
        }

// Path: src/main/java/org/terasology/launcher/util/visitor/ArchiveCopyVisitor.java
// public class ArchiveCopyVisitor extends SimpleFileVisitor<Path> {
// 
//     /**
//      * Directory to which the files are copied.
//      */
//     private final Path targetLocation;
// 
//     public ArchiveCopyVisitor(final Path targetLocation) {
//         this.targetLocation = targetLocation;
//     }
// 
//     @Override
//     public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
//         final Path destFile = Paths.get(targetLocation.toString() + file.toString());
//         Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);
//         return FileVisitResult.CONTINUE;
//     }
// 
//     @Override
//     public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
//         final Path dirToCreate = Paths.get(targetLocation.toString() + dir.toString());
//         if (Files.notExists(dirToCreate)) {
//             Files.createDirectories(dirToCreate);
//         }
//         return FileVisitResult.CONTINUE;
//     }
// }
// 
// Path: src/main/java/org/terasology/launcher/util/visitor/DeleteFileVisitor.java
// public class DeleteFileVisitor extends SimpleFileVisitor<Path> {
// 
//     @Override
//     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
//         Files.delete(file);
//         return FileVisitResult.CONTINUE;
//     }
// 
//     @Override
//     public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
//         Files.delete(dir);
//         return FileVisitResult.CONTINUE;
//     }
// }
// 
// Path: src/main/java/org/terasology/launcher/util/visitor/LocalCopyVisitor.java
// public class LocalCopyVisitor extends SimpleFileVisitor<Path> {
// 
//     /**
//      * Directory to copy from.
//      */
//     private final Path sourceDirectory;
// 
//     /**
//      * Directory to copy to.
//      */
//     private final Path targetDirectory;
// 
//     public LocalCopyVisitor(final Path sourceDirectory, final Path targetDirectory) {
//         this.sourceDirectory = sourceDirectory;
//         this.targetDirectory = targetDirectory;
//     }
// 
//     @Override
//     public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
//         Files.copy(file, targetDirectory.resolve(sourceDirectory.relativize(file)), StandardCopyOption.REPLACE_EXISTING);
//         return FileVisitResult.CONTINUE;
//     }
// 
//     @Override
//     public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
//         final Path dirToCreate = targetDirectory.resolve(sourceDirectory.relativize(dir));
//         if (Files.notExists(dirToCreate)) {
//             Files.createDirectories(dirToCreate);
//         }
//         return FileVisitResult.CONTINUE;
//     }
// }


// Path: src/main/java/org/terasology/launcher/util/FileUtils.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.launcher.util.visitor.ArchiveCopyVisitor;
import org.terasology.launcher.util.visitor.DeleteFileVisitor;
import org.terasology.launcher.util.visitor.LocalCopyVisitor;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;


        try {
            if (Files.notExists(outputLocation)) {
                Files.createDirectories(outputLocation);
            }
            try (FileSystem fileSystem = FileSystems.newFileSystem(archive, ((ClassLoader) null))) {
                for (Path rootDirectory : fileSystem.getRootDirectories()) {
                    Files.walkFileTree(rootDirectory, new ArchiveCopyVisitor(outputLocation));
                }
            }
            return true;
        } catch (IOException e) {
            logger.error("Could not extract zip archive '{}' to '{}'!", archive, outputLocation, e);
            return false;
        }
    }

    /**
     * Copy the whole folder recursively to the specified destination.
     *
     * @param source      the folder to copy
     * @param destination where to copy to
     * @throws IOException if copying fails
     */
    public static void copyFolder(final Path source, final Path destination) throws IOException {
        if (Files.notExists(source)) {
            logger.error("Source file doesn't exists! '{}'", source);
            return;
        }

        Files.walkFileTree(source, new LocalCopyVisitor(source, destination));