<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def convert_join(value):
 """ Fix a Join ;) """


    if not isinstance(value, list) or len(value) != 2:
        # Cowardly refuse
        return value

    sep, parts = value[0], value[1]

    if isinstance(parts, six.string_types):
        return parts

    if not isinstance(parts, list):
        # This looks tricky, just return the join as it was
        return {
            "Fn::Join": value,
        }

    plain_string = True

    args = ODict()
    new_parts = []

    for part in parts:
        part = clean(part)

        if isinstance(part, dict):
            plain_string = False

            if "Ref" in part:
                new_parts.append("${{{}}}".format(part["Ref"]))
            elif "Fn::GetAtt" in part:
                params = part["Fn::GetAtt"]
                new_parts.append("${{{}}}".format(".".join(params)))
            else:
                for key, val in args.items():
                    # we want to bail if a conditional can evaluate to AWS::NoValue
                    if isinstance(val, dict):
                        if "Fn::If" in val and "AWS::NoValue" in str(val["Fn::If"]):
                            return {
                                "Fn::Join": value,
                            }

                    if val == part:
                        param_name = key
                        break
                else:
                    param_name = "Param{}".format(len(args) + 1)
                    args[param_name] = part

                new_parts.append("${{{}}}".format(param_name))

        elif isinstance(part, six.string_types):
            new_parts.append(part.replace("${", "${!"))

        else:
            # Doing something weird; refuse
            return {
                "Fn::Join": value
            }

    source = sep.join(new_parts)

    if plain_string:
        return source

    if args:
        return ODict((
            ("Fn::Sub", [source, args]),
        ))

    return ODict((
        ("Fn::Sub", source),
    ))