// Path: core/src/main/java/me/gregorias/dfuntest/util/FileUtilsImpl.java
// public class FileUtilsImpl implements FileUtils {
//   private static FileUtilsImpl FILE_UTILS_IMPL = new FileUtilsImpl();
// 
//   @Override
//   public void copyDirectoryToDirectory(File from, File to) throws IOException {
//     org.apache.commons.io.FileUtils.copyDirectoryToDirectory(from, to);
//   }
// 
//   @Override
//   public void copyFileToDirectory(File from, File to) throws IOException {
//     org.apache.commons.io.FileUtils.copyFileToDirectory(from, to);
//   }
// 
//   @Override
//   public void createDirectories(Path path) throws IOException {
//     Files.createDirectories(path);
//   }
// 
//   @Override
//   public Path createTempDirectory(String dirPrefix) throws IOException {
//     return Files.createTempDirectory(dirPrefix);
//   }
// 
//   @Override
//   public boolean deleteQuietly(File file) {
//     return org.apache.commons.io.FileUtils.deleteQuietly(file);
//   }
// 
//   @Override
//   public boolean exists(Path path) {
//     return Files.exists(path);
//   }
// 
//   public static FileUtilsImpl getFileUtilsImpl() {
//     return FILE_UTILS_IMPL;
//   }
// 
//   @Override
//   public boolean isDirectory(Path path) {
//     return Files.isDirectory(path);
//   }
// 
//   @Override
//   public Process runCommand(List<String> command, File pwdFile) throws IOException {
//     ProcessBuilder pb = new ProcessBuilder();
//     pb.command(command).directory(pwdFile);
//     return pb.start();
//   }
// 
//   @Override
//   public void write(Path path, String content) throws IOException {
//     StandardOpenOption[] options = new StandardOpenOption[3];
// 
//     options[0] = StandardOpenOption.CREATE;
//     options[1] = StandardOpenOption.WRITE;
//     options[2] = StandardOpenOption.APPEND;
// 
//     Collection<String> lines = new ArrayList<>();
//     lines.add(content);
//     Files.write(path, lines, Charset.defaultCharset(), options);
//   }
// }
// 
// Path: core/src/main/java/me/gregorias/dfuntest/util/SSHClientFactory.java
// public class SSHClientFactory {
//   private static SSHClientFactory SSH_CLIENT_FACTORY = null;
// 
//   public static synchronized SSHClientFactory getSSHClientFactory() {
//     if (SSH_CLIENT_FACTORY == null) {
//       SSH_CLIENT_FACTORY = new SSHClientFactory();
//     }
//     return SSH_CLIENT_FACTORY;
//   }
// 
//   public SSHClient newSSHClient() {
//     return new SSHClient();
//   }
// }


import java.io.IOException;
import java.net.InetAddress;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import me.gregorias.dfuntest.util.FileUtilsImpl;
import me.gregorias.dfuntest.util.SSHClientFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
      @Named(HOSTS_ARGUMENT_NAME) Collection<String> hosts,
      @Named(USERNAME_ARGUMENT_NAME) String username,
      @Named(PRIVATE_KEY_PATH) Path privateKeyPath,
      @Named(REMOTE_DIR_ARGUMENT_NAME) String remoteDir,
      @Named(EXECUTOR_ARGUMENT_NAME) Executor executor) {
    if (hosts.size() == 0) {
      throw new IllegalArgumentException("Hosts collection is empty.");
    }
    mHostnames = new ArrayList<>(hosts);
    mUsername = username;
    mPrivateKeyPath = privateKeyPath;
    mRemoteDir = remoteDir;
    mExecutor = executor;
  }

  @Override
  public Collection<Environment> create() throws IOException {
    LOGGER.info("create()");

    Collection<Environment> environments = new ArrayList<>();
    for (int envIdx = 0; envIdx < mHostnames.size(); ++envIdx) {
      LOGGER.trace("create(): Setting up environment for host: {}.", mHostnames.get(envIdx));

      InetAddress hostInetAddress = InetAddress.getByName(mHostnames.get(envIdx));
      final Environment env = new SSHEnvironment(envIdx,
          mUsername,
          mPrivateKeyPath,
          hostInetAddress,
          String.format("%s%04d", mRemoteDir, envIdx),
          mExecutor,
// Path: core/src/main/java/me/gregorias/dfuntest/util/FileUtilsImpl.java
// public class FileUtilsImpl implements FileUtils {
//   private static FileUtilsImpl FILE_UTILS_IMPL = new FileUtilsImpl();
// 
//   @Override
//   public void copyDirectoryToDirectory(File from, File to) throws IOException {
//     org.apache.commons.io.FileUtils.copyDirectoryToDirectory(from, to);
//   }
// 
//   @Override
//   public void copyFileToDirectory(File from, File to) throws IOException {
//     org.apache.commons.io.FileUtils.copyFileToDirectory(from, to);
//   }
// 
//   @Override
//   public void createDirectories(Path path) throws IOException {
//     Files.createDirectories(path);
//   }
// 
//   @Override
//   public Path createTempDirectory(String dirPrefix) throws IOException {
//     return Files.createTempDirectory(dirPrefix);
//   }
// 
//   @Override
//   public boolean deleteQuietly(File file) {
//     return org.apache.commons.io.FileUtils.deleteQuietly(file);
//   }
// 
//   @Override
//   public boolean exists(Path path) {
//     return Files.exists(path);
//   }
// 
//   public static FileUtilsImpl getFileUtilsImpl() {
//     return FILE_UTILS_IMPL;
//   }
// 
//   @Override
//   public boolean isDirectory(Path path) {
//     return Files.isDirectory(path);
//   }
// 
//   @Override
//   public Process runCommand(List<String> command, File pwdFile) throws IOException {
//     ProcessBuilder pb = new ProcessBuilder();
//     pb.command(command).directory(pwdFile);
//     return pb.start();
//   }
// 
//   @Override
//   public void write(Path path, String content) throws IOException {
//     StandardOpenOption[] options = new StandardOpenOption[3];
// 
//     options[0] = StandardOpenOption.CREATE;
//     options[1] = StandardOpenOption.WRITE;
//     options[2] = StandardOpenOption.APPEND;
// 
//     Collection<String> lines = new ArrayList<>();
//     lines.add(content);
//     Files.write(path, lines, Charset.defaultCharset(), options);
//   }
// }
// 
// Path: core/src/main/java/me/gregorias/dfuntest/util/SSHClientFactory.java
// public class SSHClientFactory {
//   private static SSHClientFactory SSH_CLIENT_FACTORY = null;
// 
//   public static synchronized SSHClientFactory getSSHClientFactory() {
//     if (SSH_CLIENT_FACTORY == null) {
//       SSH_CLIENT_FACTORY = new SSHClientFactory();
//     }
//     return SSH_CLIENT_FACTORY;
//   }
// 
//   public SSHClient newSSHClient() {
//     return new SSHClient();
//   }
// }


// Path: core/src/main/java/me/gregorias/dfuntest/SSHEnvironmentFactory.java
import java.io.IOException;
import java.net.InetAddress;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import me.gregorias.dfuntest.util.FileUtilsImpl;
import me.gregorias.dfuntest.util.SSHClientFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

      @Named(HOSTS_ARGUMENT_NAME) Collection<String> hosts,
      @Named(USERNAME_ARGUMENT_NAME) String username,
      @Named(PRIVATE_KEY_PATH) Path privateKeyPath,
      @Named(REMOTE_DIR_ARGUMENT_NAME) String remoteDir,
      @Named(EXECUTOR_ARGUMENT_NAME) Executor executor) {
    if (hosts.size() == 0) {
      throw new IllegalArgumentException("Hosts collection is empty.");
    }
    mHostnames = new ArrayList<>(hosts);
    mUsername = username;
    mPrivateKeyPath = privateKeyPath;
    mRemoteDir = remoteDir;
    mExecutor = executor;
  }

  @Override
  public Collection<Environment> create() throws IOException {
    LOGGER.info("create()");

    Collection<Environment> environments = new ArrayList<>();
    for (int envIdx = 0; envIdx < mHostnames.size(); ++envIdx) {
      LOGGER.trace("create(): Setting up environment for host: {}.", mHostnames.get(envIdx));

      InetAddress hostInetAddress = InetAddress.getByName(mHostnames.get(envIdx));
      final Environment env = new SSHEnvironment(envIdx,
          mUsername,
          mPrivateKeyPath,
          hostInetAddress,
          String.format("%s%04d", mRemoteDir, envIdx),
          mExecutor,
          SSHClientFactory.getSSHClientFactory(),