Resolve resource references within a GetAtt dict.

        Example:
            { "Fn::GetAtt": ["LogicalId", "Arn"] }  =>  {"Fn::GetAtt":  ["ResolvedLogicalId", "Arn"]}


        Theoretically, only the first element of the array can contain reference to SAM resources. The second element
        is name of an attribute (like Arn) of the resource.

        However tools like AWS CLI apply the assumption that first element of the array is a LogicalId and cannot
        contain a 'dot'. So they break at the first dot to convert YAML tag to JSON map like this:

             `!GetAtt LogicalId.Arn` => {"Fn::GetAtt": [ "LogicalId", "Arn" ] }

        Therefore to resolve the reference, we join the array into a string, break it back up to check if it contains
        a known reference, and resolve it if we can.

        :param input_dict: Dictionary to be resolved
        :param dict supported_resource_id_refs: Dictionary that maps old logical ids to new ones.
        :return: Resolved dictionary

def resolve_resource_id_refs(self, input_dict, supported_resource_id_refs):
        """
        Resolve resource references within a GetAtt dict.

        Example:
            { "Fn::GetAtt": ["LogicalId", "Arn"] }  =>  {"Fn::GetAtt":  ["ResolvedLogicalId", "Arn"]}


        Theoretically, only the first element of the array can contain reference to SAM resources. The second element
        is name of an attribute (like Arn) of the resource.

        However tools like AWS CLI apply the assumption that first element of the array is a LogicalId and cannot
        contain a 'dot'. So they break at the first dot to convert YAML tag to JSON map like this:

             `!GetAtt LogicalId.Arn` => {"Fn::GetAtt": [ "LogicalId", "Arn" ] }

        Therefore to resolve the reference, we join the array into a string, break it back up to check if it contains
        a known reference, and resolve it if we can.

        :param input_dict: Dictionary to be resolved
        :param dict supported_resource_id_refs: Dictionary that maps old logical ids to new ones.
        :return: Resolved dictionary
        """

        if not self.can_handle(input_dict):
            return input_dict

        key = self.intrinsic_name
        value = input_dict[key]

        # Value must be an array with *at least* two elements. If not, this is invalid GetAtt syntax. We just pass along
        # the input to CFN for it to do the "official" validation.
        if not isinstance(value, list) or len(value) < 2:
            return input_dict

        value_str = self._resource_ref_separator.join(value)
        splits = value_str.split(self._resource_ref_separator)
        logical_id = splits[0]
        remaining = splits[1:]  # if any

        resolved_value = supported_resource_id_refs.get(logical_id)
        return self._get_resolved_dictionary(input_dict, key, resolved_value, remaining)