prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  STS calls to use regional endpoints instead of global endpoint
  Change STS api calls to use regional STS endpoints to gain the benefits of "reduce latency, build in redundancy, and increase session token validity" as documented at https://docs.aws.amazon.com/general/latest/gr/rande.html#sts_region
  
  This will also enable leveraging a VPC Endpoint for STS, if provisioned.  
  
  </issue>
  <code>
  [start of c7n/credentials.py]
  1 # Copyright 2016-2017 Capital One Services, LLC
  2 #
  3 # Licensed under the Apache License, Version 2.0 (the "License");
  4 # you may not use this file except in compliance with the License.
  5 # You may obtain a copy of the License at
  6 #
  7 # http://www.apache.org/licenses/LICENSE-2.0
  8 #
  9 # Unless required by applicable law or agreed to in writing, software
  10 # distributed under the License is distributed on an "AS IS" BASIS,
  11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 # See the License for the specific language governing permissions and
  13 # limitations under the License.
  14 """
  15 Authentication utilities
  16 """
  17 from __future__ import absolute_import, division, print_function, unicode_literals
  18 
  19 import os
  20 
  21 from botocore.credentials import RefreshableCredentials
  22 from botocore.session import get_session
  23 from boto3 import Session
  24 
  25 from c7n.version import version
  26 from c7n.utils import get_retry
  27 
  28 
  29 class SessionFactory(object):
  30 
  31     def __init__(self, region, profile=None, assume_role=None, external_id=None):
  32         self.region = region
  33         self.profile = profile
  34         self.assume_role = assume_role
  35         self.external_id = external_id
  36         self.user_agent_name = "CloudCustodian"
  37         self.session_name = "CloudCustodian"
  38         if 'C7N_SESSION_SUFFIX' in os.environ:
  39             self.session_name = "%s@%s" % (
  40                 self.session_name, os.environ['C7N_SESSION_SUFFIX'])
  41         self._subscribers = []
  42 
  43     def _set_policy_name(self, name):
  44         self.user_agent_name = ("CloudCustodian(%s)" % name).strip()
  45 
  46     policy_name = property(None, _set_policy_name)
  47 
  48     def __call__(self, assume=True, region=None):
  49         if self.assume_role and assume:
  50             session = Session(profile_name=self.profile)
  51             session = assumed_session(
  52                 self.assume_role, self.session_name, session,
  53                 region or self.region, self.external_id)
  54         else:
  55             session = Session(
  56                 region_name=region or self.region, profile_name=self.profile)
  57 
  58         return self.update(session)
  59 
  60     def update(self, session):
  61         session._session.user_agent_name = self.user_agent_name
  62         session._session.user_agent_version = version
  63 
  64         for s in self._subscribers:
  65             s(session)
  66 
  67         return session
  68 
  69     def set_subscribers(self, subscribers):
  70         self._subscribers = subscribers
  71 
  72 
  73 def assumed_session(role_arn, session_name, session=None, region=None, external_id=None):
  74     """STS Role assume a boto3.Session
  75 
  76     With automatic credential renewal.
  77 
  78     Args:
  79       role_arn: iam role arn to assume
  80       session_name: client session identifier
  81       session: an optional extant session, note session is captured
  82       in a function closure for renewing the sts assumed role.
  83 
  84     :return: a boto3 session using the sts assumed role credentials
  85 
  86     Notes: We have to poke at botocore internals a few times
  87     """
  88     if session is None:
  89         session = Session()
  90 
  91     retry = get_retry(('Throttling',))
  92 
  93     def refresh():
  94 
  95         parameters = {"RoleArn": role_arn, "RoleSessionName": session_name}
  96 
  97         if external_id is not None:
  98             parameters['ExternalId'] = external_id
  99 
  100         credentials = retry(
  101             session.client('sts').assume_role, **parameters)['Credentials']
  102         return dict(
  103             access_key=credentials['AccessKeyId'],
  104             secret_key=credentials['SecretAccessKey'],
  105             token=credentials['SessionToken'],
  106             # Silly that we basically stringify so it can be parsed again
  107             expiry_time=credentials['Expiration'].isoformat())
  108 
  109     session_credentials = RefreshableCredentials.create_from_metadata(
  110         metadata=refresh(),
  111         refresh_using=refresh,
  112         method='sts-assume-role')
  113 
  114     # so dirty.. it hurts, no clean way to set this outside of the
  115     # internals poke. There's some work upstream on making this nicer
  116     # but its pretty baroque as well with upstream support.
  117     # https://github.com/boto/boto3/issues/443
  118     # https://github.com/boto/botocore/issues/761
  119 
  120     s = get_session()
  121     s._credentials = session_credentials
  122     if region is None:
  123         region = s.get_config_variable('region') or 'us-east-1'
  124     s.set_config_variable('region', region)
  125     return Session(botocore_session=s)
  126
  [end of c7n/credentials.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/c7n/credentials.py b/c7n/credentials.py
  --- a/c7n/credentials.py
  +++ b/c7n/credentials.py
  @@ -26,6 +26,10 @@
   from c7n.utils import get_retry
   
   
  +# 0.8.45.1 compatibility with global only sts endpoints, out of caution, remove in 0.8.46.1
  +USE_STS_GLOBAL = os.environ.get('C7N_USE_STS_GLOBAL', '').lower() in ('yes', 'true')
  +
  +
   class SessionFactory(object):
   
       def __init__(self, region, profile=None, assume_role=None, external_id=None):
  @@ -98,7 +102,8 @@
               parameters['ExternalId'] = external_id
   
           credentials = retry(
  -            session.client('sts').assume_role, **parameters)['Credentials']
  +            get_sts_client(
  +                session, region).assume_role, **parameters)['Credentials']
           return dict(
               access_key=credentials['AccessKeyId'],
               secret_key=credentials['SecretAccessKey'],
  @@ -123,3 +128,20 @@
           region = s.get_config_variable('region') or 'us-east-1'
       s.set_config_variable('region', region)
       return Session(botocore_session=s)
  +
  +
  +def get_sts_client(session, region):
  +    """Get the AWS STS endpoint specific for the given region.
  +
  +    Returns the global endpoint if region is not specified.
  +
  +    For the list of regional endpoints, see https://amzn.to/2ohJgtR
  +    """
  +    if region and not USE_STS_GLOBAL:
  +        endpoint_url = "https://sts.{}.amazonaws.com".format(region)
  +        region_name = region
  +    else:
  +        endpoint_url = "https://sts.amazonaws.com"
  +        region_name = None
  +    return session.client(
  +        'sts', endpoint_url=endpoint_url, region_name=region_name)
  
verification_info: {"golden_diff": "diff --git a/c7n/credentials.py b/c7n/credentials.py\n--- a/c7n/credentials.py\n+++ b/c7n/credentials.py\n@@ -26,6 +26,10 @@\n from c7n.utils import get_retry\n \n \n+# 0.8.45.1 compatibility with global only sts endpoints, out of caution, remove in 0.8.46.1\n+USE_STS_GLOBAL = os.environ.get('C7N_USE_STS_GLOBAL', '').lower() in ('yes', 'true')\n+\n+\n class SessionFactory(object):\n \n     def __init__(self, region, profile=None, assume_role=None, external_id=None):\n@@ -98,7 +102,8 @@\n             parameters['ExternalId'] = external_id\n \n         credentials = retry(\n-            session.client('sts').assume_role, **parameters)['Credentials']\n+            get_sts_client(\n+                session, region).assume_role, **parameters)['Credentials']\n         return dict(\n             access_key=credentials['AccessKeyId'],\n             secret_key=credentials['SecretAccessKey'],\n@@ -123,3 +128,20 @@\n         region = s.get_config_variable('region') or 'us-east-1'\n     s.set_config_variable('region', region)\n     return Session(botocore_session=s)\n+\n+\n+def get_sts_client(session, region):\n+    \"\"\"Get the AWS STS endpoint specific for the given region.\n+\n+    Returns the global endpoint if region is not specified.\n+\n+    For the list of regional endpoints, see https://amzn.to/2ohJgtR\n+    \"\"\"\n+    if region and not USE_STS_GLOBAL:\n+        endpoint_url = \"https://sts.{}.amazonaws.com\".format(region)\n+        region_name = region\n+    else:\n+        endpoint_url = \"https://sts.amazonaws.com\"\n+        region_name = None\n+    return session.client(\n+        'sts', endpoint_url=endpoint_url, region_name=region_name)\n", "issue": "STS calls to use regional endpoints instead of global endpoint\nChange STS api calls to use regional STS endpoints to gain the benefits of \"reduce latency, build in redundancy, and increase session token validity\" as documented at https://docs.aws.amazon.com/general/latest/gr/rande.html#sts_region\r\n\r\nThis will also enable leveraging a VPC Endpoint for STS, if provisioned.  \n", "before_files": [{"content": "# Copyright 2016-2017 Capital One Services, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"\nAuthentication utilities\n\"\"\"\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport os\n\nfrom botocore.credentials import RefreshableCredentials\nfrom botocore.session import get_session\nfrom boto3 import Session\n\nfrom c7n.version import version\nfrom c7n.utils import get_retry\n\n\nclass SessionFactory(object):\n\n    def __init__(self, region, profile=None, assume_role=None, external_id=None):\n        self.region = region\n        self.profile = profile\n        self.assume_role = assume_role\n        self.external_id = external_id\n        self.user_agent_name = \"CloudCustodian\"\n        self.session_name = \"CloudCustodian\"\n        if 'C7N_SESSION_SUFFIX' in os.environ:\n            self.session_name = \"%s@%s\" % (\n                self.session_name, os.environ['C7N_SESSION_SUFFIX'])\n        self._subscribers = []\n\n    def _set_policy_name(self, name):\n        self.user_agent_name = (\"CloudCustodian(%s)\" % name).strip()\n\n    policy_name = property(None, _set_policy_name)\n\n    def __call__(self, assume=True, region=None):\n        if self.assume_role and assume:\n            session = Session(profile_name=self.profile)\n            session = assumed_session(\n                self.assume_role, self.session_name, session,\n                region or self.region, self.external_id)\n        else:\n            session = Session(\n                region_name=region or self.region, profile_name=self.profile)\n\n        return self.update(session)\n\n    def update(self, session):\n        session._session.user_agent_name = self.user_agent_name\n        session._session.user_agent_version = version\n\n        for s in self._subscribers:\n            s(session)\n\n        return session\n\n    def set_subscribers(self, subscribers):\n        self._subscribers = subscribers\n\n\ndef assumed_session(role_arn, session_name, session=None, region=None, external_id=None):\n    \"\"\"STS Role assume a boto3.Session\n\n    With automatic credential renewal.\n\n    Args:\n      role_arn: iam role arn to assume\n      session_name: client session identifier\n      session: an optional extant session, note session is captured\n      in a function closure for renewing the sts assumed role.\n\n    :return: a boto3 session using the sts assumed role credentials\n\n    Notes: We have to poke at botocore internals a few times\n    \"\"\"\n    if session is None:\n        session = Session()\n\n    retry = get_retry(('Throttling',))\n\n    def refresh():\n\n        parameters = {\"RoleArn\": role_arn, \"RoleSessionName\": session_name}\n\n        if external_id is not None:\n            parameters['ExternalId'] = external_id\n\n        credentials = retry(\n            session.client('sts').assume_role, **parameters)['Credentials']\n        return dict(\n            access_key=credentials['AccessKeyId'],\n            secret_key=credentials['SecretAccessKey'],\n            token=credentials['SessionToken'],\n            # Silly that we basically stringify so it can be parsed again\n            expiry_time=credentials['Expiration'].isoformat())\n\n    session_credentials = RefreshableCredentials.create_from_metadata(\n        metadata=refresh(),\n        refresh_using=refresh,\n        method='sts-assume-role')\n\n    # so dirty.. it hurts, no clean way to set this outside of the\n    # internals poke. There's some work upstream on making this nicer\n    # but its pretty baroque as well with upstream support.\n    # https://github.com/boto/boto3/issues/443\n    # https://github.com/boto/botocore/issues/761\n\n    s = get_session()\n    s._credentials = session_credentials\n    if region is None:\n        region = s.get_config_variable('region') or 'us-east-1'\n    s.set_config_variable('region', region)\n    return Session(botocore_session=s)\n", "path": "c7n/credentials.py"}]}