// Path: deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/SyncBuildProcessAdapter.java
// public abstract class SyncBuildProcessAdapter extends BuildProcessAdapter {
//   protected final BuildProgressLogger myLogger;
//   private volatile boolean hasFinished;
//   private volatile BuildFinishedStatus statusCode;
//   private volatile boolean isInterrupted;
// 
// 
//   public SyncBuildProcessAdapter(@NotNull final BuildProgressLogger logger) {
//     myLogger = logger;
//     hasFinished = false;
//     statusCode = null;
//   }
// 
// 
//   @Override
//   public void interrupt() {
//     isInterrupted = true;
//   }
// 
//   @Override
//   public boolean isInterrupted() {
//     return isInterrupted;
//   }
// 
//   @Override
//   public boolean isFinished() {
//     return hasFinished;
//   }
// 
//   @NotNull
//   @Override
//   public BuildFinishedStatus waitFor() throws RunBuildException {
//     while (!isInterrupted() && !hasFinished) {
//       try {
//         Thread.sleep(1000);
//       } catch (InterruptedException e) {
//         throw new RunBuildException(e);
//       }
//     }
//     return hasFinished ? statusCode : BuildFinishedStatus.INTERRUPTED;
//   }
// 
//   @Override
//   public void start() throws RunBuildException {
//     try {
//       statusCode = runProcess();
//       hasFinished = true;
//     } catch (UploadInterruptedException e) {
//       hasFinished = false;
//     }
//   }
// 
//   /**
//    * @return true is process finished successfully
//    */
//   protected abstract BuildFinishedStatus runProcess();
// 
//   protected void checkIsInterrupted() throws UploadInterruptedException {
//     if (isInterrupted()) throw new UploadInterruptedException();
//   }
// 
// }
// 
// Path: deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/UploadInterruptedException.java
// public class UploadInterruptedException extends RuntimeException {
// 
// }
// 
// Path: deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/DeployerAgentUtils.java
// public static void logBuildProblem(BuildProgressLogger logger, String message) {
//   logger.logBuildProblem(BuildProblemData
//           .createBuildProblem(String.valueOf(message.hashCode()),
//                   DeployerRunnerConstants.BUILD_PROBLEM_TYPE,
//                   "Deployment problem: " + message));
// }


import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.mssmb.SMB1NotSupportedException;
import com.hierynomus.mssmb2.SMB2ShareAccess;
import com.hierynomus.protocol.transport.TransportException;
import com.hierynomus.smbj.SMBClient;
import com.hierynomus.smbj.SmbConfig;
import com.hierynomus.smbj.auth.AuthenticationContext;
import com.hierynomus.smbj.common.SMBRuntimeException;
import com.hierynomus.smbj.connection.Connection;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.Share;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import jetbrains.buildServer.agent.BuildFinishedStatus;
import jetbrains.buildServer.agent.BuildRunnerContext;
import jetbrains.buildServer.agent.impl.artifacts.ArtifactsCollection;
import jetbrains.buildServer.deployer.agent.SyncBuildProcessAdapter;
import jetbrains.buildServer.deployer.agent.UploadInterruptedException;
import jetbrains.buildServer.log.Loggers;
import jetbrains.buildServer.util.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import static com.hierynomus.mssmb2.SMB2CreateDisposition.FILE_OVERWRITE_IF;
import static jetbrains.buildServer.deployer.agent.DeployerAgentUtils.logBuildProblem;

      Connection connection = client.connect(host);
      Session session = connection.authenticate(new AuthenticationContext(myUsername, myPassword.toCharArray(), myDomain));
      Share share = session.connectShare(shareName);

      if (share instanceof DiskShare) {
        DiskShare diskShare = (DiskShare)share;
        for (ArtifactsCollection artifactsCollection : myArtifactsCollections) {
          final int numOfUploadedFiles = upload(artifactsCollection.getFilePathMap(), diskShare, pathInShare);
          myLogger.message("Uploaded [" + numOfUploadedFiles + "] files for [" + artifactsCollection.getSourcePath() + "] pattern");
        }

      } else {
        logBuildProblem(myLogger, "Shared resource [" + shareName + "] is not a folder, can not upload files.");
        return BuildFinishedStatus.FINISHED_FAILED;
      }

      return BuildFinishedStatus.FINISHED_SUCCESS;
    } catch (TransportException e) {

      final String message;
      if (hasCauseOfType(SMB1NotSupportedException.class, e)) {
        message = "The remote host [" + host + "] does not support SMBv2 or support was explicitly disabled. Please, check the remote host configuration";
      } else {
        message = e.getMessage();
      }
      logBuildProblem(myLogger, message);

      LOG.warnAndDebugDetails("Error executing SMB command", e);
      return BuildFinishedStatus.FINISHED_FAILED;
// Path: deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/SyncBuildProcessAdapter.java
// public abstract class SyncBuildProcessAdapter extends BuildProcessAdapter {
//   protected final BuildProgressLogger myLogger;
//   private volatile boolean hasFinished;
//   private volatile BuildFinishedStatus statusCode;
//   private volatile boolean isInterrupted;
// 
// 
//   public SyncBuildProcessAdapter(@NotNull final BuildProgressLogger logger) {
//     myLogger = logger;
//     hasFinished = false;
//     statusCode = null;
//   }
// 
// 
//   @Override
//   public void interrupt() {
//     isInterrupted = true;
//   }
// 
//   @Override
//   public boolean isInterrupted() {
//     return isInterrupted;
//   }
// 
//   @Override
//   public boolean isFinished() {
//     return hasFinished;
//   }
// 
//   @NotNull
//   @Override
//   public BuildFinishedStatus waitFor() throws RunBuildException {
//     while (!isInterrupted() && !hasFinished) {
//       try {
//         Thread.sleep(1000);
//       } catch (InterruptedException e) {
//         throw new RunBuildException(e);
//       }
//     }
//     return hasFinished ? statusCode : BuildFinishedStatus.INTERRUPTED;
//   }
// 
//   @Override
//   public void start() throws RunBuildException {
//     try {
//       statusCode = runProcess();
//       hasFinished = true;
//     } catch (UploadInterruptedException e) {
//       hasFinished = false;
//     }
//   }
// 
//   /**
//    * @return true is process finished successfully
//    */
//   protected abstract BuildFinishedStatus runProcess();
// 
//   protected void checkIsInterrupted() throws UploadInterruptedException {
//     if (isInterrupted()) throw new UploadInterruptedException();
//   }
// 
// }
// 
// Path: deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/UploadInterruptedException.java
// public class UploadInterruptedException extends RuntimeException {
// 
// }
// 
// Path: deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/DeployerAgentUtils.java
// public static void logBuildProblem(BuildProgressLogger logger, String message) {
//   logger.logBuildProblem(BuildProblemData
//           .createBuildProblem(String.valueOf(message.hashCode()),
//                   DeployerRunnerConstants.BUILD_PROBLEM_TYPE,
//                   "Deployment problem: " + message));
// }


// Path: deploy-runner-agent-smb2/src/main/java/jetbrains/buildServer/deployer/agent/smb/SMBJBuildProcessAdapter.java
import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.mssmb.SMB1NotSupportedException;
import com.hierynomus.mssmb2.SMB2ShareAccess;
import com.hierynomus.protocol.transport.TransportException;
import com.hierynomus.smbj.SMBClient;
import com.hierynomus.smbj.SmbConfig;
import com.hierynomus.smbj.auth.AuthenticationContext;
import com.hierynomus.smbj.common.SMBRuntimeException;
import com.hierynomus.smbj.connection.Connection;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.Share;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import jetbrains.buildServer.agent.BuildFinishedStatus;
import jetbrains.buildServer.agent.BuildRunnerContext;
import jetbrains.buildServer.agent.impl.artifacts.ArtifactsCollection;
import jetbrains.buildServer.deployer.agent.SyncBuildProcessAdapter;
import jetbrains.buildServer.deployer.agent.UploadInterruptedException;
import jetbrains.buildServer.log.Loggers;
import jetbrains.buildServer.util.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import static com.hierynomus.mssmb2.SMB2CreateDisposition.FILE_OVERWRITE_IF;
import static jetbrains.buildServer.deployer.agent.DeployerAgentUtils.logBuildProblem;


      Connection connection = client.connect(host);
      Session session = connection.authenticate(new AuthenticationContext(myUsername, myPassword.toCharArray(), myDomain));
      Share share = session.connectShare(shareName);

      if (share instanceof DiskShare) {
        DiskShare diskShare = (DiskShare)share;
        for (ArtifactsCollection artifactsCollection : myArtifactsCollections) {
          final int numOfUploadedFiles = upload(artifactsCollection.getFilePathMap(), diskShare, pathInShare);
          myLogger.message("Uploaded [" + numOfUploadedFiles + "] files for [" + artifactsCollection.getSourcePath() + "] pattern");
        }

      } else {
        logBuildProblem(myLogger, "Shared resource [" + shareName + "] is not a folder, can not upload files.");
        return BuildFinishedStatus.FINISHED_FAILED;
      }

      return BuildFinishedStatus.FINISHED_SUCCESS;
    } catch (TransportException e) {

      final String message;
      if (hasCauseOfType(SMB1NotSupportedException.class, e)) {
        message = "The remote host [" + host + "] does not support SMBv2 or support was explicitly disabled. Please, check the remote host configuration";
      } else {
        message = e.getMessage();
      }
      logBuildProblem(myLogger, message);

      LOG.warnAndDebugDetails("Error executing SMB command", e);
      return BuildFinishedStatus.FINISHED_FAILED;
    } catch (UploadInterruptedException e) {