a method to copy a folder or file from local device to AWS instance

        :param local_path: string with path to folder or file on local host
        :param remote_path: [optional] string with path to copy contents on remote host
        :param overwrite: [optional] boolean to enable file overwrite on remote host
        :param synopsis: [optional] boolean to simplify progress messages to one line
        :return: string with response

def put(self, local_path, remote_path='', overwrite=False, synopsis=True):

        '''
            a method to copy a folder or file from local device to AWS instance

        :param local_path: string with path to folder or file on local host
        :param remote_path: [optional] string with path to copy contents on remote host
        :param overwrite: [optional] boolean to enable file overwrite on remote host
        :param synopsis: [optional] boolean to simplify progress messages to one line
        :return: string with response
        '''

        title = '%s.put' % self.__class__.__name__

    # validate inputs
        input_fields = {
            'local_path': local_path,
            'remote_path': remote_path
        }
        for key, value in input_fields.items():
            if value:
                object_title = '%s(%s=%s)' % (title, key, str(value))
                self.fields.validate(value, '.%s' % key, object_title)
        
    # verify local path exists
        from os import path
        if not path.exists(local_path):
            raise Exception('%s is not a valid path on local host.' % local_path)
        local_path_root, local_path_node = path.split(local_path)

    # verify remote root exists
        self.ec2.iam.printer_on = False
        if remote_path:
            remote_path_root, remote_path_node = path.split(remote_path)
            if not remote_path_root:
                remote_path_root = '~/'
                remote_path = path.join(remote_path_root, remote_path_node)
            remote_path_root = remote_path_root.replace(' ', '\ ')
            remote_path_node = remote_path_node.replace(' ', '\ ')
            test_root_cmd = 'cd %s' % remote_path_root
            try:
                self.script(test_root_cmd)
            except:
                raise ValueError('%s folder does not exist on remote host. Canceling transfer.' % remote_path_root)
            remote_path = remote_path.replace(' ', '\ ')
        else:
            from copy import deepcopy
            remote_path_node = deepcopy(local_path_node)
            remote_path_root = '~/'
            remote_path = '~/%s' % remote_path_node.replace(' ','\ ')

    # verify remote path does not exist
        if not overwrite:
            try:
                test_path_cmd = 'ls %s' % remote_path
                self.script(test_path_cmd)
            except Exception as err:
                pass
            else:
                raise ValueError('%s already exists on remote host. Canceling transfer.' % remote_path)

    # verify installation of scp on remote host
        if not self.scp:
            try:
                self.script('scp')
                self.scp = True
            except Exception as err:
                if str(err).find('usage: scp') > 1:
                    self.scp = True
                else:
                    raise Exception('SCP needs to be installed on remote host. Canceling transfer.\nOn remote host, try: sudo yum install -y git')

    # determine sudo privileges
        sudo_insert = 'sudo '
        user_abs = self.script('readlink -f ~/')
        remote_abs = self.script('readlink -f %s' % remote_path_root)
        if remote_abs.find(user_abs) > -1:
            sudo_insert = ''
        self.ec2.iam.printer_on = True

    # initiate transfer process
        remote_host = '[%s@%s]' % (self.login_name, self.instance_ip)
        if synopsis:
            self.ec2.iam.printer('Transferring %s to %s:%s ... ' % (local_path, remote_host, remote_path), flush=True)
            self.ec2.iam.printer_on = False
        self.ec2.iam.printer('Initiating transfer of %s to %s:%s.' % (local_path, remote_host, remote_path))

    # construct temporary file folder
        from labpack import __module__
        from labpack.storage.appdata import appdataClient
        client_kwargs = {
            'collection_name': 'TempFiles',
            'prod_name': __module__
        }
        tempfiles_client = appdataClient(**client_kwargs)

    # make local folder into a tar file
        from time import time
        tar_file = 'temp%s.tar.gz' % str(time())
        tar_path = path.join(tempfiles_client.collection_folder, tar_file)
        self.ec2.iam.printer('Creating temporary file %s ... ' % tar_file, flush=True)
        def _make_tar(source_path, output_file, content_name=''):
            kw_args = { 'name': source_path }
            if content_name:
                kw_args['arcname'] = content_name
            with tarfile.open(output_file, 'w:gz') as tar:
                tar.add(**kw_args)
        _make_tar(local_path, tar_path, remote_path_node)
        self.ec2.iam.printer('done.')

    # define cleanup function
        def _cleanup_temp(tar_file):
            self.ec2.iam.printer('Cleaning up temporary file %s ... ' % tar_file, flush=True)
            tempfiles_client.delete(tar_file)
            self.ec2.iam.printer('done.')

    # initiate scp transfer of tar file
        copy_msg = 'Copying %s to %s:~/%s ... ' % (tar_file, remote_host, tar_file)
        error_msg = 'Failure copying file %s to ip %s.' % (tar_file, self.instance_ip)

    # use paramiko on windows systems
        if self.localhost.os.sysname in ('Windows'):
            ssh_key = paramiko.RSAKey.from_private_key_file(self.pem_file)
            client = paramiko.SSHClient()
            client.load_system_host_keys()
            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            client.connect(hostname=self.instance_ip, username=self.ec2.iam.user_name, pkey=ssh_key)
            scp_transport = scp.SCPClient(client.get_transport())
            self.ec2.iam.printer(copy_msg, flush=True)
            try:
                response = scp_transport.put(tar_path, tar_file)
            except:
                self.ec2.iam.printer('ERROR.')
                _cleanup_temp(tar_file)
                raise Exception(error_msg)
            client.close()
            self.ec2.iam.printer('done.')

    # use scp on other systems
        else:
            self.ec2.iam.printer(copy_msg, flush=True)
            sys_command = 'scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentityFile="%s" "%s" %s@%s:~/' % (self.pem_file, tar_path, self.login_name, self.instance_ip)
            from subprocess import check_output, CalledProcessError, STDOUT
            try:
                response = check_output(sys_command, shell=True, stderr=STDOUT).decode('utf-8')
                self.ec2.iam.printer('done.')
            except CalledProcessError as err:
                self.ec2.iam.printer('ERROR.')
                _cleanup_temp(tar_file)
                print(err)
                raise Exception(error_msg)

    # extract tar file to remote path
        extract_cmd = '%star -C %s -xvf %s' % (sudo_insert, remote_path_root, tar_file)
        ext_kwargs = {
            'commands': extract_cmd,
            'synopsis': True
        }
        try:
            self.script(**ext_kwargs)
        except:
            _cleanup_temp(tar_file)
            raise

    # cleanup temporary files on remote host
        rm_cmd = 'sudo rm -f %s' % tar_file
        rm_kwargs = {
            'commands': rm_cmd,
            'synopsis': True
        }
        try:
            self.script(**rm_kwargs)
        except:
            _cleanup_temp(tar_file)
            raise

    # cleanup local temporary files and return response
        _cleanup_temp(tar_file)
        self.ec2.iam.printer('Transfer of %s to %s:%s complete.' % (local_path, remote_host, remote_path))
        if synopsis:
            self.ec2.iam.printer_on = True
            self.ec2.iam.printer('done.')

        return response