<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def reshard(stream_name, desired_size, force=False, region=None, key=None, keyid=None, profile=None):
 """ Reshard a kinesis stream. Each call to this function will wait until the stream is ACTIVE, then make a single split or merge operation. This function decides where to split or merge with the assumption that the ultimate goal is a balanced partition space. For safety, user must past in force=True; otherwise, the function will dry run. CLI example:: salt myminion boto_kinesis.reshard my_stream N True region=us-east-1 :return: True if a split or merge was found/performed, False if nothing is needed """

    conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
    r = {}

    stream_response = get_stream_when_active(stream_name, region, key, keyid, profile)
    if 'error' in stream_response:
        return stream_response

    stream_details = stream_response['result']["StreamDescription"]
    min_hash_key, max_hash_key, stream_details = get_info_for_reshard(stream_details)

    log.debug("found %s open shards, min_hash_key %s max_hash_key %s",
              len(stream_details["OpenShards"]), min_hash_key, max_hash_key)

    # find the first open shard that doesn't match the desired pattern. When we find it,
    # either split or merge (depending on if it's too big or too small), and then return.
    for shard_num, shard in enumerate(stream_details["OpenShards"]):
        shard_id = shard["ShardId"]
        if "EndingSequenceNumber" in shard["SequenceNumberRange"]:
            # something went wrong, there's a closed shard in our open shard list
            log.debug("this should never happen! closed shard %s", shard_id)
            continue

        starting_hash_key = shard["HashKeyRange"]["StartingHashKey"]
        ending_hash_key = shard["HashKeyRange"]["EndingHashKey"]
        # this weird math matches what AWS does when you create a kinesis stream
        # with an initial number of shards.
        expected_starting_hash_key = (
            max_hash_key - min_hash_key) / desired_size * shard_num + shard_num
        expected_ending_hash_key = (
            max_hash_key - min_hash_key) / desired_size * (shard_num + 1) + shard_num
        # fix an off-by-one at the end
        if expected_ending_hash_key > max_hash_key:
            expected_ending_hash_key = max_hash_key

        log.debug(
            "Shard %s (%s) should start at %s: %s",
            shard_num, shard_id, expected_starting_hash_key,
            starting_hash_key == expected_starting_hash_key
        )
        log.debug(
            "Shard %s (%s) should end at %s: %s",
            shard_num, shard_id, expected_ending_hash_key,
            ending_hash_key == expected_ending_hash_key
        )

        if starting_hash_key != expected_starting_hash_key:
            r['error'] = "starting hash keys mismatch, don't know what to do!"
            return r

        if ending_hash_key == expected_ending_hash_key:
            continue

        if ending_hash_key > expected_ending_hash_key + 1:
            # split at expected_ending_hash_key
            if force:
                log.debug("%s should end at %s, actual %s, splitting",
                          shard_id, expected_ending_hash_key, ending_hash_key)
                r = _execute_with_retries(conn,
                                          "split_shard",
                                          StreamName=stream_name,
                                          ShardToSplit=shard_id,
                                          NewStartingHashKey=str(expected_ending_hash_key + 1))  # future lint: disable=blacklisted-function
            else:
                log.debug("%s should end at %s, actual %s would split",
                          shard_id, expected_ending_hash_key, ending_hash_key)

            if 'error' not in r:
                r['result'] = True
            return r
        else:
            # merge
            next_shard_id = _get_next_open_shard(stream_details, shard_id)
            if not next_shard_id:
                r['error'] = "failed to find next shard after {0}".format(shard_id)
                return r
            if force:
                log.debug("%s should continue past %s, merging with %s",
                          shard_id, ending_hash_key, next_shard_id)
                r = _execute_with_retries(conn,
                                          "merge_shards",
                                          StreamName=stream_name,
                                          ShardToMerge=shard_id,
                                          AdjacentShardToMerge=next_shard_id)
            else:
                log.debug("%s should continue past %s, would merge with %s",
                          shard_id, ending_hash_key, next_shard_id)

            if 'error' not in r:
                r['result'] = True
            return r

    log.debug("No split or merge action necessary")
    r['result'] = False
    return r