prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  E0002 bug when using parameters for DynamoDB AttributeDefinitions
  *cfn-lint version: 0.28.2*
  
  *Description of issue.*
  
  Rule E3039 (added in 0.28.0) doesn't support Refs and results in a E0002 error for the template. 
  
  Repeatable with this template snippet:
  
  ```
  AWSTemplateFormatVersion: '2010-09-09'
  
  Parameters:
      HashKeyName:
          Description: Primary Key Name
          Type: String
          AllowedPattern: '[a-zA-Z0-9]*'
          MinLength: '1'
          MaxLength: '2048'
          ConstraintDescription: must contain only alphanumberic characters
  
      HashKeyType:
          Description: Primary Key Type
          Type: String
          Default: S
          AllowedPattern: '[S|N]'
          MinLength: '1'
          MaxLength: '1'
          ConstraintDescription: must be either S or N
  
      RangeKeyName:
          Description: Sort Key Name
          Type: String
          Default: 'NA'
          AllowedPattern: '[a-zA-Z0-9]*'
          MinLength: '0'
          MaxLength: '2048'
          ConstraintDescription: must contain only alphanumberic characters
  
      RangeKeyType:
          Description: Sort Key Type
          Type: String
          Default: S
          AllowedPattern: '[S|N]'
          MinLength: '0'
          MaxLength: '1'
          ConstraintDescription: must be either S or Ns
  
  Conditions:
      isRangeKeyAvailable: !Not [ !Equals [ !Ref RangeKeyName, 'NA' ] ]
  
  Resources:
      DynamoDBTable:
          DeletionPolicy: Delete
          UpdateReplacePolicy: Delete
          Type: AWS::DynamoDB::Table
          Properties:
              AttributeDefinitions: !If
                  - isRangeKeyAvailable
                  - - AttributeName: !Ref HashKeyName
                      AttributeType: !Ref HashKeyType
                    - AttributeName: !Ref RangeKeyName
                      AttributeType: !Ref RangeKeyType
                  - - AttributeName: !Ref HashKeyName
                      AttributeType: !Ref HashKeyType
              KeySchema: !If
                  - isRangeKeyAvailable
                  - - AttributeName: !Ref HashKeyName
                      KeyType: HASH
                    - AttributeName: !Ref RangeKeyName
                      KeyType: RANGE
                  - - AttributeName: !Ref HashKeyName
                      KeyType: HASH
  ```
  
  
  </issue>
  <code>
  [start of src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py]
  1 """
  2 Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3 SPDX-License-Identifier: MIT-0
  4 """
  5 import six
  6 from cfnlint.decode.node import list_node
  7 from cfnlint.rules import CloudFormationLintRule
  8 from cfnlint.rules import RuleMatch
  9 
  10 
  11 class AttributeMismatch(CloudFormationLintRule):
  12     """Check DynamoDB Attributes"""
  13     id = 'E3039'
  14     shortdesc = 'AttributeDefinitions / KeySchemas mismatch'
  15     description = 'Verify the set of Attributes in AttributeDefinitions and KeySchemas match'
  16     source_url = 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html'
  17     tags = ['resources', 'dynamodb']
  18 
  19     def __init__(self):
  20         """Init"""
  21         super(AttributeMismatch, self).__init__()
  22         self.resource_property_types = ['AWS::DynamoDB::Table']
  23 
  24     def _get_key_schema_attributes(self, key_schemas_sets):
  25         """ Get Key Schema attributes """
  26         keys = set()
  27 
  28         for properties, _ in key_schemas_sets:
  29             for key in properties:
  30                 attribute_name = key.get_safe('AttributeName', type_t=six.string_types)
  31                 if attribute_name:
  32                     keys.add(key.get('AttributeName'))
  33         return keys
  34 
  35     def _get_attribute_secondary(self, property_sets):
  36         """ Get the key schemas from secondary indexes """
  37         keys = set()
  38 
  39         for properties, _ in property_sets:
  40             for index in properties:
  41                 keys = keys.union(
  42                     self._get_key_schema_attributes(
  43                         index.get_safe('KeySchema', list_node([], None, None), [], list)
  44                     )
  45                 )
  46 
  47         return keys
  48 
  49     def check_property_set(self, property_set, path):
  50         """ Check a property set """
  51         matches = []
  52         properties = property_set.get('Object')
  53 
  54         keys = set()
  55         attributes = set()
  56 
  57         for attribute in properties.get('AttributeDefinitions', []):
  58             attribute_name = attribute.get('AttributeName')
  59             if isinstance(attribute_name, six.string_types):
  60                 attributes.add(attribute.get('AttributeName'))
  61             else:
  62                 self.logger.info('attribute definitions is not using just strings')
  63                 return matches
  64         keys = keys.union(
  65             self._get_key_schema_attributes(
  66                 properties.get_safe('KeySchema', list_node([], None, None), [], list)
  67             )
  68         )
  69         keys = keys.union(self._get_attribute_secondary(
  70             properties.get_safe('GlobalSecondaryIndexes', list_node([], None, None), path, list
  71                                 )))  # pylint: disable=bad-continuation
  72         keys = keys.union(self._get_attribute_secondary(
  73             properties.get_safe('LocalSecondaryIndexes', list_node([], None, None), path, list
  74                                 )))  # pylint: disable=bad-continuation
  75 
  76         if attributes != keys:
  77             message = 'The set of Attributes in AttributeDefinitions: {0} and KeySchemas: {1} must match at {2}'
  78             matches.append(RuleMatch(
  79                 path,
  80                 message.format(sorted(list(attributes)), sorted(list(keys)), '/'.join(map(str, path)))
  81             ))
  82 
  83         return matches
  84 
  85     def check(self, properties, path, cfn):
  86         """Check itself"""
  87         matches = []
  88 
  89         property_sets = cfn.get_object_without_conditions(properties, path)
  90         for property_set in property_sets:
  91             matches.extend(self.check_property_set(property_set, path))
  92         return matches
  93 
  94     def match_resource_properties(self, properties, _, path, cfn):
  95         """Match for sub properties"""
  96         matches = []
  97         matches.extend(self.check(properties, path, cfn))
  98         return matches
  99
  [end of src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py b/src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py
  --- a/src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py
  +++ b/src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py
  @@ -77,7 +77,8 @@
               message = 'The set of Attributes in AttributeDefinitions: {0} and KeySchemas: {1} must match at {2}'
               matches.append(RuleMatch(
                   path,
  -                message.format(sorted(list(attributes)), sorted(list(keys)), '/'.join(map(str, path)))
  +                message.format(sorted(list(attributes)), sorted(
  +                    list(keys)), '/'.join(map(str, path)))
               ))
   
           return matches
  @@ -86,7 +87,8 @@
           """Check itself"""
           matches = []
   
  -        property_sets = cfn.get_object_without_conditions(properties, path)
  +        property_sets = cfn.get_object_without_conditions(
  +            properties, ['AttributeDefinitions', 'KeySchema', 'GlobalSecondaryIndexes', 'LocalSecondaryIndexes'])
           for property_set in property_sets:
               matches.extend(self.check_property_set(property_set, path))
           return matches
  
verification_info: {"golden_diff": "diff --git a/src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py b/src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py\n--- a/src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py\n+++ b/src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py\n@@ -77,7 +77,8 @@\n             message = 'The set of Attributes in AttributeDefinitions: {0} and KeySchemas: {1} must match at {2}'\n             matches.append(RuleMatch(\n                 path,\n-                message.format(sorted(list(attributes)), sorted(list(keys)), '/'.join(map(str, path)))\n+                message.format(sorted(list(attributes)), sorted(\n+                    list(keys)), '/'.join(map(str, path)))\n             ))\n \n         return matches\n@@ -86,7 +87,8 @@\n         \"\"\"Check itself\"\"\"\n         matches = []\n \n-        property_sets = cfn.get_object_without_conditions(properties, path)\n+        property_sets = cfn.get_object_without_conditions(\n+            properties, ['AttributeDefinitions', 'KeySchema', 'GlobalSecondaryIndexes', 'LocalSecondaryIndexes'])\n         for property_set in property_sets:\n             matches.extend(self.check_property_set(property_set, path))\n         return matches\n", "issue": "E0002 bug when using parameters for DynamoDB AttributeDefinitions\n*cfn-lint version: 0.28.2*\r\n\r\n*Description of issue.*\r\n\r\nRule E3039 (added in 0.28.0) doesn't support Refs and results in a E0002 error for the template. \r\n\r\nRepeatable with this template snippet:\r\n\r\n```\r\nAWSTemplateFormatVersion: '2010-09-09'\r\n\r\nParameters:\r\n    HashKeyName:\r\n        Description: Primary Key Name\r\n        Type: String\r\n        AllowedPattern: '[a-zA-Z0-9]*'\r\n        MinLength: '1'\r\n        MaxLength: '2048'\r\n        ConstraintDescription: must contain only alphanumberic characters\r\n\r\n    HashKeyType:\r\n        Description: Primary Key Type\r\n        Type: String\r\n        Default: S\r\n        AllowedPattern: '[S|N]'\r\n        MinLength: '1'\r\n        MaxLength: '1'\r\n        ConstraintDescription: must be either S or N\r\n\r\n    RangeKeyName:\r\n        Description: Sort Key Name\r\n        Type: String\r\n        Default: 'NA'\r\n        AllowedPattern: '[a-zA-Z0-9]*'\r\n        MinLength: '0'\r\n        MaxLength: '2048'\r\n        ConstraintDescription: must contain only alphanumberic characters\r\n\r\n    RangeKeyType:\r\n        Description: Sort Key Type\r\n        Type: String\r\n        Default: S\r\n        AllowedPattern: '[S|N]'\r\n        MinLength: '0'\r\n        MaxLength: '1'\r\n        ConstraintDescription: must be either S or Ns\r\n\r\nConditions:\r\n    isRangeKeyAvailable: !Not [ !Equals [ !Ref RangeKeyName, 'NA' ] ]\r\n\r\nResources:\r\n    DynamoDBTable:\r\n        DeletionPolicy: Delete\r\n        UpdateReplacePolicy: Delete\r\n        Type: AWS::DynamoDB::Table\r\n        Properties:\r\n            AttributeDefinitions: !If\r\n                - isRangeKeyAvailable\r\n                - - AttributeName: !Ref HashKeyName\r\n                    AttributeType: !Ref HashKeyType\r\n                  - AttributeName: !Ref RangeKeyName\r\n                    AttributeType: !Ref RangeKeyType\r\n                - - AttributeName: !Ref HashKeyName\r\n                    AttributeType: !Ref HashKeyType\r\n            KeySchema: !If\r\n                - isRangeKeyAvailable\r\n                - - AttributeName: !Ref HashKeyName\r\n                    KeyType: HASH\r\n                  - AttributeName: !Ref RangeKeyName\r\n                    KeyType: RANGE\r\n                - - AttributeName: !Ref HashKeyName\r\n                    KeyType: HASH\r\n```\r\n\n", "before_files": [{"content": "\"\"\"\nCopyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: MIT-0\n\"\"\"\nimport six\nfrom cfnlint.decode.node import list_node\nfrom cfnlint.rules import CloudFormationLintRule\nfrom cfnlint.rules import RuleMatch\n\n\nclass AttributeMismatch(CloudFormationLintRule):\n    \"\"\"Check DynamoDB Attributes\"\"\"\n    id = 'E3039'\n    shortdesc = 'AttributeDefinitions / KeySchemas mismatch'\n    description = 'Verify the set of Attributes in AttributeDefinitions and KeySchemas match'\n    source_url = 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html'\n    tags = ['resources', 'dynamodb']\n\n    def __init__(self):\n        \"\"\"Init\"\"\"\n        super(AttributeMismatch, self).__init__()\n        self.resource_property_types = ['AWS::DynamoDB::Table']\n\n    def _get_key_schema_attributes(self, key_schemas_sets):\n        \"\"\" Get Key Schema attributes \"\"\"\n        keys = set()\n\n        for properties, _ in key_schemas_sets:\n            for key in properties:\n                attribute_name = key.get_safe('AttributeName', type_t=six.string_types)\n                if attribute_name:\n                    keys.add(key.get('AttributeName'))\n        return keys\n\n    def _get_attribute_secondary(self, property_sets):\n        \"\"\" Get the key schemas from secondary indexes \"\"\"\n        keys = set()\n\n        for properties, _ in property_sets:\n            for index in properties:\n                keys = keys.union(\n                    self._get_key_schema_attributes(\n                        index.get_safe('KeySchema', list_node([], None, None), [], list)\n                    )\n                )\n\n        return keys\n\n    def check_property_set(self, property_set, path):\n        \"\"\" Check a property set \"\"\"\n        matches = []\n        properties = property_set.get('Object')\n\n        keys = set()\n        attributes = set()\n\n        for attribute in properties.get('AttributeDefinitions', []):\n            attribute_name = attribute.get('AttributeName')\n            if isinstance(attribute_name, six.string_types):\n                attributes.add(attribute.get('AttributeName'))\n            else:\n                self.logger.info('attribute definitions is not using just strings')\n                return matches\n        keys = keys.union(\n            self._get_key_schema_attributes(\n                properties.get_safe('KeySchema', list_node([], None, None), [], list)\n            )\n        )\n        keys = keys.union(self._get_attribute_secondary(\n            properties.get_safe('GlobalSecondaryIndexes', list_node([], None, None), path, list\n                                )))  # pylint: disable=bad-continuation\n        keys = keys.union(self._get_attribute_secondary(\n            properties.get_safe('LocalSecondaryIndexes', list_node([], None, None), path, list\n                                )))  # pylint: disable=bad-continuation\n\n        if attributes != keys:\n            message = 'The set of Attributes in AttributeDefinitions: {0} and KeySchemas: {1} must match at {2}'\n            matches.append(RuleMatch(\n                path,\n                message.format(sorted(list(attributes)), sorted(list(keys)), '/'.join(map(str, path)))\n            ))\n\n        return matches\n\n    def check(self, properties, path, cfn):\n        \"\"\"Check itself\"\"\"\n        matches = []\n\n        property_sets = cfn.get_object_without_conditions(properties, path)\n        for property_set in property_sets:\n            matches.extend(self.check_property_set(property_set, path))\n        return matches\n\n    def match_resource_properties(self, properties, _, path, cfn):\n        \"\"\"Match for sub properties\"\"\"\n        matches = []\n        matches.extend(self.check(properties, path, cfn))\n        return matches\n", "path": "src/cfnlint/rules/resources/dynamodb/AttributeMismatch.py"}]}