prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  AWS::Logs::MetricFilter MetricValues permits invalid strings
  `cfn-lint 0.30.1`
  
  AWS::Logs::MetricFilter.Properties.MetricTransformations[*].MetricValue allows a bare string not starting with '$' which it appears is never actually valid, ie 
  "MetricValue: length" vs "MetricValue: $length"
  
  Assuming I'm reading the documentation correctly MetricValue must always either be a number OR start with a '$' character.
  
  The following fragment lints, but is rejected by CloudFormation at runtime without a $ at the start of the named MetricValue field
  ```
      QueueLengthMetricFilter:
          Type: AWS::Logs::MetricFilter
          Properties:
              LogGroupName: !Ref LogGroup
              FilterPattern: '[date, time, tag="rh-sched*", x01=throttling, x02="jobs.", ..., x10=Len, x11=of, x12=job, x13="queue*",  length]'
              MetricTransformations:
                - MetricValue: length
                  MetricNamespace: !Sub '${EnvironmentName}'
                  MetricName: 'JobsQueued'
  ```
  
  
  Note: I believe that this is also missed by the AWS ValidateTemplate API
  
  </issue>
  <code>
  [start of src/cfnlint/rules/resources/properties/AllowedPattern.py]
  1 """
  2 Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3 SPDX-License-Identifier: MIT-0
  4 """
  5 import re
  6 from cfnlint.rules import CloudFormationLintRule
  7 from cfnlint.rules import RuleMatch
  8 
  9 from cfnlint.helpers import RESOURCE_SPECS
  10 
  11 
  12 class AllowedPattern(CloudFormationLintRule):
  13     """Check if properties have a valid value"""
  14     id = 'E3031'
  15     shortdesc = 'Check if property values adhere to a specific pattern'
  16     description = 'Check if properties have a valid value in case of a pattern (Regular Expression)'
  17     source_url = 'https://github.com/awslabs/cfn-python-lint/blob/master/docs/cfn-resource-specification.md#allowedpattern'
  18     tags = ['resources', 'property', 'allowed pattern', 'regex']
  19 
  20     def initialize(self, cfn):
  21         """Initialize the rule"""
  22         for resource_type_spec in RESOURCE_SPECS.get(cfn.regions[0]).get('ResourceTypes'):
  23             self.resource_property_types.append(resource_type_spec)
  24         for property_type_spec in RESOURCE_SPECS.get(cfn.regions[0]).get('PropertyTypes'):
  25             self.resource_sub_property_types.append(property_type_spec)
  26 
  27     def check_value(self, value, path, property_name, **kwargs):
  28         """Check Value"""
  29         matches = []
  30 
  31         # Get the Allowed Pattern Regex
  32         value_pattern_regex = kwargs.get('value_specs', {}).get('AllowedPatternRegex', {})
  33         # Get the "Human Readable" version for the error message. Optional, if not specified,
  34         # the RegEx itself is used.
  35         value_pattern = kwargs.get('value_specs', {}).get('AllowedPattern', value_pattern_regex)
  36 
  37         if value_pattern_regex:
  38             regex = re.compile(value_pattern_regex)
  39 
  40             # Ignore values with dynamic references. Simple check to prevent false-positives
  41             # See: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html
  42             if '{{resolve:' not in value:
  43                 if not regex.match(value):
  44                     full_path = ('/'.join(str(x) for x in path))
  45 
  46                     message = '{} contains invalid characters (Pattern: {}) at {}'
  47                     matches.append(RuleMatch(path, message.format(
  48                         property_name, value_pattern, full_path)))
  49 
  50         return matches
  51 
  52     def check(self, cfn, properties, value_specs, property_specs, path):
  53         """Check itself"""
  54         matches = list()
  55         for p_value, p_path in properties.items_safe(path[:]):
  56             for prop in p_value:
  57                 if prop in value_specs:
  58                     value = value_specs.get(prop).get('Value', {})
  59                     if value:
  60                         value_type = value.get('ValueType', '')
  61                         property_type = property_specs.get('Properties').get(prop).get('Type')
  62                         matches.extend(
  63                             cfn.check_value(
  64                                 p_value, prop, p_path,
  65                                 check_value=self.check_value,
  66                                 value_specs=RESOURCE_SPECS.get(cfn.regions[0]).get(
  67                                     'ValueTypes').get(value_type, {}),
  68                                 cfn=cfn, property_type=property_type, property_name=prop
  69                             )
  70                         )
  71         return matches
  72 
  73     def match_resource_sub_properties(self, properties, property_type, path, cfn):
  74         """Match for sub properties"""
  75         matches = list()
  76 
  77         specs = RESOURCE_SPECS.get(cfn.regions[0]).get(
  78             'PropertyTypes').get(property_type, {}).get('Properties', {})
  79         property_specs = RESOURCE_SPECS.get(cfn.regions[0]).get('PropertyTypes').get(property_type)
  80         matches.extend(self.check(cfn, properties, specs, property_specs, path))
  81 
  82         return matches
  83 
  84     def match_resource_properties(self, properties, resource_type, path, cfn):
  85         """Check CloudFormation Properties"""
  86         matches = list()
  87 
  88         specs = RESOURCE_SPECS.get(cfn.regions[0]).get(
  89             'ResourceTypes').get(resource_type, {}).get('Properties', {})
  90         resource_specs = RESOURCE_SPECS.get(cfn.regions[0]).get('ResourceTypes').get(resource_type)
  91         matches.extend(self.check(cfn, properties, specs, resource_specs, path))
  92 
  93         return matches
  94
  [end of src/cfnlint/rules/resources/properties/AllowedPattern.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/properties/AllowedPattern.py b/src/cfnlint/rules/resources/properties/AllowedPattern.py
  --- a/src/cfnlint/rules/resources/properties/AllowedPattern.py
  +++ b/src/cfnlint/rules/resources/properties/AllowedPattern.py
  @@ -3,6 +3,7 @@
   SPDX-License-Identifier: MIT-0
   """
   import re
  +import six
   from cfnlint.rules import CloudFormationLintRule
   from cfnlint.rules import RuleMatch
   
  @@ -34,18 +35,22 @@
           # the RegEx itself is used.
           value_pattern = kwargs.get('value_specs', {}).get('AllowedPattern', value_pattern_regex)
   
  -        if value_pattern_regex:
  -            regex = re.compile(value_pattern_regex)
  +        if isinstance(value, (int, float)):
  +            value = str(value)
   
  -            # Ignore values with dynamic references. Simple check to prevent false-positives
  -            # See: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html
  -            if '{{resolve:' not in value:
  -                if not regex.match(value):
  -                    full_path = ('/'.join(str(x) for x in path))
  +        if isinstance(value, six.string_types):
  +            if value_pattern_regex:
  +                regex = re.compile(value_pattern_regex)
   
  -                    message = '{} contains invalid characters (Pattern: {}) at {}'
  -                    matches.append(RuleMatch(path, message.format(
  -                        property_name, value_pattern, full_path)))
  +                # Ignore values with dynamic references. Simple check to prevent false-positives
  +                # See: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html
  +                if '{{resolve:' not in value:
  +                    if not regex.match(value):
  +                        full_path = ('/'.join(str(x) for x in path))
  +
  +                        message = '{} contains invalid characters (Pattern: {}) at {}'
  +                        matches.append(RuleMatch(path, message.format(
  +                            property_name, value_pattern, full_path)))
   
           return matches
  
verification_info: {"golden_diff": "diff --git a/src/cfnlint/rules/resources/properties/AllowedPattern.py b/src/cfnlint/rules/resources/properties/AllowedPattern.py\n--- a/src/cfnlint/rules/resources/properties/AllowedPattern.py\n+++ b/src/cfnlint/rules/resources/properties/AllowedPattern.py\n@@ -3,6 +3,7 @@\n SPDX-License-Identifier: MIT-0\n \"\"\"\n import re\n+import six\n from cfnlint.rules import CloudFormationLintRule\n from cfnlint.rules import RuleMatch\n \n@@ -34,18 +35,22 @@\n         # the RegEx itself is used.\n         value_pattern = kwargs.get('value_specs', {}).get('AllowedPattern', value_pattern_regex)\n \n-        if value_pattern_regex:\n-            regex = re.compile(value_pattern_regex)\n+        if isinstance(value, (int, float)):\n+            value = str(value)\n \n-            # Ignore values with dynamic references. Simple check to prevent false-positives\n-            # See: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html\n-            if '{{resolve:' not in value:\n-                if not regex.match(value):\n-                    full_path = ('/'.join(str(x) for x in path))\n+        if isinstance(value, six.string_types):\n+            if value_pattern_regex:\n+                regex = re.compile(value_pattern_regex)\n \n-                    message = '{} contains invalid characters (Pattern: {}) at {}'\n-                    matches.append(RuleMatch(path, message.format(\n-                        property_name, value_pattern, full_path)))\n+                # Ignore values with dynamic references. Simple check to prevent false-positives\n+                # See: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html\n+                if '{{resolve:' not in value:\n+                    if not regex.match(value):\n+                        full_path = ('/'.join(str(x) for x in path))\n+\n+                        message = '{} contains invalid characters (Pattern: {}) at {}'\n+                        matches.append(RuleMatch(path, message.format(\n+                            property_name, value_pattern, full_path)))\n \n         return matches\n", "issue": "AWS::Logs::MetricFilter MetricValues permits invalid strings\n`cfn-lint 0.30.1`\r\n\r\nAWS::Logs::MetricFilter.Properties.MetricTransformations[*].MetricValue allows a bare string not starting with '$' which it appears is never actually valid, ie \r\n\"MetricValue: length\" vs \"MetricValue: $length\"\r\n\r\nAssuming I'm reading the documentation correctly MetricValue must always either be a number OR start with a '$' character.\r\n\r\nThe following fragment lints, but is rejected by CloudFormation at runtime without a $ at the start of the named MetricValue field\r\n```\r\n    QueueLengthMetricFilter:\r\n        Type: AWS::Logs::MetricFilter\r\n        Properties:\r\n            LogGroupName: !Ref LogGroup\r\n            FilterPattern: '[date, time, tag=\"rh-sched*\", x01=throttling, x02=\"jobs.\", ..., x10=Len, x11=of, x12=job, x13=\"queue*\",  length]'\r\n            MetricTransformations:\r\n              - MetricValue: length\r\n                MetricNamespace: !Sub '${EnvironmentName}'\r\n                MetricName: 'JobsQueued'\r\n```\r\n\r\n\r\nNote: I believe that this is also missed by the AWS ValidateTemplate API\n", "before_files": [{"content": "\"\"\"\nCopyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: MIT-0\n\"\"\"\nimport re\nfrom cfnlint.rules import CloudFormationLintRule\nfrom cfnlint.rules import RuleMatch\n\nfrom cfnlint.helpers import RESOURCE_SPECS\n\n\nclass AllowedPattern(CloudFormationLintRule):\n    \"\"\"Check if properties have a valid value\"\"\"\n    id = 'E3031'\n    shortdesc = 'Check if property values adhere to a specific pattern'\n    description = 'Check if properties have a valid value in case of a pattern (Regular Expression)'\n    source_url = 'https://github.com/awslabs/cfn-python-lint/blob/master/docs/cfn-resource-specification.md#allowedpattern'\n    tags = ['resources', 'property', 'allowed pattern', 'regex']\n\n    def initialize(self, cfn):\n        \"\"\"Initialize the rule\"\"\"\n        for resource_type_spec in RESOURCE_SPECS.get(cfn.regions[0]).get('ResourceTypes'):\n            self.resource_property_types.append(resource_type_spec)\n        for property_type_spec in RESOURCE_SPECS.get(cfn.regions[0]).get('PropertyTypes'):\n            self.resource_sub_property_types.append(property_type_spec)\n\n    def check_value(self, value, path, property_name, **kwargs):\n        \"\"\"Check Value\"\"\"\n        matches = []\n\n        # Get the Allowed Pattern Regex\n        value_pattern_regex = kwargs.get('value_specs', {}).get('AllowedPatternRegex', {})\n        # Get the \"Human Readable\" version for the error message. Optional, if not specified,\n        # the RegEx itself is used.\n        value_pattern = kwargs.get('value_specs', {}).get('AllowedPattern', value_pattern_regex)\n\n        if value_pattern_regex:\n            regex = re.compile(value_pattern_regex)\n\n            # Ignore values with dynamic references. Simple check to prevent false-positives\n            # See: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html\n            if '{{resolve:' not in value:\n                if not regex.match(value):\n                    full_path = ('/'.join(str(x) for x in path))\n\n                    message = '{} contains invalid characters (Pattern: {}) at {}'\n                    matches.append(RuleMatch(path, message.format(\n                        property_name, value_pattern, full_path)))\n\n        return matches\n\n    def check(self, cfn, properties, value_specs, property_specs, path):\n        \"\"\"Check itself\"\"\"\n        matches = list()\n        for p_value, p_path in properties.items_safe(path[:]):\n            for prop in p_value:\n                if prop in value_specs:\n                    value = value_specs.get(prop).get('Value', {})\n                    if value:\n                        value_type = value.get('ValueType', '')\n                        property_type = property_specs.get('Properties').get(prop).get('Type')\n                        matches.extend(\n                            cfn.check_value(\n                                p_value, prop, p_path,\n                                check_value=self.check_value,\n                                value_specs=RESOURCE_SPECS.get(cfn.regions[0]).get(\n                                    'ValueTypes').get(value_type, {}),\n                                cfn=cfn, property_type=property_type, property_name=prop\n                            )\n                        )\n        return matches\n\n    def match_resource_sub_properties(self, properties, property_type, path, cfn):\n        \"\"\"Match for sub properties\"\"\"\n        matches = list()\n\n        specs = RESOURCE_SPECS.get(cfn.regions[0]).get(\n            'PropertyTypes').get(property_type, {}).get('Properties', {})\n        property_specs = RESOURCE_SPECS.get(cfn.regions[0]).get('PropertyTypes').get(property_type)\n        matches.extend(self.check(cfn, properties, specs, property_specs, path))\n\n        return matches\n\n    def match_resource_properties(self, properties, resource_type, path, cfn):\n        \"\"\"Check CloudFormation Properties\"\"\"\n        matches = list()\n\n        specs = RESOURCE_SPECS.get(cfn.regions[0]).get(\n            'ResourceTypes').get(resource_type, {}).get('Properties', {})\n        resource_specs = RESOURCE_SPECS.get(cfn.regions[0]).get('ResourceTypes').get(resource_type)\n        matches.extend(self.check(cfn, properties, specs, resource_specs, path))\n\n        return matches\n", "path": "src/cfnlint/rules/resources/properties/AllowedPattern.py"}]}