<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:

def put(
    state, host, local_filename, remote_filename,
    user=None, group=None, mode=None, add_deploy_dir=True,
):
    '''
    Copy a local file to the remote system.

    + local_filename: local filename
    + remote_filename: remote filename
    + user: user to own the files
    + group: group to own the files
    + mode: permissions of the files
    '''

    # Upload IO objects as-is
    if hasattr(local_filename, 'read'):
        local_file = local_filename

    # Assume string filename
    else:
        # Add deploy directory?
        if add_deploy_dir and state.deploy_dir:
            local_filename = path.join(state.deploy_dir, local_filename)

        local_file = local_filename

        if not path.isfile(local_file):
            raise IOError('No such file: {0}'.format(local_file))

    mode = ensure_mode_int(mode)
    remote_file = host.fact.file(remote_filename)

    # No remote file, always upload and user/group/mode if supplied
    if not remote_file:
        yield (local_file, remote_filename)

        if user or group:
            yield chown(remote_filename, user, group)

        if mode:
            yield chmod(remote_filename, mode)

    # File exists, check sum and check user/group/mode if supplied
    else:
        local_sum = get_file_sha1(local_filename)
        remote_sum = host.fact.sha1_file(remote_filename)

        # Check sha1sum, upload if needed
        if local_sum != remote_sum:
            yield (local_file, remote_filename)

            if user or group:
                yield chown(remote_filename, user, group)

            if mode:
                yield chmod(remote_filename, mode)

        else:
            # Check mode
            if mode and remote_file['mode'] != mode:
                yield chmod(remote_filename, mode)

            # Check user/group
            if (
                (user and remote_file['user'] != user)
                or (group and remote_file['group'] != group)
            ):
                yield chown(remote_filename, user, group)