Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-social-auth-core for
openSUSE:Factory checked in at 2023-12-01 21:26:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-social-auth-core (Old)
and /work/SRC/openSUSE:Factory/.python-social-auth-core.new.25432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-social-auth-core"
Fri Dec 1 21:26:54 2023 rev:22 rq:1130256 version:4.5.1
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-social-auth-core/python-social-auth-core.changes
2023-11-14 21:42:31.079477034 +0100
+++
/work/SRC/openSUSE:Factory/.python-social-auth-core.new.25432/python-social-auth-core.changes
2023-12-01 21:27:22.262292267 +0100
@@ -1,0 +2,11 @@
+Fri Dec 1 09:59:25 UTC 2023 - David Anes <[email protected]>
+
+- Update to 4.5.1
+ - OpenID Connect skips at_hash validation when missing
+ - redirect_name is now passed to backend on do_complete
+ - next is preserved through SAML RelayState
+ - Add Discogs backend
+ - Add BitbucketDataCenterOAuth2 backend
+ - Keycloak's ID_KEY is no longer configurable (it never worked)
+
+-------------------------------------------------------------------
Old:
----
social-core-4.5.0.tar.gz
New:
----
social-core-4.5.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-social-auth-core.spec ++++++
--- /var/tmp/diff_new_pack.5Y0akc/_old 2023-12-01 21:27:22.810312435 +0100
+++ /var/tmp/diff_new_pack.5Y0akc/_new 2023-12-01 21:27:22.810312435 +0100
@@ -23,7 +23,7 @@
%bcond_with saml
Name: python-social-auth-core
-Version: 4.5.0
+Version: 4.5.1
Release: 0
Summary: Python Social Auth Core
License: BSD-3-Clause
++++++ social-core-4.5.0.tar.gz -> social-core-4.5.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/social-core-4.5.0/.github/ISSUE_TEMPLATE.md
new/social-core-4.5.1/.github/ISSUE_TEMPLATE.md
--- old/social-core-4.5.0/.github/ISSUE_TEMPLATE.md 2023-10-31
13:44:09.000000000 +0100
+++ new/social-core-4.5.1/.github/ISSUE_TEMPLATE.md 1970-01-01
01:00:00.000000000 +0100
@@ -1,30 +0,0 @@
-### Expected behaviour
-
-Describe what should happen.
-
-### Actual behaviour
-
-Describe what happens instead and why is it an issue.
-
-### What are the steps to reproduce this issue?
-
-Input clear steps to reproduce the issue for a maintainer.
-
-1. ...
-2. ...
-3. ...
-
-### Any logs, error output, etc?
-
-Add any code, log or error output that you see fit for this issue, wrap any
code
-and / or console output with the proper code blocks.
-
-### Any other comments?
-
-Expand the issue with any details you find appropriate to solve or reproduce
it.
-
-<!--
- Issue template based on the following templates:
- *
https://raw.githubusercontent.com/theos/theos/master/.github/ISSUE_TEMPLATE.md
- *
https://raw.githubusercontent.com/EddyVerbruggen/Toast-PhoneGap-Plugin/master/issue_template.md
--->
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/social-core-4.5.0/.github/PULL_REQUEST_TEMPLATE.md
new/social-core-4.5.1/.github/PULL_REQUEST_TEMPLATE.md
--- old/social-core-4.5.0/.github/PULL_REQUEST_TEMPLATE.md 2023-10-31
13:44:09.000000000 +0100
+++ new/social-core-4.5.1/.github/PULL_REQUEST_TEMPLATE.md 1970-01-01
01:00:00.000000000 +0100
@@ -1,39 +0,0 @@
-## Proposed changes
-
-Describe the big picture of your changes here to communicate to the maintainers
-why we should accept this pull request. If it fixes a bug or resolves a feature
-request, be sure to link to that issue.
-
-## Types of changes
-
-Please check the type of change your PR introduces:
-
-- [ ] Release (new release request)
-- [ ] Bugfix (non-breaking change which fixes an issue)
-- [ ] New feature (non-breaking change which adds functionality)
-- [ ] Code style update (PEP8, lint, formatting, renaming, etc)
-- [ ] Refactoring (no functional changes, no api changes)
-- [ ] Breaking change (fix or feature that would cause existing functionality
to not work as expected)
-- [ ] Build related changes (build process, tests runner, etc)
-- [ ] Other (please describe):
-
-## Checklist
-
-_Put an `x` in the boxes that apply. You can also fill these out after creating
-the PR. If you're unsure about any of them, don't hesitate to ask. We're here
to
-help! This is simply a reminder of what we are going to look for before merging
-your code._
-
-- [ ] Lint and unit tests pass locally with my changes
-- [ ] I have added tests that prove my fix is effective or that my feature
works
-
-## Other information
-
-Any other information that is important to this PR such as screenshots of how
-the component looks before and after the change.
-
-<!--
- Pull request template based on the following templates:
- *
https://raw.githubusercontent.com/ionic-team/ionic/master/.github/PULL_REQUEST_TEMPLATE.md
- *
https://raw.githubusercontent.com/appium/appium/master/.github/PULL_REQUEST_TEMPLATE.md
--->
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/social-core-4.5.0/.pre-commit-config.yaml
new/social-core-4.5.1/.pre-commit-config.yaml
--- old/social-core-4.5.0/.pre-commit-config.yaml 2023-10-31
13:44:09.000000000 +0100
+++ new/social-core-4.5.1/.pre-commit-config.yaml 2023-11-29
09:52:23.000000000 +0100
@@ -20,7 +20,7 @@
- id: pyupgrade
args: [--py38-plus]
- repo: https://github.com/psf/black
- rev: 23.10.1
+ rev: 23.11.0
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/social-core-4.5.0/CHANGELOG.md
new/social-core-4.5.1/CHANGELOG.md
--- old/social-core-4.5.0/CHANGELOG.md 2023-10-31 13:44:09.000000000 +0100
+++ new/social-core-4.5.1/CHANGELOG.md 2023-11-29 09:52:23.000000000 +0100
@@ -5,6 +5,16 @@
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+##
[4.5.1](https://github.com/python-social-auth/social-core/releases/tag/4.5.1) -
2023-11-29
+
+### Changed
+- OpenID Connect skips `at_hash` validation when missing
+- `redirect_name` is now passed to backend on `do_complete`
+- `next` is preserved through SAML RelayState
+- Add Discogs backend
+- Add BitbucketDataCenterOAuth2 backend
+- Keycloak's `ID_KEY` is no longer configurable (it never worked)
+
##
[4.5.0](https://github.com/python-social-auth/social-core/releases/tag/4.5.0) -
2023-10-31
### Changed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/social-core-4.5.0/social_core/__init__.py
new/social-core-4.5.1/social_core/__init__.py
--- old/social-core-4.5.0/social_core/__init__.py 2023-10-31
13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/__init__.py 2023-11-29
09:52:23.000000000 +0100
@@ -1 +1 @@
-__version__ = "4.5.0"
+__version__ = "4.5.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/social-core-4.5.0/social_core/actions.py
new/social-core-4.5.1/social_core/actions.py
--- old/social-core-4.5.0/social_core/actions.py 2023-10-31
13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/actions.py 2023-11-29
09:52:23.000000000 +0100
@@ -46,7 +46,7 @@
# clean partial data after usage
backend.strategy.clean_partial_pipeline(partial.token)
else:
- user = backend.complete(user=user, *args, **kwargs)
+ user = backend.complete(user=user, redirect_name=redirect_name, *args,
**kwargs)
# pop redirect value before the session is trashed on login(), but after
# the pipeline so that the pipeline can change the redirect if needed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/backends/bitbucket_datacenter.py
new/social-core-4.5.1/social_core/backends/bitbucket_datacenter.py
--- old/social-core-4.5.0/social_core/backends/bitbucket_datacenter.py
1970-01-01 01:00:00.000000000 +0100
+++ new/social-core-4.5.1/social_core/backends/bitbucket_datacenter.py
2023-11-29 09:52:23.000000000 +0100
@@ -0,0 +1,107 @@
+"""
+Bitbucket Data Center OAuth2 backend, docs at:
+
https://python-social-auth.readthedocs.io/en/latest/backends/bitbucket_datacenter_oauth2.html
+
https://confluence.atlassian.com/bitbucketserver/bitbucket-oauth-2-0-provider-api-1108483661.html
+"""
+
+from .oauth import BaseOAuth2PKCE
+
+
+class BitbucketDataCenterOAuth2(BaseOAuth2PKCE):
+ """
+ Implements client for Bitbucket Data Center OAuth 2.0 provider API.
+ ref:
https://confluence.atlassian.com/bitbucketserver/bitbucket-oauth-2-0-provider-api-1108483661.html
+ """
+
+ name = "bitbucket-datacenter-oauth2"
+ ID_KEY = "id"
+ SCOPE_SEPARATOR = " "
+ ACCESS_TOKEN_METHOD = "POST"
+ REFRESH_TOKEN_METHOD = "POST"
+ REDIRECT_STATE = False
+ STATE_PARAMETER = True
+ # ref:
https://confluence.atlassian.com/bitbucketserver/bitbucket-oauth-2-0-provider-api-1108483661.html#BitbucketOAuth2.0providerAPI-scopes
# noqa
+ DEFAULT_SCOPE = ["PUBLIC_REPOS"]
+ USE_BASIC_AUTH = False
+ EXTRA_DATA = [
+ ("token_type", "token_type"),
+ ("access_token", "access_token"),
+ ("refresh_token", "refresh_token"),
+ ("expires_in", "expires"),
+ ("scope", "scope"),
+ # extra user profile fields
+ ("first_name", "first_name"),
+ ("last_name", "last_name"),
+ ("email", "email"),
+ ("name", "name"),
+ ("username", "username"),
+ ("display_name", "display_name"),
+ ("type", "type"),
+ ("active", "active"),
+ ("url", "url"),
+ ("avatar_url", "avatar_url"),
+ ]
+ PKCE_DEFAULT_CODE_CHALLENGE_METHOD = "s256" # can be "plain" or "s256"
+ PKCE_DEFAULT_CODE_VERIFIER_LENGTH = 48 # must be b/w 43-127 chars
+ DEFAULT_USE_PKCE = True
+ DEFAULT_USER_AVATAR_SIZE = 48
+
+ @property
+ def server_base_oauth2_api_url(self) -> str:
+ base_url = self.setting("URL")
+ return f"{base_url}/rest/oauth2/latest"
+
+ @property
+ def server_base_rest_api_url(self) -> str:
+ base_url = self.setting("URL")
+ return f"{base_url}/rest/api/latest"
+
+ def authorization_url(self) -> str:
+ return f"{self.server_base_oauth2_api_url}/authorize"
+
+ def access_token_url(self) -> str:
+ return f"{self.server_base_oauth2_api_url}/token"
+
+ def get_user_details(self, response) -> dict:
+ """Return user details for the Bitbucket Data Center account"""
+ # `response` here is the return value of `user_data` method
+ user_data = response
+ _, first_name, last_name =
self.get_user_names(user_data["displayName"])
+ uid = self.get_user_id(details=None, response=response)
+ return {
+ "uid": uid,
+ "first_name": first_name,
+ "last_name": last_name,
+ "email": user_data["emailAddress"],
+ "name": user_data["name"],
+ "username": user_data["slug"],
+ "display_name": user_data["displayName"],
+ "type": user_data["type"],
+ "active": user_data["active"],
+ "url": user_data["links"]["self"][0]["href"],
+ "avatar_url": user_data["avatarUrl"],
+ }
+
+ def user_data(self, access_token, *args, **kwargs) -> dict:
+ """Fetch user data from Bitbucket Data Center REST API"""
+ # At this point, we don't know the current user's username
+ # and Bitbucket doesn't provide any API to do so.
+ # However, the current user's username is sent in every response
header.
+ # ref:
https://community.developer.atlassian.com/t/obtain-authorised-users-username-from-api/24422/2
# noqa
+ headers = {"Authorization": f"Bearer {access_token}"}
+ response = self.request(
+ url=f"{self.server_base_rest_api_url}/application-properties",
+ method="GET",
+ headers=headers,
+ )
+ # ref:
https://developer.atlassian.com/server/bitbucket/rest/v815/api-group-system-maintenance/#api-api-latest-users-userslug-get
# noqa
+ username = response.headers["x-ausername"]
+ return self.get_json(
+ url=f"{self.server_base_rest_api_url}/users/{username}",
+ headers=headers,
+ params={
+ "avatarSize": self.setting(
+ "USER_AVATAR_SIZE", default=self.DEFAULT_USER_AVATAR_SIZE
+ ) # to force `avatarUrl` in response
+ },
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/social-core-4.5.0/social_core/backends/discogs.py
new/social-core-4.5.1/social_core/backends/discogs.py
--- old/social-core-4.5.0/social_core/backends/discogs.py 1970-01-01
01:00:00.000000000 +0100
+++ new/social-core-4.5.1/social_core/backends/discogs.py 2023-11-29
09:52:23.000000000 +0100
@@ -0,0 +1,37 @@
+"""
+Discogs OAuth1 backend, docs at:
+ https://www.discogs.com/developers/
+"""
+
+from social_core.backends.oauth import BaseOAuth1
+
+
+class DiscogsOAuth1(BaseOAuth1):
+ """
+ Implements the OAuth1 authentication mechanism for https://www.discogs.com
+ """
+
+ name = "discogs"
+
+ OAUTH_TOKEN_PARAMETER_NAME = "oauth_token"
+
+ AUTHORIZATION_URL = "https://www.discogs.com/oauth/authorize"
+ REQUEST_TOKEN_URL = "https://api.discogs.com/oauth/request_token"
+ ACCESS_TOKEN_URL = "https://api.discogs.com/oauth/access_token"
+
+ def get_user_details(self, user_data):
+ return {
+ "username": user_data["username"],
+ "id": user_data["id"],
+ "profile": user_data["profile"],
+ "name": user_data["name"],
+ }
+
+ def user_data(self, access_token, *args, **kwargs):
+ identity = self.get_json(
+ "https://api.discogs.com/oauth/identity",
auth=self.oauth_auth(access_token)
+ )
+
+ return self.get_json(
+ identity["resource_url"], auth=self.oauth_auth(access_token)
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/social-core-4.5.0/social_core/backends/keycloak.py
new/social-core-4.5.1/social_core/backends/keycloak.py
--- old/social-core-4.5.0/social_core/backends/keycloak.py 2023-10-31
13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/backends/keycloak.py 2023-11-29
09:52:23.000000000 +0100
@@ -96,6 +96,7 @@
"""
name = "keycloak"
+ ID_KEY = "username"
ACCESS_TOKEN_METHOD = "POST"
REDIRECT_STATE = False
@@ -120,9 +121,6 @@
]
)
- def id_key(self):
- return self.setting("ID_KEY", default="username")
-
def user_data(
self, access_token, *args, **kwargs
): # pylint: disable=unused-argument
@@ -151,11 +149,5 @@
}
def get_user_id(self, details, response):
- """Get and associate Django User by the field indicated by ID_KEY
-
- The ID_KEY can be any field in the user details or the access token.
- """
- id_key = self.id_key()
- if id_key in details:
- return details[id_key]
- return response.get(id_key)
+ """Get and associate Django User by the field indicated by ID_KEY"""
+ return details.get(self.ID_KEY)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/social-core-4.5.0/social_core/backends/oauth.py
new/social-core-4.5.1/social_core/backends/oauth.py
--- old/social-core-4.5.0/social_core/backends/oauth.py 2023-10-31
13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/backends/oauth.py 2023-11-29
09:52:23.000000000 +0100
@@ -1,3 +1,5 @@
+import base64
+import hashlib
from urllib.parse import unquote, urlencode
from oauthlib.oauth1 import SIGNATURE_TYPE_AUTH_HEADER
@@ -5,6 +7,7 @@
from ..exceptions import (
AuthCanceled,
+ AuthException,
AuthFailed,
AuthMissingParameter,
AuthStateForbidden,
@@ -459,3 +462,68 @@
def refresh_token_url(self):
return self.REFRESH_TOKEN_URL or self.access_token_url()
+
+
+class BaseOAuth2PKCE(BaseOAuth2):
+ """
+ Base class for providers using OAuth2 with Proof Key for Code Exchange
(PKCE).
+
+ OAuth2 details at:
+ https://datatracker.ietf.org/doc/html/rfc6749
+ PKCE details at:
+ https://datatracker.ietf.org/doc/html/rfc7636
+ """
+
+ PKCE_DEFAULT_CODE_CHALLENGE_METHOD = "s256"
+ PKCE_DEFAULT_CODE_VERIFIER_LENGTH = 32
+ DEFAULT_USE_PKCE = True
+
+ def create_code_verifier(self):
+ name = f"{self.name}_code_verifier"
+ code_verifier_len = self.setting(
+ "PKCE_CODE_VERIFIER_LENGTH",
default=self.PKCE_DEFAULT_CODE_VERIFIER_LENGTH
+ )
+ code_verifier = self.strategy.random_string(code_verifier_len)
+ self.strategy.session_set(name, code_verifier)
+ return code_verifier
+
+ def get_code_verifier(self):
+ name = f"{self.name}_code_verifier"
+ code_verifier = self.strategy.session_get(name)
+ return code_verifier
+
+ def generate_code_challenge(self, code_verifier, challenge_method):
+ method = challenge_method.lower()
+ if method == "s256":
+ hashed = hashlib.sha256(code_verifier.encode()).digest()
+ encoded = base64.urlsafe_b64encode(hashed)
+ code_challenge = encoded.decode().replace("=", "") # remove
padding
+ return code_challenge
+ if method == "plain":
+ return code_verifier
+ raise AuthException("Unsupported code challenge method.")
+
+ def auth_params(self, state=None):
+ params = super().auth_params(state=state)
+
+ if self.setting("USE_PKCE", default=self.DEFAULT_USE_PKCE):
+ code_challenge_method = self.setting(
+ "PKCE_CODE_CHALLENGE_METHOD",
+ default=self.PKCE_DEFAULT_CODE_CHALLENGE_METHOD,
+ )
+ code_verifier = self.create_code_verifier()
+ code_challenge = self.generate_code_challenge(
+ code_verifier, code_challenge_method
+ )
+ params["code_challenge_method"] = code_challenge_method
+ params["code_challenge"] = code_challenge
+ return params
+
+ def auth_complete_params(self, state=None):
+ params = super().auth_complete_params(state=state)
+
+ if self.setting("USE_PKCE", default=self.DEFAULT_USE_PKCE):
+ code_verifier = self.get_code_verifier()
+ params["code_verifier"] = code_verifier
+
+ return params
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/backends/open_id_connect.py
new/social-core-4.5.1/social_core/backends/open_id_connect.py
--- old/social-core-4.5.0/social_core/backends/open_id_connect.py
2023-10-31 13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/backends/open_id_connect.py
2023-11-29 09:52:23.000000000 +0100
@@ -236,7 +236,9 @@
# pyjwt does not validate OIDC claims
# see https://github.com/jpadilla/pyjwt/pull/296
- if claims.get("at_hash") != self.calc_at_hash(access_token,
key["alg"]):
+ if "at_hash" in claims and claims["at_hash"] != self.calc_at_hash(
+ access_token, key["alg"]
+ ):
raise AuthTokenError(self, "Invalid access token")
self.validate_claims(claims)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/social-core-4.5.0/social_core/backends/saml.py
new/social-core-4.5.1/social_core/backends/saml.py
--- old/social-core-4.5.0/social_core/backends/saml.py 2023-10-31
13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/backends/saml.py 2023-11-29
09:52:23.000000000 +0100
@@ -7,6 +7,8 @@
"Identity Provider" (IdP): The third-party site that is authenticating
users via SAML
"""
+import json
+
from onelogin.saml2.auth import OneLogin_Saml2_Auth
from onelogin.saml2.settings import OneLogin_Saml2_Settings
@@ -278,8 +280,12 @@
# Below, return_to sets the RelayState, which can contain
# arbitrary data. We use it to store the specific SAML IdP
# name, since we multiple IdPs share the same auth_complete
- # URL.
- return auth.login(return_to=idp_name)
+ # URL, and the URL to redirect to after auth completes.
+ relay_state = {
+ "idp": idp_name,
+ "next": self.data.get("next"),
+ }
+ return auth.login(return_to=json.dumps(relay_state))
def get_user_details(self, response):
"""Get user details like full name, email, etc. from the
@@ -303,10 +309,26 @@
now log them in, if everything checks out.
"""
try:
- idp_name = self.strategy.request_data()["RelayState"]
+ relay_state_str = self.strategy.request_data()["RelayState"]
except KeyError:
raise AuthMissingParameter(self, "RelayState")
+ try:
+ relay_state = json.loads(relay_state_str)
+ if not isinstance(relay_state, dict) or "idp" not in relay_state:
+ raise ValueError(
+ "RelayState is expected to contain a JSON object with an
'idp' key"
+ )
+ except ValueError:
+ # Assume RelayState is just the idp_name, as it used to be in
previous versions of this code.
+ # This ensures compatibility with previous versions.
+ idp_name = relay_state_str
+ else:
+ idp_name = relay_state["idp"]
+ if next_url := relay_state.get("next"):
+ # The do_complete action expects the "next" URL to be in
session state or the request params.
+ self.strategy.session_set(kwargs.get("redirect_name", "next"),
next_url)
+
idp = self.get_idp(idp_name)
auth = self._create_saml_auth(idp)
auth.process_response()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/backends/twitter_oauth2.py
new/social-core-4.5.1/social_core/backends/twitter_oauth2.py
--- old/social-core-4.5.0/social_core/backends/twitter_oauth2.py
2023-10-31 13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/backends/twitter_oauth2.py
2023-11-29 09:52:23.000000000 +0100
@@ -3,14 +3,10 @@
https://python-social-auth.readthedocs.io/en/latest/backends/twitter-oauth2.html
https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code
"""
-import base64
-import hashlib
+from .oauth import BaseOAuth2PKCE
-from ..exceptions import AuthException
-from .oauth import BaseOAuth2
-
-class TwitterOAuth2(BaseOAuth2):
+class TwitterOAuth2(BaseOAuth2PKCE):
"""Twitter OAuth2 authentication backend"""
name = "twitter-oauth2"
@@ -40,7 +36,8 @@
("public_metrics", "public_metrics"),
]
PKCE_DEFAULT_CODE_CHALLENGE_METHOD = "s256"
- USE_PKCE = True
+ PKCE_DEFAULT_CODE_VERIFIER_LENGTH = 32
+ DEFAULT_USE_PKCE = True
def get_user_details(self, response):
"""Return user details from Twitter account"""
@@ -104,50 +101,3 @@
headers={"Authorization": "Bearer %s" % access_token},
)
return response["data"]
-
- def create_code_verifier(self):
- name = self.name + "_code_verifier"
- code_verifier = self.strategy.random_string(32)
- self.strategy.session_set(name, code_verifier)
- return code_verifier
-
- def get_code_verifier(self):
- name = self.name + "_code_verifier"
- code_verifier = self.strategy.session_get(name)
- return code_verifier
-
- def generate_code_challenge(self, code_verifier, challenge_method):
- method = challenge_method.lower()
- if method == "s256":
- hashed = hashlib.sha256(code_verifier.encode()).digest()
- encoded = base64.urlsafe_b64encode(hashed)
- code_challenge = encoded.decode().replace("=", "") # remove
padding
- return code_challenge
- elif method == "plain":
- return code_verifier
- else:
- raise AuthException("Unsupported code challenge method.")
-
- def auth_params(self, state=None):
- params = super().auth_params(state=state)
-
- if self.USE_PKCE:
- code_challenge_method = self.setting("PKCE_CODE_CHALLENGE_METHOD")
- if not code_challenge_method:
- code_challenge_method = self.PKCE_DEFAULT_CODE_CHALLENGE_METHOD
- code_verifier = self.create_code_verifier()
- code_challenge = self.generate_code_challenge(
- code_verifier, code_challenge_method
- )
- params["code_challenge_method"] = code_challenge_method
- params["code_challenge"] = code_challenge
- return params
-
- def auth_complete_params(self, state=None):
- params = super().auth_complete_params(state=state)
-
- if self.USE_PKCE:
- code_verifier = self.get_code_verifier()
- params["code_verifier"] = code_verifier
-
- return params
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/actions/actions.py
new/social-core-4.5.1/social_core/tests/actions/actions.py
--- old/social-core-4.5.0/social_core/tests/actions/actions.py 2023-10-31
13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/tests/actions/actions.py 2023-11-29
09:52:23.000000000 +0100
@@ -53,6 +53,7 @@
def __init__(self, *args, **kwargs):
self.strategy = None
+ self.backend = None
super().__init__(*args, **kwargs)
def setUp(self):
@@ -63,7 +64,9 @@
TestAssociation.reset_cache()
Backend = module_member("social_core.backends.github.GithubOAuth2")
self.strategy = self.strategy or TestStrategy(TestStorage)
- self.backend = Backend(self.strategy, redirect_uri="/complete/github")
+ self.backend = self.backend or Backend(
+ self.strategy, redirect_uri="/complete/github"
+ )
self.user = None
def tearDown(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/actions/test_login.py
new/social-core-4.5.1/social_core/tests/actions/test_login.py
--- old/social-core-4.5.0/social_core/tests/actions/test_login.py
2023-10-31 13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/tests/actions/test_login.py
2023-11-29 09:52:23.000000000 +0100
@@ -1,8 +1,33 @@
+from ...backends.base import BaseAuth
from ...utils import PARTIAL_TOKEN_SESSION_NAME
-from ..models import User
+from ..models import TestUserSocialAuth, User
from .actions import BaseActionTest
+class BackendThatControlsRedirect(BaseAuth):
+ """
+ A fake backend that sets the URL to redirect to after login.
+
+ It is not always possible to set the redirect URL in the session state
prior to auth and then retrieve it when
+ auth is complete, because the session cookie might not be available
post-auth. For example, for SAML, a POST request
+ redirects the user from the IdP (Identity Provider) back to the SP
(Service Provider) to complete the auth process,
+ but the session cookie will not be present if the session cookie's
`SameSite` attribute is not set to "None".
+ To mitigate this, SAML provides a `RelayState` parameter to pass data like
a redirect URL from the SP to the IdP
+ and back again. In that case, the redirect URL is only known in
`auth_complete`, and must be communicated back to
+ the `do_complete` action via session state so that it can issue the
intended redirect.
+ """
+
+ ACCESS_TOKEN_URL = "https://example.com/oauth/access_token"
+
+ def auth_url(self):
+ return "https://example.com/oauth/auth?state=foo"
+
+ def auth_complete(self, *args, **kwargs):
+ # Put the redirect URL in the session state, as this is where the
`do_complete` action looks for it.
+ self.strategy.session_set(kwargs["redirect_name"], "/after-login")
+ return kwargs["user"]
+
+
class LoginActionTest(BaseActionTest):
def test_login(self):
self.do_login()
@@ -37,6 +62,12 @@
redirect = self.do_login(after_complete_checks=False)
self.assertEqual(redirect.url, "/after-login")
+ def test_redirect_value_set_by_backend(self):
+ self.backend = BackendThatControlsRedirect(self.strategy)
+ self.user = TestUserSocialAuth.create_user("test-user")
+ redirect = self.do_login(after_complete_checks=False)
+ self.assertEqual(redirect.url, "/after-login")
+
def test_login_with_invalid_partial_pipeline(self):
def before_complete():
partial_token =
self.strategy.session_get(PARTIAL_TOKEN_SESSION_NAME)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/backends/data/saml_response.txt
new/social-core-4.5.1/social_core/tests/backends/data/saml_response.txt
--- old/social-core-4.5.0/social_core/tests/backends/data/saml_response.txt
2023-10-31 13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/tests/backends/data/saml_response.txt
2023-11-29 09:52:23.000000000 +0100
@@ -1 +1 @@
-http://myapp.com/?RelayState=testshib&SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJlc3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBEZXN0aW5hdGlvbj0iaHR0cDovL215YXBwLmNvbSIgSUQ9Il8yNTk2NTFlOTY3ZGIwOGZjYTQ4MjdkODI3YWY1M2RkMCIgSW5SZXNwb25zZVRvPSJURVNUX0lEIiBJc3N1ZUluc3RhbnQ9IjIwMTUtMDUtMDlUMDM6NTc6NDMuNzkyWiIgVmVyc2lvbj0iMi4wIj48c2FtbDI6SXNzdWVyIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI%2BaHR0cHM6Ly9pZHAudGVzdHNoaWIub3JnL2lkcC9zaGliYm9sZXRoPC9zYW1sMjpJc3N1ZXI%2BPHNhbWwycDpTdGF0dXM%2BPHNhbWwycDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz48L3NhbWwycDpTdGF0dXM%2BPHNhbWwyOkVuY3J5cHRlZEFzc2VydGlvbiB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BPHhlbmM6RW5jcnlwdGVkRGF0YSB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiIElkPSJfMGM0NzYzNzIyOWFkNmEzMTY1
OGU0MDc2ZDNlYzBmNmQiIFR5cGU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI0VsZW1lbnQiPjx4ZW5jOkVuY3J5cHRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNhZXMxMjgtY2JjIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiLz48ZHM6S2V5SW5mbyB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI%2BPHhlbmM6RW5jcnlwdGVkS2V5IElkPSJfYjZmNmU2YWZjMzYyNGI3NmM1N2JmOWZhODA5YzAzNmMiIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6RW5jcnlwdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3JzYS1vYWVwLW1nZjFwIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiLz48L3hlbmM6RW5jcnlwdGlvbk1ldGhvZD48ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE%2BPGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDc0RDQ0FobWdBd0lCQWdJSkFPN0J3ZGpEWmNVV01BMEdDU3FHU0liM0RRRUJCUVVBTUVVeEN6QUpCZ05WQkFZVEFrTkJNUmt
3CkZ3WURWUVFJRXhCQ2NtbDBhWE5vSUVOdmJIVnRZbWxoTVJzd0dRWURWUVFLRXhKd2VYUm9iMjR0YzI5amFXRnNMV0YxZEdnd0hoY04KTVRVd05UQTRNRGMxT0RRMldoY05NalV3TlRBM01EYzFPRFEyV2pCRk1Rc3dDUVlEVlFRR0V3SkRRVEVaTUJjR0ExVUVDQk1RUW5KcApkR2x6YUNCRGIyeDFiV0pwWVRFYk1Ca0dBMVVFQ2hNU2NIbDBhRzl1TFhOdlkybGhiQzFoZFhSb01JR2ZNQTBHQ1NxR1NJYjNEUUVCCkFRVUFBNEdOQURDQmlRS0JnUUNxM2cxQ2wrM3VSNXZDbk40SGJnalRnK20zbkhodGVFTXliKyt5Y1pZcmUyYnhVZnNzaEVSNngzM2wKMjN0SGNrUll3bTdNZEJicnAzTHJWb2lPQ2RQYmxUbWwxSWhFUFRDd0tNaEJLdnZXcVR2Z2ZjU1NuUnpBV2tMbFFZU3VzYXl5Wks0bgo5cWNZa1Y1TUZuaTFyYmp4K01yNWFPRW1iNXUzM2FtTUtMd1NUd0lEQVFBQm80R25NSUdrTUIwR0ExVWREZ1FXQkJSUmlCUjZ6UzY2CmZLVm9rcDB5SkhiZ3YzUlltakIxQmdOVkhTTUViakJzZ0JSUmlCUjZ6UzY2ZktWb2twMHlKSGJndjNSWW1xRkpwRWN3UlRFTE1Ba0cKQTFVRUJoTUNRMEV4R1RBWEJnTlZCQWdURUVKeWFYUnBjMmdnUTI5c2RXMWlhV0V4R3pBWkJnTlZCQW9URW5CNWRHaHZiaTF6YjJOcApZV3d0WVhWMGFJSUpBTzdCd2RqRFpjVVdNQXdHQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUp3c01VM1lTCmF5YlZqdUo4VVMwZlVobFBPbE00MFFGQ0dMNHZCM1RFYmIyNE1xOEhyalV3clUwSkZQR2xz
OWEyT1l6TjJCM2UzNU5vck11eHMrZ3IKR3RyMnlQNkx2dVgrblY2QTkzd2I0b29HSG9HZkM3VkxseXhTU25zOTM3U1M1UjFwelE0Z1d6Wm1hMktHV0tJQ1dwaDV6UTBBUlZoTAo2Mzk2N21HTG1vST08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BTElQdkVNVUVGeXhrVHowQ2N4QVA5TjV4Y3NYT2V4aVV4cXBvR2VIeVFMV0R5RVBBUDVnZ1daL3NLZ1ViL2xWSk92bCtuQXhSdVhXUlc5dGxSWWx3R2orRVhIOWhIbmdEY1BWMDNqSUJMQnFJbElBL1RmMGw4cVliOHFKRy9ZM0RTS2RQNkwvUURtYXBtTXpFM29YOEJxMW5Ea3YrUWh4cmQwMGVGK2ZMYVQ0PTwveGVuYzpDaXBoZXJWYWx1ZT48L3hlbmM6Q2lwaGVyRGF0YT48L3hlbmM6RW5jcnlwdGVkS2V5PjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BRVpUWDhHTkM0My9yWStTUVlBMXRudHlUTTVVNkN2dUNCaktsVEVlekZPRjBZZHhCWUdFQVVjYU8xNVNKOXBMemJ1L1h0WGxzTkVMZTdKdEx4RUpwYUxubWFENnIranNWczdLaTBLNHRTMGNBUERDWHV2R1FoMmFOVjVQOGJ3N1JWUGhLOGQwYlJ1RklGR09FOHMwTTZYOUpxWDN4S0MvL1lSbVVoeDlybnU3ZWlwM
Gh5ZitPaUZiVGR2SDY2NTB2LzQ3aVdKcDNZeFlUV0QyMHBNbVRJMUpwWUEwYjByWVFQRkR0RU93d0JxYktxanRJc3ZYVFJzeXJhQkxvbnFOeHN5dHpEWHEra0JsMXp3WGUvSE5QcUVQblczdnNxaFhZcDVGM3dkWThkKzNCOTRMZlpOdUd4a0p3VDNzdVR0OGY5VHRBSlI4VytBUmtzT2M4eDBVaVNsVG5BNHFHOTBLMTR5dkVoVHcvd2drZjFXV01RT3dpZDNpakFYbUV4MU5MbVZvYUxYb3p4VExkTjN6YnJ6VEJIRXc3R2J3ZEdrdU5pMlhZOW16YUgwaWtGRm51VUxjMHUwc0pycEdGdzlaK0VlUk44RzNVUVZ5MjhtS2g3ZFBwWU5KbzhyajIxZFFaK2JaeUtTUHZablU3REkyakdJRE5US1g2ZkVyVWFINGlOTzN4cUU2Vk90L2d4T3BMNE5VNUhLV0Q0bG93VzcwdUJjVEVQRmhwaThpYUovdTB6YzUvTEhvdVBjMzByc1RLZFc5cmJLL2NWaHNQUHErZzA5WHZpZ0QweTJvN2tOc1pVL25tRXFiSzBKOTBrazhCR3I5cXRSczY4bUJnSURtUHVwUkhwWjM4eXNnU2VZN3V0VlVaSG5tQ0dzTzZ2NDJ6OTVOK05Pb3RCTEVZbFd1ZEdzYnowQWc4VkRDSlY5ak95QW95MDZyL1AyUHBsOFhjdmJza2d2T1BMMWdDNnVYbVJJS1lmOEw4UDJCNXVjN0haK0dtUHNOWXRLS2VKRDFFUHovdCt2NlBIbXNVb3dsSDhSd3FMRHdtMUF4dlNLQTR3UXBlQ0dQd3A5YXRYS0lWMS84NUZzRWMzajVzNjd6VlRybThrVEpydXV2MDZEdFVRZDNMOFdwTkV4cWhQait6RUp6U3RxSG04ckhNMVhNQUVxdVozc0xycTVqLzFSNlpqS0dOdFJCbjhwOE5ERGtrWm0vWTV5TXlJNX
JJS3U5bnA3bXdaaEVpeWVHeHdxblV3VVMvUzVDRjNnMHVidnd4eVVnalVvd1ZvTkNqYktBbkdtT2VCSW5abkh0eGdIVUhVOUVlTFdyd2pRc3JtUmpJV0R2RkZQa3l6SzJDL20yaitubmNxc2E1OGRLVXZxcGR1VTRJYnNPQng3UGpXdXRBNmY5bXd6YWxyRU1NK0lGR3VPdk9HMC93eUdzQjZLREV6bldjUC83NkQ4angzaHZFSlAzN3REbFgreGM4Qno5TXdKdkd6VG4xbTdCb2xoR0lzSXlCTys1ZXpXa3RDWVVIUURGVE9wbXA0MDlOWHp6ZUNTUGY1U2NDWG5YYjRPd01ULy9VM1JFUnRRbGMrNmU2WG1JRjhoRkJVc0taUUJsS2ppSDkwZHlzYWlsNmN2V3UyQW55Q3QxbWxXcHFLc0MzU2RTRVZDTG1qRjlUQUFUMEtFSGdZQjg3RjZtZUpTTysvOXkyZkRuYVVvUUlUVzdubnVuSCtkT3dWSGZMU0wyL2N5YTltNlQzR29TSVNMbGJPMVRzalhKclVkZW55OTcvM2tkNmhFQlphdGY1U3NETFQ3SjNsQUVJNDROeXJ0NkIxQWdod2JNdkpqd1JNTXRNdUJLc3ltUytKVzc4UFNEWXQ4MG9waDJQTTc1N0tBNCtUMTAvYnZaQkE5Vk1OdVpqNVV3NXRWMnFIS3dwS0t6ZVVETUFiQlBRaGpYcXlQZzFKa09rd2RQMUpnOHRITjJTelBZQTlmT1htV0pBZGJDS2tMb0F4ZTV6cDZBUzYzS3FXMmFmSUt6SHJ3RTJmS1VtamppeURvMnNuMkJHbWtBaTRzbnpiVzc2SUQvSVgwd044aDBaQ2VRc29vKzdtb1RCMEJxSnBkS1MycXlsUktoc3BSTC9henVQdmxaK1pwckJxdXpJdEZkNFVLMkpzQkp6VXcwZkpxcTV1bk9PZENzVWM3SUU3QTNmZ1NmZ3NBd1R3WFZJMEV
oME5ySWZpMkFKV1Z2VFpEMys2eFZ3dS96WWhuVjc0VXkvMFE4Mi8yQWtpSGpFRjNJVGNLWHdTNTB6bWtLakxjZDJqa2h5TUFYMWRoQ0wwZElFMUJoN0RNamVvNC9YbjBqSlpPL3Rrbi9xZmYzc3RNb1BYVG9KTnBIU1RjR2ZheGtaMzJYNCt3Q0xPc0VBRWxlMVZSY0kwUkZyOFhHTSsxWU9BTjBodFdGcFMxaG9kSi9OczJqL1FnUVNEemNpQ1FZeUFDd3lFRWZDZjZybnR0VmJyTlJQZWlmSHhBM3B2UnZ5ZGRhNDE5cXl0ZXI0akJ3cmw3ZUpuVnJ2VEprR2VhU2FRbDdXWk5SQXBscXRnNnZPYmpiMHZDRWlFaFhKbmNzQUhxcXp5QTRGeWFUVGQ2R0FySU9adUNxRWVoWk51T01lOVlrMVpya0VkR3pIalJESWk3Q1BKQk12NEZ4ZHI3bnJvN0I1WEhKb0ZMNE1DSUtOWWU2aWZiTUtYOU5uN1FWdnphUmY2UXlaSW1BWENQZndvU1BkN2x6NXl3UDJLSUIyaGhFMWt5eVZ5YVc5T0praWpUY3dvUnZrSXhIU0RqMXFqeGxueXh0QzhVZ1pNWmlwcGgzQXJpcjRiekIzUDhIbGIzejZ0OW51KzZMemNiN2ZObVo0UHluaU50Vk9OQ0lHbEh4dTBSY3hQK3cwUXNsM1BtTzJLaHBpc2RIanhvSUJ1YVY1NXdoTlFFNmdNNFBrT0xINDc4Rzg4bUxkd2s2RFpkWVl4L2d6RWE3b3ZIL0pReFp2TzRLdFVTNmZjZHJxV2thTFg1cEhkNkdneFBGZ2NFc2Nad1ZqM2hCS0xFQmE5L0dodERINEhzRnNRbmpPZnNDQkNzN0tjRitmTi9oSUdUeHFqTVlKVHJRYmNtdWF5dk9xR3RQMDFPcXltR24rVm5FSVkzKytQcm95SFN3K0Q0b0JIVG1maFNXRmJLZCtuTlVFS3BhRVIx
NkdCU256WktQRVRVSmdRWEw5QWJRQ3RXVjFHb0UzRWNnMDZYaVd2aHFHakpGNldtdEU4dHY4Q25rZmxMNm91TDRvNldpbmx2WnNEdkZrS0R6TDkwUTNsWC9NanBtRTFpWU9uYzdISXdEVGwraFRRcHdsYXJiTDVUNGNkZTg1akNwYU0xU3p1TStiQU5zMHlXVDA0ZXJUVFc2cnhlbXFDTHAra202TVVMTlZOcE1CazBiQjJpRU82UlRtc3VpRlhDUU1xdU5xZjdkWXUwTFFCZzQ0MkJzU1pBV1ZrWEVZblduOURLdTRSby8veEFsb2h5VHozWlZmSkhuWVBSdDloSUErRHVUL3c4T2ZzTURIWnlCelUvL0JEa1NiNkxjMHdraVA3QlhIdjBoNVdud2dNWUxlZDBPalR5UWI2aGxpVnQ5b0FjaDRFVy9EZUlBdkpaQ1BYVm1pUFFYTGVsOVJIRko2bXFiYVo0TCtaZG1ONmQwcFZNZ1FveXhmQTR3dEwwYVpiNnFZYkhibjJMd2VBQVZwL3M2TzVlMVExdnZpZDRTWHo0a2l3RW1LSStIeXZEQ1pnekpQQVN5Z1gvWDJFWEZ0NGV3SjVmUFQyVXZmWnhQWlpqMFZGSFpyUFQwWVd2VE16bjUva3hoT09oM2drVGdDSmNwNWVsZnp4cEFPNFl1a0NoNHJXdVNndDRqVUJyaWNYbFdWdWo5U3JSZVhUalNHTktLK202NWovUDllNHRHT0RkMk9BbjNKTVQ3Q3FuaDhreTZpZjVjbmpVMmU3UDhTZnBONGwxWEFiZEZEcGk5bVJYamEyTzR1RWFHNGNvNW4xcWNDT3ZNMWYyblFBY1ZGNUFoSXhueS96TWhmU2l2RXdOQ0Zyd2tBWDRyQVE0WldUNldFakFyUG5jb1Y4Z1VRclhxQVA4NDJmK1lNWWI5RHFncmFicEg1a3ZuMnQzcWRldGJHODJ0QWlTamhPcUxNYW9iU2F4cXdWa
1lUOHRTMW9rUUt2MWZoZ2t6elpEOE5IQnVQQzdNVHdXS0VCS2tDRUUzRWRFMXhNQURLd1B1M3NSaGpSaExXZyszZ2srejJtdlU4cTBhTlc0Y3hObUdoekx4eEY0Q3NFNStMQ1cwOWFpUVJOM1VvWmg1aktBZzBiMlh3WHBLS3pycUVTY1BYdnI0L1dWUTMyMm5qRWRvQVdXR0t2WnBKMlRlREo0eDdiT21LVElFc2RHWU1UZzFVaEU2eFFQcnhqS3dWeGFJNVJyaVE4a0xpaGgwa0t0WHQvYTVsSDhzUjVwR0ZISGZ3dlNVb3liQTB1eUVDNnNRVitPbTVReUZmRmpqZHFCOGNpOGxQS1hLTHFCTHJ6bjNmUkh3TmQwbzFiRTg0aGllTkx5UlhZVmhrRCtFNEpGaVd3ZWt3U3VWM3BjQk9ybnRVU3RoWmx6M3hIUURUVGNJNWliOFJyQ2swZEZ6YTgvQmw3VUdtWlUwSXZ2UmdvVXF2TXNHT2dMY3pGWmRpZnJ5aGNiUTY4a2ZzZ3lCMHppdC9MN1BSV3V4RkdYdDFoTVZSVUZ3WXBJS04zVkI3cXVKZlgwamZsU1JaRndMaXdlK3VhYndmTVZ6c2doajUvOXZNNzcwK0JaMGtJcE45NzBTMG5BbHl6R0h0aW1nTUl1RXFhbUt5QTNTQlI1aHZIYmRyNENnTHFUbXIzbFFnWmpnSkNvN1FXYUJWTXdCR0RpdzVOVVhUUnBycWc4U3h2eDlnNWZwbXMrL0o2QjFEelNTM3ZRZzgxdHFRU1ZDWVJpc0Y3M2VqZlFuZk4zcUszd3RJRDkxQnRISmFvMEFaUUdKVFpKOXVsZ0kzV3hzdWR4ejB0VHVpNlJlSWpmSWsxekZRdFpwRExGMnB3NGpTQVdQTlJqNDBYdVIrRzFUVlI3OVFiME9FYkw4RDFoTU5zWmo3MTZNbUhSOTlKaUxNdm1FWHV5a1V4VGhGYjRMTzZVbW1kU3UwTl
BpMXQ2NmNkYURpQWhMaVBFTGdUNkZsenA2T2FGSGNSNjRncEtyemtTNDJONEhJeFpNa2R6M0FsYkRhK2pOWHZPR1l3UWl5K0xNNENZWGtrTWtHR3ZTWis5R2xWQ0l5RXBJaXIzbEQ3bmdzZGk4emxGWDYvekNaczlQSUtwZFZlSGJGZi9GS20wV3AreHI0Ykd0R0RrVHR2Nk1Manh2YU8zanFHaUFWeERKVWFkTVBlS2VHSm5uempTdnpKbGdOVHV3c3grRnF5L2dPMkwxMGowWmhDWi92dE9NelVjNjl3cGhKZm9FNzU3V3lOeFJOcThJc0Y1Tkg5Y0x0b3UvbUNxOTc3YnZPSkRrSURCN3lKWEJ6YUhVQkJuSXJra1Qyemg3bGJmUm5SREJUSFZraVZMazVESUxqeC9XL1BSZEZpUUM2SzRmZGx4Y29JbzlMcnM4ZFVWZkt2TTNNYnJ6c1hGT3ZtVVh0K3NsZldvd3UyTC9ndG9mRFhvTUJZZnlEcWIvWlRaRWZ0MC83blliRm1relBEUlZacU5SR0F3YWZVNTU1UjB2SWtNbGR2VjdKUzhNT1BNYWlXQVBpelNLRG4yRzNvcys1MzRFQytaOGZnWmFPVWpZL0xLME9vME9RMmhvNUV6MGNMYWpwUjFINk9FNEhvUm1ydjQzZkFjdGpYc0hYdi81RXg3emdrWk1NZXZhTFNEdjZtcjFGcDk4QXR4L296VTFGVDBoMDUxcVcwR0g2VWpRRXk5aExSZDBBMnFkUTRMZXpReDNvbDFTblhsamt2MG4zTXFlaFozOC94bzZhdHFDdkJtQkc3amlUdXd6YnlVUngzRm1TM0NCNllOYnFON3hPYVRZRnlkOEZDL01nY0xGQmMwS3F4MXllQ2VUd1hucldQb0dvdllVQlYxYjA1cWtIa1d5V0RUaCsveXJFNzF0RjNxbUQvd3F6cUJyNE04NERtWWVuQkdFOWxtb3FIZEMyWnRpK09
KVFZKcmlHZWxQQ3RjZnZRaUlQcHdDZ3BFNmg1ekZhRndLajRuZGtBUkRpTC95L1EwWTZxNU5rM1g5RURlTmdjY1pIcFdmOUpKQ3M2a29wdXRtYjdDczIrbVJYdER1S09DaGY5UVUyN3Bmb1NJaklYK3NGdHY1c0hhSms2aHBZMlpzUUhzaTBYbFowc3FMTnQ5ayszdTVnYnBSU1JCczlHaC9BaVY0dkNyYTRkOTh5U0dCdzRSR1FhSStpQ29RaG9YK3lxc3VrYkx6bXJUU3FXMVRXaXJReUlHZ1Q5VnFERE1mUzAxeGdQSlNFSTlIWlp6TGlFVXVGMm1CMi81Y2dqaEFUaWQrdGV1UVB4aldhN2NSc2t5YUhuTENjQURVUU9ESUFPVjJDWXROcnAwY29ZL091S3ZzaXlJT0lacVJ5dE1PMGVNZ1ZJWTBzWmdxeVEycXlubUx0NDBmWmd3SFVyV245Zm9TYTNtMkVRTy9uOS8yU2NuelJWdVZpVnNjM0tCSElQL3AzNlJlSWowTGlNcCtPQ0p3SHlLVW1UeDRBU1V0dXVhWktlRHl1QjlxcXJuUEFNWUVCeElsTGFvdXMzV1pHakIrcW9ub3QvNmk1UE40bUZjbHFDcUxhMGJHbks4ZnJxYy9yd2tuVGV0YUE0c2tXTEw1L21qNEd5MitFQkh3a0x3UXd2K0FKdmZTOXYvNDl1LzY0N1ZFYW15UzdZQ2ZEUHNBQUREQ1FFcWJNQ1h2Ui8xVmEwWi9YUWhoNlkrZUt0MEVpRDdpNmRZODJtQkFoNEJMRmRVV3VGZHVrdUVwaGZ2WXB3N2loVjNxTjB1NFM1NTRXU0dUa0ZsdlpYNG1hbkF4a1g2ekQxS0NWaEFMdEJnSDgzdkhxam9uc0lwOFMydHgwZ0tiYzEreHVaRVppVWlNVVlVdTByQVFsRFcrZHJoN3lVRHZqekFHSnBmTk01eThaMW45em93VzZ5YW5VZWFBNjhSZDd5
TUxobFd0NVh6bGhBTVZDZmZYZ0pFelR1YzJEbENVOXNMLzVTVkRaV2N4R1E5aFM1cnJtK2VyQ1Jxd2FJQk1DNUtza0RCZHdOWmh2Q0FCdEpqS2Vla1FUSjd5MFp4SGNhbGVCaU1rbkYwZVRDZzFvUEhPUVZLQ3V3NE94cHRZUS9xS1V0TEFIWFZ2OTlLMGRWcWZDMmpVQWlHQmVYa0t3aGRYTGtJYlZxU0EyZmxraXBBeEhYNnByUEExQjF3eTVab3hPUFg4RVExOW92eXpBbFg1dHU0OXEwWC9PSExFN1o5T1cxenltRXR6ZFpyNXJZbWtFcVdtcHVSNU5jeHFwTWlZam93dUNXZWhubzIyeG5JM09IQ0xDZkFKaHRrcklhL1hPc0tZRFpCRzFJMGJsN2taR2R5cEtUQlhYdXl6WE5WUlU5L005ejhaVytwdG1oZ2NOUzBJS2VaaSs5bFl4cWRlS3lnbldTTTV3czdSYUpmNlRRZTNSaWJZUjFvNkhwRzB2VHpiTEtQZTZnRjJGODdiWlBJei9mcTNLWnZiM3UrSnhZcCtJVjBtQi9VN29YelhRRk1RK3VmWllpNzUxbkx6WlVxRE1ybU53TFJPVUFNUk8rVnJtblkwSVB1cFBVMXc0b0hBb1dnVGRnTk5pNk1uTFQ4V0pmUlhjT0pKMk1lbUc2K2ZNeHNZUU52UVJwa1RGY05vaFV6Y3ZjcHJ3NUV3WEVZQTJzbzczL2MvY3RIRGcreU05YlF4REppUlltRnFydkhYb29hS1JyekxnUjZLVWdoM3ltaWxaQ0lSSm9KbTE3aEtHM1pxTTE0Lzl5OUc5OE9BZjNkVTlqMDk3aUNlaEc3a2VxYXRJQ2hFWmJqbmQ4Y00rS3djN2FtVWp2ekQzQmNvMHl3MDJxT054OWF3OGhSblZiWDZhdkRJbGhySHZ6SU44MzFvUjljRHBwMG1DUEJXZFVDQlNqVGJ1RkZqRC90WElSbGxlT
2JraFFKSUdSNlE2U1MxcXkzT29WT1VheFl6THY0U2s3dndrQUMwUitGREVIeVFZbFVhbVVkTWcyUmdwRUdhSVd1V3IxaGNnRm10QmREV2g3ZFBuWTF0U3VKOC95MXp4NkRvN2ZJYmNFenBBK2E0ODNtRG5vemdld3VmaFdqVCsvUS85WlEreFQ5UWJBT1pQSXhHV3VhSXVrVk8zSWxvZDhJM1NGZFJCTHY5ZXBDNzFLeXpSdVlpMktkOHJ5NVNINit1WnMxUHlZUlpRakdDK3Q4VzRtSE82Z1lFRWVXSkJ1UWhnSHdmV2xhZXlWb3hac0NBQVZKRUllT3hPZDZtNW45OHRCUDdHTmgxT1M0eDRCS2FVN1A0UVQzNVVIZW5meE84WWFQUThmbXlobUJhSVJVZklBTVN2ZTJZRFp5SWNNTTkrN0tNSVVabzJ0eXRvYzdCOGVvZzBNaUkrVkpFdFg0c29FRjFSWkhQZVV3NWlCTjI4OTh2MmVTcGNnVUJhWHFzOUN5VlZtTVJQMEtLUDJ1REt4MUdJcUhjS0ZCOXVQVWRkQS9vT3dNa0tVUWsraFZVVDVPbEVMdjd1a0FBUEE0eE4rZkczVmYxeUVKV0FiVGx5dWtGcThjNXBTRkY1cXVHbUgwVmVpQzVvVEFka1VES3Z6WGhWWUs5c3BRYjNVZ1Z0Qld6N1ZScnlOUVVST3BIZU5xeDlhZHA4YWREWCtRSHJUKytYblN4VVI3SVdGanlNTkZJRWlMWmkxdks1UVVrZlRDUU9qdjh2SHdiUi9MRHF3Z3M5bXdsT3pPY0RLdVBVK0dTb2lnVFdRejRWN0N2SHRaVDI3WUdKVG44RFFFM3IzdjB4aWxvODJ2U3VXSDg0WEU3VEJsTUpFb2R5eDNDRngwVUVkc3VhRHBPSEV3UjZYNlUyU0xseERYSXVZeEhlNXh2NjI4bXU0bDRMSnBYUjhkYmljTEZKQW55Q0FVeDJLb2dDamt1cm
U4bXNUZktDbG8wamFlN1hNR05PSk15b0ZYbVlHZUh2eGhNUGMzTEtYLy9VY1p0c3p3dFJrQmNFdURXQysvQWNWZVBOSHVOWWI5MEpIcnRucGg1ZDlhL1lpTkpzY1N3QTFwUVZrdW1TQWtPQWdLdWRzcnl3c0N3Zkg1anNydVpHUTJDd1hKRXQzUU4wU2NLUlVnT1NCQ3FYa1BqZDVSVzJuOFZpamt4anovbWptakhCNmk0eHM5NEU2Nzk5STAyaldYNVd3UDZhTFRaTGt5TjhxNDUxT0RmeUZVZEY5WWsyZXQ5VUpsV1NzRFJMSWVCd0ZyQkEyZTdyRWsybWFLVUNCRW5PUWM2bUhVMXQvZ3gzK1VXVVFXbkpMZVUxbWUvbkFEdy96UGUwd3d0Vm9BaERZdDBoR1hQblJydjFoUHRGS01CeWtqckg3a0J5U0R3WDlQMi9XZkNkQlE5K1J4cHRsR2hvRmdpMUs0NVlOeEpEd05wTmd5MDV2WXUzVUtrMkpRYVNGUzcwK0Y1NzluRE5RenZpK0pPRlRsdDFmWDJGNXk5NEV2NHZobWRQSmRVOFVVRjU2Ymx0emxKREVFdmsySlFrOTM0aHpwTXJGZ1d3ZHUxUkxxSEhCN2h2T2hnaHNqV0ZGY01zNjZaRUtWcVhKUytxWWNVMHk0akwySVQrNlF2N2pvQ3BWbUdzUWtGY1FyblhxOUJiOTdaUS96UCtwaldmWTU0UmNRVlMydUU1YURObVVyVkdLK3E0d0xRcUhuRVViT2puSHFFeGlacUtxOVdRaUtUK2c3QS96bVlIQ2k0YzFTejRNVWhHb0t6U2l4aXoxYUNJUEJXdy9vczR2cUVqbXgzOGx6YnV0OWNWbElzeGNkTUpUTERRK3ZOZ0YyY1ZRaVcxRTQ0d3lWcnI3TUFaOE9KRVpFSzlEZWt5MzJQUkFuSkRUVXVqdGFscmJ0T2VOczhyS09uTjcvNFRqUEwvZmRlbEI4bjA
4WXdSNXdmbU42VGpGWUhRSDFjbUZmK1AvNUxVMTI4Q1pEYjNQUStxMlFJazV3aE40eGwvcy9lb29pallmeWtDcm5aSEhHWkluTGhoU2pWbk5ISWdTL203VWV0NlhBTDdvZUl5UFRLeHVnbDJzRWtUQzNnZ0tjTnFZR0E5U3ZlYVlaQ00vWHNQRUtQbWs3QmlRNmprWFBKaE1yREd4Vkc0SW9aSDgrYjBrUWJYR2l0Mkw0L3hZdHh1bTVzcFNPSjdsTDltVFpRNnBxM2JOaTEwZU1mZ0ZWaDc3NU5JRlc0SEp3U1FtaTU0bk11blZTQjhxdjZKc0w3SGlsZ2N0ZHFSNThTTjVad1lCa2dOR1hzYjA1QXJWemVXbHh1Y21BSHNPT3dyczFnMzh6bTRZN2ZPZmducmFhV1kxanZZOFlEODZQZThkZzR4cE5paTg3UnNDZk5WK2NKVmMraktFdnpuZVY1Zzd0RmlxZCtsZHp4STlKemdSS2t0WUV6RUpRSVU5M2UvclJaN1lrVkZtNVV1cjVhMWYzcG83T0VtYkJUc2MrQ1FaOGNnYmIvbUphRXJoa3NyL3JURjBNcjNxeDl5SlJWSEJ6YWNWd0dScEFRaURPdnJkWU4xQXBVOTRyR1lrVFVzdWs1YjE1Wll2QVZxRlRzVlVMaS9HY29mbEljMm01Z2RFTFZOblRmdXY1Zlk5S1NlWHFoUU80S0pOYVZmbHAwQ0VKYWFFZFNLUXJJNXRaT2w1RkE4VXZlNmxTWVd5TVk0REl4a1RiT1JoWHVBdzR6b1RTMjgrN3d2TXhydVBkZnlKbUJCTkhQdCtEYmdKNHovcHJZWUhpTmFMTXNZamtQZE44ajNKZDczQXJFZk92Um52MzYxSVVVMFg1RDc1dlRSdlpkbzMzWERzanRlOU4weUo3K2lIQnF1a1FJY2pIVW9ic2RQN0hOajBVYWNSMHIvTmRlVTlGNFBNc1VLY2t6Tk4rZGhyMVI2
d1J2R1VZb1pDRWJaWlJMWEt4QnA3SElUNEVQUktHakIvdW1xTFhhMXl6RWx2QW1WQUJhMDFZN3dGdk4wM2Ywb25FbUhTM2w1d1paRmV6cjVibnN5T01XVGxhMU5kaW1ZNXNVeE15VFliZmc4dzB2cXNEc28zWFAxYndLdzZ3M3VIRGQ1UHBSWnVDSnR0eWk0ZzJGeWI0Ymg1UU42ZkdORTI2ekRGN1Y4QmJwZXJLNkFKQ0xTWm5kaDZMMTlPUTBram4xUGpEMGk4c1BZcGFXOWxVeVJkZElPKzRWQS9LemxPUzJ4M2s5VUtUdElsTTBUSVdtZXFIS0dYUVpocGpvVGI2VlNKN203cjZaaVlQMnVsQVVvZmVWL0o2eCtzckxEQXkyQ2ZFNnFrREZ1OU9NWDBBSXVnN3loQUtOMDRyT3hVNk5tcGtjOUZ4bXUvVS9vR3hHdmIzeFVFTDYwdE1sSE9EaWtqY1I5RDJrKzRwbEc1WnV0d0FIY2kwRU02WHRrVEhQOU5QMlRTR1VFN1E5SGYvU0VEc2V0a25hZXhvWmhDczJLWDFMeU5JS0U0N2pkMkR3MTUreDRRVXV0VUFTbzU5Q1lHMVFBeW9BVVhrV3dtbXkzTGdTUWp5T3ZLV25qaE8veWpPd0FyWGd0NFBrSVVnZDQ1N05ReFpMbU41K0J4NVJoQ0FHdkUxYmxOZjlMek9keGJiaG5VZ2Z1RDM5MXVSRkhjS2RYREY3ZmVqb3gveThtaWZJcTRWVzQyajBHQnFOQUtkK0prMnJCMW9hOTRiT2hxcVVzanhqWnlRaGRXTzhNblR6T2tOaGVpZXU2blYxcW5yZ3JHU2huWTNJMlczb29GNFNnczRjZ3drZ2h2dHpFa0xUbU5OUm83RTdudVRuMkxJcmlGSnlvTmZQdUp0aWN0S0JtNzRGZytkWVBTMlIzTzNmOWxBZWxiVWZjbzZGNU9EL3hkS1VuRTh0V3FOMExVcDlWQUptW
VZYZFVDaGJ4MjM4MWtDaStLNDJoRzUydFNQYU1hb1dTb0xQY2Zrb24rc1pYdjdEdEtwZi9HTzdhcUMza1pzRGpva29haHJGZGJWSlNTZWhrNGp5K3RzRHplQnJKSjBrMVZrUnJHN1NoVHZjTmd1cjVucVRUTEE5dlJMQmJNTTlhNlI1NEZ0Z1pQOWFKMU1aMEdCcUVpMnF6Ui8yd2tYQlhwcFhZdi9TcU1RV1dhbTVsSHBMVktxaDN4ZHRjNFdmck9mYldsbU1PNXA5Z0JUSFp1YUcxVGFkZXFRVVpKQmZBS01ENFdSR0NsMDFaeDRTVzE0YzZrdnFKdXExL080N215L3RsVHlLWndpYlBkQTNRMVVGd0I3R2Z4anEwaDN2ckxFbUNrS3Vsc0VBUkN6UnZNVjJSVnBVbFpUV240Y1Boc0hjcTNROElHSUYyKy9nOENFSU4vMU8xcVMvMkpXcXlDNmtIb0w4Y2R2R0VHbmkxSTNDTk1JcXhxaHhJL1V0R3REc2VwYmwrSHI0elh4MzZna3BCbXBoT2xkTFVYTHAzVEtibVVZRWJSWHcvZmRmeFQ3WDdZUFhHQ0hHVG1uTzk4WkxDOTA2Zmkvekd2b04rNlpzbCs3MkpWMGxJWEo0V3dZdWxFUmZHbkFDWGNoa0Yzei9ITWR3elcwTUFFaXptQmwvREo2ZUoyU01PSG1Uc25YbElGRDRlcFRrYnFBQ0dpZ2I1UExFdHdQRVRjYkNRckM5YUtTU1FnSTdEZXd1aWlxM2J0Y0RUWkIzeEI5WWxlbmhpU0FXNjIwcmwzc2ZjY3d3eGFSOHBDV2Rzd0x3dmFxcDhjM01PV3RCc2xPcmVTSkNEcWgvdzBYbm1WMFJVWFpNM2JvUmkwVXhsaHVUeDFlM1NTd09pbTlOczNYV3NoTmI4Lzc3VkhnUWhRVFlSUU1NRllYaWRmMElCKzBtSUpocWNoQTlUeUY3dGRjSDhrUUJUSHNEWS96bF
pqK3EwNlFMd0JkbTkxc3IyK3VzZmxlaXB3WUMrcmdiNHROVnA3VU5rYkVqTnR6ZWZsTi9VRTlkbHZtT2x6V1dtZkh2NGVkUGkzMmJmeUNRS1d6SGJVVEV3NU0yVFpsZnpNaTFWUjVsaDBxQ1lqaDNITUlmL2MwcHBKd2I1b1lFTnBBenlxbnlmdmlTV3lBYzc2L1l1VWwvb2FVaysrYzBZc2d1TGo5ZGFQdVVvemhoZ3VjSytQRGlNckI0ODU1Mk83VWg0aHRwNmZ3S2dJa1JCTVFIUTd6MmV5WXovV1AwQm9ZZVhjOGc3aUprclhFNzA1bFo1bXhGU0poT3E1WlNleVJSb21pUm41K3VRemM5ZFdWQjBYb2JURXdOc0VRM2FIZ25JY29BczY2UGplUT09PC94ZW5jOkNpcGhlclZhbHVlPjwveGVuYzpDaXBoZXJEYXRhPjwveGVuYzpFbmNyeXB0ZWREYXRhPjwvc2FtbDI6RW5jcnlwdGVkQXNzZXJ0aW9uPjwvc2FtbDJwOlJlc3BvbnNlPg==
\ No newline at end of file
+http://myapp.com/?RelayState=%7b%22idp%22%3a+%22testshib%22%2c+%22next%22%3a+%22%2ffoo%2fbar%22%7d&SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJlc3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBEZXN0aW5hdGlvbj0iaHR0cDovL215YXBwLmNvbSIgSUQ9Il8yNTk2NTFlOTY3ZGIwOGZjYTQ4MjdkODI3YWY1M2RkMCIgSW5SZXNwb25zZVRvPSJURVNUX0lEIiBJc3N1ZUluc3RhbnQ9IjIwMTUtMDUtMDlUMDM6NTc6NDMuNzkyWiIgVmVyc2lvbj0iMi4wIj48c2FtbDI6SXNzdWVyIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI%2BaHR0cHM6Ly9pZHAudGVzdHNoaWIub3JnL2lkcC9zaGliYm9sZXRoPC9zYW1sMjpJc3N1ZXI%2BPHNhbWwycDpTdGF0dXM%2BPHNhbWwycDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz48L3NhbWwycDpTdGF0dXM%2BPHNhbWwyOkVuY3J5cHRlZEFzc2VydGlvbiB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BPHhlbmM6RW5jcnlwdGVkRGF0YSB4bWxuczp4ZW5jPSJodHRwOi8vd3d3Lnc
zLm9yZy8yMDAxLzA0L3htbGVuYyMiIElkPSJfMGM0NzYzNzIyOWFkNmEzMTY1OGU0MDc2ZDNlYzBmNmQiIFR5cGU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI0VsZW1lbnQiPjx4ZW5jOkVuY3J5cHRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNhZXMxMjgtY2JjIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiLz48ZHM6S2V5SW5mbyB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI%2BPHhlbmM6RW5jcnlwdGVkS2V5IElkPSJfYjZmNmU2YWZjMzYyNGI3NmM1N2JmOWZhODA5YzAzNmMiIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6RW5jcnlwdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3JzYS1vYWVwLW1nZjFwIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiLz48L3hlbmM6RW5jcnlwdGlvbk1ldGhvZD48ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE%2BPGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDc0RDQ0FobWdBd0lCQWdJSkFPN0J3ZGpEWm
NVV01BMEdDU3FHU0liM0RRRUJCUVVBTUVVeEN6QUpCZ05WQkFZVEFrTkJNUmt3CkZ3WURWUVFJRXhCQ2NtbDBhWE5vSUVOdmJIVnRZbWxoTVJzd0dRWURWUVFLRXhKd2VYUm9iMjR0YzI5amFXRnNMV0YxZEdnd0hoY04KTVRVd05UQTRNRGMxT0RRMldoY05NalV3TlRBM01EYzFPRFEyV2pCRk1Rc3dDUVlEVlFRR0V3SkRRVEVaTUJjR0ExVUVDQk1RUW5KcApkR2x6YUNCRGIyeDFiV0pwWVRFYk1Ca0dBMVVFQ2hNU2NIbDBhRzl1TFhOdlkybGhiQzFoZFhSb01JR2ZNQTBHQ1NxR1NJYjNEUUVCCkFRVUFBNEdOQURDQmlRS0JnUUNxM2cxQ2wrM3VSNXZDbk40SGJnalRnK20zbkhodGVFTXliKyt5Y1pZcmUyYnhVZnNzaEVSNngzM2wKMjN0SGNrUll3bTdNZEJicnAzTHJWb2lPQ2RQYmxUbWwxSWhFUFRDd0tNaEJLdnZXcVR2Z2ZjU1NuUnpBV2tMbFFZU3VzYXl5Wks0bgo5cWNZa1Y1TUZuaTFyYmp4K01yNWFPRW1iNXUzM2FtTUtMd1NUd0lEQVFBQm80R25NSUdrTUIwR0ExVWREZ1FXQkJSUmlCUjZ6UzY2CmZLVm9rcDB5SkhiZ3YzUlltakIxQmdOVkhTTUViakJzZ0JSUmlCUjZ6UzY2ZktWb2twMHlKSGJndjNSWW1xRkpwRWN3UlRFTE1Ba0cKQTFVRUJoTUNRMEV4R1RBWEJnTlZCQWdURUVKeWFYUnBjMmdnUTI5c2RXMWlhV0V4R3pBWkJnTlZCQW9URW5CNWRHaHZiaTF6YjJOcApZV3d0WVhWMGFJSUpBTzdCd2RqRFpjVVdNQXdHQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUp3c01VM1lTCmF5YlZqdUo
4VVMwZlVobFBPbE00MFFGQ0dMNHZCM1RFYmIyNE1xOEhyalV3clUwSkZQR2xzOWEyT1l6TjJCM2UzNU5vck11eHMrZ3IKR3RyMnlQNkx2dVgrblY2QTkzd2I0b29HSG9HZkM3VkxseXhTU25zOTM3U1M1UjFwelE0Z1d6Wm1hMktHV0tJQ1dwaDV6UTBBUlZoTAo2Mzk2N21HTG1vST08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BTElQdkVNVUVGeXhrVHowQ2N4QVA5TjV4Y3NYT2V4aVV4cXBvR2VIeVFMV0R5RVBBUDVnZ1daL3NLZ1ViL2xWSk92bCtuQXhSdVhXUlc5dGxSWWx3R2orRVhIOWhIbmdEY1BWMDNqSUJMQnFJbElBL1RmMGw4cVliOHFKRy9ZM0RTS2RQNkwvUURtYXBtTXpFM29YOEJxMW5Ea3YrUWh4cmQwMGVGK2ZMYVQ0PTwveGVuYzpDaXBoZXJWYWx1ZT48L3hlbmM6Q2lwaGVyRGF0YT48L3hlbmM6RW5jcnlwdGVkS2V5PjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BRVpUWDhHTkM0My9yWStTUVlBMXRudHlUTTVVNkN2dUNCaktsVEVlekZPRjBZZHhCWUdFQVVjYU8xNVNKOXBMemJ1L1h0WGxzTkVMZTdKdEx4RUpwYUxubWFENnIranNWczdLaTBLNHRTMGNBUERDWHV2R1FoMmFOVjVQOGJ3N1JW
UGhLOGQwYlJ1RklGR09FOHMwTTZYOUpxWDN4S0MvL1lSbVVoeDlybnU3ZWlwMGh5ZitPaUZiVGR2SDY2NTB2LzQ3aVdKcDNZeFlUV0QyMHBNbVRJMUpwWUEwYjByWVFQRkR0RU93d0JxYktxanRJc3ZYVFJzeXJhQkxvbnFOeHN5dHpEWHEra0JsMXp3WGUvSE5QcUVQblczdnNxaFhZcDVGM3dkWThkKzNCOTRMZlpOdUd4a0p3VDNzdVR0OGY5VHRBSlI4VytBUmtzT2M4eDBVaVNsVG5BNHFHOTBLMTR5dkVoVHcvd2drZjFXV01RT3dpZDNpakFYbUV4MU5MbVZvYUxYb3p4VExkTjN6YnJ6VEJIRXc3R2J3ZEdrdU5pMlhZOW16YUgwaWtGRm51VUxjMHUwc0pycEdGdzlaK0VlUk44RzNVUVZ5MjhtS2g3ZFBwWU5KbzhyajIxZFFaK2JaeUtTUHZablU3REkyakdJRE5US1g2ZkVyVWFINGlOTzN4cUU2Vk90L2d4T3BMNE5VNUhLV0Q0bG93VzcwdUJjVEVQRmhwaThpYUovdTB6YzUvTEhvdVBjMzByc1RLZFc5cmJLL2NWaHNQUHErZzA5WHZpZ0QweTJvN2tOc1pVL25tRXFiSzBKOTBrazhCR3I5cXRSczY4bUJnSURtUHVwUkhwWjM4eXNnU2VZN3V0VlVaSG5tQ0dzTzZ2NDJ6OTVOK05Pb3RCTEVZbFd1ZEdzYnowQWc4VkRDSlY5ak95QW95MDZyL1AyUHBsOFhjdmJza2d2T1BMMWdDNnVYbVJJS1lmOEw4UDJCNXVjN0haK0dtUHNOWXRLS2VKRDFFUHovdCt2NlBIbXNVb3dsSDhSd3FMRHdtMUF4dlNLQTR3UXBlQ0dQd3A5YXRYS0lWMS84NUZzRWMzajVzNjd6VlRybThrVEpydXV2MDZEdFVRZDNMOFdwTkV4cWhQait6RUp6U3RxSG04ckhNM
VhNQUVxdVozc0xycTVqLzFSNlpqS0dOdFJCbjhwOE5ERGtrWm0vWTV5TXlJNXJJS3U5bnA3bXdaaEVpeWVHeHdxblV3VVMvUzVDRjNnMHVidnd4eVVnalVvd1ZvTkNqYktBbkdtT2VCSW5abkh0eGdIVUhVOUVlTFdyd2pRc3JtUmpJV0R2RkZQa3l6SzJDL20yaitubmNxc2E1OGRLVXZxcGR1VTRJYnNPQng3UGpXdXRBNmY5bXd6YWxyRU1NK0lGR3VPdk9HMC93eUdzQjZLREV6bldjUC83NkQ4angzaHZFSlAzN3REbFgreGM4Qno5TXdKdkd6VG4xbTdCb2xoR0lzSXlCTys1ZXpXa3RDWVVIUURGVE9wbXA0MDlOWHp6ZUNTUGY1U2NDWG5YYjRPd01ULy9VM1JFUnRRbGMrNmU2WG1JRjhoRkJVc0taUUJsS2ppSDkwZHlzYWlsNmN2V3UyQW55Q3QxbWxXcHFLc0MzU2RTRVZDTG1qRjlUQUFUMEtFSGdZQjg3RjZtZUpTTysvOXkyZkRuYVVvUUlUVzdubnVuSCtkT3dWSGZMU0wyL2N5YTltNlQzR29TSVNMbGJPMVRzalhKclVkZW55OTcvM2tkNmhFQlphdGY1U3NETFQ3SjNsQUVJNDROeXJ0NkIxQWdod2JNdkpqd1JNTXRNdUJLc3ltUytKVzc4UFNEWXQ4MG9waDJQTTc1N0tBNCtUMTAvYnZaQkE5Vk1OdVpqNVV3NXRWMnFIS3dwS0t6ZVVETUFiQlBRaGpYcXlQZzFKa09rd2RQMUpnOHRITjJTelBZQTlmT1htV0pBZGJDS2tMb0F4ZTV6cDZBUzYzS3FXMmFmSUt6SHJ3RTJmS1VtamppeURvMnNuMkJHbWtBaTRzbnpiVzc2SUQvSVgwd044aDBaQ2VRc29vKzdtb1RCMEJxSnBkS1MycXlsUktoc3BSTC9henVQdmxaK1pwckJxdXpJdEZkNF
VLMkpzQkp6VXcwZkpxcTV1bk9PZENzVWM3SUU3QTNmZ1NmZ3NBd1R3WFZJMEVoME5ySWZpMkFKV1Z2VFpEMys2eFZ3dS96WWhuVjc0VXkvMFE4Mi8yQWtpSGpFRjNJVGNLWHdTNTB6bWtLakxjZDJqa2h5TUFYMWRoQ0wwZElFMUJoN0RNamVvNC9YbjBqSlpPL3Rrbi9xZmYzc3RNb1BYVG9KTnBIU1RjR2ZheGtaMzJYNCt3Q0xPc0VBRWxlMVZSY0kwUkZyOFhHTSsxWU9BTjBodFdGcFMxaG9kSi9OczJqL1FnUVNEemNpQ1FZeUFDd3lFRWZDZjZybnR0VmJyTlJQZWlmSHhBM3B2UnZ5ZGRhNDE5cXl0ZXI0akJ3cmw3ZUpuVnJ2VEprR2VhU2FRbDdXWk5SQXBscXRnNnZPYmpiMHZDRWlFaFhKbmNzQUhxcXp5QTRGeWFUVGQ2R0FySU9adUNxRWVoWk51T01lOVlrMVpya0VkR3pIalJESWk3Q1BKQk12NEZ4ZHI3bnJvN0I1WEhKb0ZMNE1DSUtOWWU2aWZiTUtYOU5uN1FWdnphUmY2UXlaSW1BWENQZndvU1BkN2x6NXl3UDJLSUIyaGhFMWt5eVZ5YVc5T0praWpUY3dvUnZrSXhIU0RqMXFqeGxueXh0QzhVZ1pNWmlwcGgzQXJpcjRiekIzUDhIbGIzejZ0OW51KzZMemNiN2ZObVo0UHluaU50Vk9OQ0lHbEh4dTBSY3hQK3cwUXNsM1BtTzJLaHBpc2RIanhvSUJ1YVY1NXdoTlFFNmdNNFBrT0xINDc4Rzg4bUxkd2s2RFpkWVl4L2d6RWE3b3ZIL0pReFp2TzRLdFVTNmZjZHJxV2thTFg1cEhkNkdneFBGZ2NFc2Nad1ZqM2hCS0xFQmE5L0dodERINEhzRnNRbmpPZnNDQkNzN0tjRitmTi9oSUdUeHFqTVlKVHJRYmNtdWF5dk9xR3RQMDFPcXl
tR24rVm5FSVkzKytQcm95SFN3K0Q0b0JIVG1maFNXRmJLZCtuTlVFS3BhRVIxNkdCU256WktQRVRVSmdRWEw5QWJRQ3RXVjFHb0UzRWNnMDZYaVd2aHFHakpGNldtdEU4dHY4Q25rZmxMNm91TDRvNldpbmx2WnNEdkZrS0R6TDkwUTNsWC9NanBtRTFpWU9uYzdISXdEVGwraFRRcHdsYXJiTDVUNGNkZTg1akNwYU0xU3p1TStiQU5zMHlXVDA0ZXJUVFc2cnhlbXFDTHAra202TVVMTlZOcE1CazBiQjJpRU82UlRtc3VpRlhDUU1xdU5xZjdkWXUwTFFCZzQ0MkJzU1pBV1ZrWEVZblduOURLdTRSby8veEFsb2h5VHozWlZmSkhuWVBSdDloSUErRHVUL3c4T2ZzTURIWnlCelUvL0JEa1NiNkxjMHdraVA3QlhIdjBoNVdud2dNWUxlZDBPalR5UWI2aGxpVnQ5b0FjaDRFVy9EZUlBdkpaQ1BYVm1pUFFYTGVsOVJIRko2bXFiYVo0TCtaZG1ONmQwcFZNZ1FveXhmQTR3dEwwYVpiNnFZYkhibjJMd2VBQVZwL3M2TzVlMVExdnZpZDRTWHo0a2l3RW1LSStIeXZEQ1pnekpQQVN5Z1gvWDJFWEZ0NGV3SjVmUFQyVXZmWnhQWlpqMFZGSFpyUFQwWVd2VE16bjUva3hoT09oM2drVGdDSmNwNWVsZnp4cEFPNFl1a0NoNHJXdVNndDRqVUJyaWNYbFdWdWo5U3JSZVhUalNHTktLK202NWovUDllNHRHT0RkMk9BbjNKTVQ3Q3FuaDhreTZpZjVjbmpVMmU3UDhTZnBONGwxWEFiZEZEcGk5bVJYamEyTzR1RWFHNGNvNW4xcWNDT3ZNMWYyblFBY1ZGNUFoSXhueS96TWhmU2l2RXdOQ0Zyd2tBWDRyQVE0WldUNldFakFyUG5jb1Y4Z1VRclhxQVA4NDJmK1lN
WWI5RHFncmFicEg1a3ZuMnQzcWRldGJHODJ0QWlTamhPcUxNYW9iU2F4cXdWa1lUOHRTMW9rUUt2MWZoZ2t6elpEOE5IQnVQQzdNVHdXS0VCS2tDRUUzRWRFMXhNQURLd1B1M3NSaGpSaExXZyszZ2srejJtdlU4cTBhTlc0Y3hObUdoekx4eEY0Q3NFNStMQ1cwOWFpUVJOM1VvWmg1aktBZzBiMlh3WHBLS3pycUVTY1BYdnI0L1dWUTMyMm5qRWRvQVdXR0t2WnBKMlRlREo0eDdiT21LVElFc2RHWU1UZzFVaEU2eFFQcnhqS3dWeGFJNVJyaVE4a0xpaGgwa0t0WHQvYTVsSDhzUjVwR0ZISGZ3dlNVb3liQTB1eUVDNnNRVitPbTVReUZmRmpqZHFCOGNpOGxQS1hLTHFCTHJ6bjNmUkh3TmQwbzFiRTg0aGllTkx5UlhZVmhrRCtFNEpGaVd3ZWt3U3VWM3BjQk9ybnRVU3RoWmx6M3hIUURUVGNJNWliOFJyQ2swZEZ6YTgvQmw3VUdtWlUwSXZ2UmdvVXF2TXNHT2dMY3pGWmRpZnJ5aGNiUTY4a2ZzZ3lCMHppdC9MN1BSV3V4RkdYdDFoTVZSVUZ3WXBJS04zVkI3cXVKZlgwamZsU1JaRndMaXdlK3VhYndmTVZ6c2doajUvOXZNNzcwK0JaMGtJcE45NzBTMG5BbHl6R0h0aW1nTUl1RXFhbUt5QTNTQlI1aHZIYmRyNENnTHFUbXIzbFFnWmpnSkNvN1FXYUJWTXdCR0RpdzVOVVhUUnBycWc4U3h2eDlnNWZwbXMrL0o2QjFEelNTM3ZRZzgxdHFRU1ZDWVJpc0Y3M2VqZlFuZk4zcUszd3RJRDkxQnRISmFvMEFaUUdKVFpKOXVsZ0kzV3hzdWR4ejB0VHVpNlJlSWpmSWsxekZRdFpwRExGMnB3NGpTQVdQTlJqNDBYdVIrRzFUVlI3OVFiME9FYkw4R
DFoTU5zWmo3MTZNbUhSOTlKaUxNdm1FWHV5a1V4VGhGYjRMTzZVbW1kU3UwTlBpMXQ2NmNkYURpQWhMaVBFTGdUNkZsenA2T2FGSGNSNjRncEtyemtTNDJONEhJeFpNa2R6M0FsYkRhK2pOWHZPR1l3UWl5K0xNNENZWGtrTWtHR3ZTWis5R2xWQ0l5RXBJaXIzbEQ3bmdzZGk4emxGWDYvekNaczlQSUtwZFZlSGJGZi9GS20wV3AreHI0Ykd0R0RrVHR2Nk1Manh2YU8zanFHaUFWeERKVWFkTVBlS2VHSm5uempTdnpKbGdOVHV3c3grRnF5L2dPMkwxMGowWmhDWi92dE9NelVjNjl3cGhKZm9FNzU3V3lOeFJOcThJc0Y1Tkg5Y0x0b3UvbUNxOTc3YnZPSkRrSURCN3lKWEJ6YUhVQkJuSXJra1Qyemg3bGJmUm5SREJUSFZraVZMazVESUxqeC9XL1BSZEZpUUM2SzRmZGx4Y29JbzlMcnM4ZFVWZkt2TTNNYnJ6c1hGT3ZtVVh0K3NsZldvd3UyTC9ndG9mRFhvTUJZZnlEcWIvWlRaRWZ0MC83blliRm1relBEUlZacU5SR0F3YWZVNTU1UjB2SWtNbGR2VjdKUzhNT1BNYWlXQVBpelNLRG4yRzNvcys1MzRFQytaOGZnWmFPVWpZL0xLME9vME9RMmhvNUV6MGNMYWpwUjFINk9FNEhvUm1ydjQzZkFjdGpYc0hYdi81RXg3emdrWk1NZXZhTFNEdjZtcjFGcDk4QXR4L296VTFGVDBoMDUxcVcwR0g2VWpRRXk5aExSZDBBMnFkUTRMZXpReDNvbDFTblhsamt2MG4zTXFlaFozOC94bzZhdHFDdkJtQkc3amlUdXd6YnlVUngzRm1TM0NCNllOYnFON3hPYVRZRnlkOEZDL01nY0xGQmMwS3F4MXllQ2VUd1hucldQb0dvdllVQlYxYjA1cWtIa1d5V0RUaC
sveXJFNzF0RjNxbUQvd3F6cUJyNE04NERtWWVuQkdFOWxtb3FIZEMyWnRpK09KVFZKcmlHZWxQQ3RjZnZRaUlQcHdDZ3BFNmg1ekZhRndLajRuZGtBUkRpTC95L1EwWTZxNU5rM1g5RURlTmdjY1pIcFdmOUpKQ3M2a29wdXRtYjdDczIrbVJYdER1S09DaGY5UVUyN3Bmb1NJaklYK3NGdHY1c0hhSms2aHBZMlpzUUhzaTBYbFowc3FMTnQ5ayszdTVnYnBSU1JCczlHaC9BaVY0dkNyYTRkOTh5U0dCdzRSR1FhSStpQ29RaG9YK3lxc3VrYkx6bXJUU3FXMVRXaXJReUlHZ1Q5VnFERE1mUzAxeGdQSlNFSTlIWlp6TGlFVXVGMm1CMi81Y2dqaEFUaWQrdGV1UVB4aldhN2NSc2t5YUhuTENjQURVUU9ESUFPVjJDWXROcnAwY29ZL091S3ZzaXlJT0lacVJ5dE1PMGVNZ1ZJWTBzWmdxeVEycXlubUx0NDBmWmd3SFVyV245Zm9TYTNtMkVRTy9uOS8yU2NuelJWdVZpVnNjM0tCSElQL3AzNlJlSWowTGlNcCtPQ0p3SHlLVW1UeDRBU1V0dXVhWktlRHl1QjlxcXJuUEFNWUVCeElsTGFvdXMzV1pHakIrcW9ub3QvNmk1UE40bUZjbHFDcUxhMGJHbks4ZnJxYy9yd2tuVGV0YUE0c2tXTEw1L21qNEd5MitFQkh3a0x3UXd2K0FKdmZTOXYvNDl1LzY0N1ZFYW15UzdZQ2ZEUHNBQUREQ1FFcWJNQ1h2Ui8xVmEwWi9YUWhoNlkrZUt0MEVpRDdpNmRZODJtQkFoNEJMRmRVV3VGZHVrdUVwaGZ2WXB3N2loVjNxTjB1NFM1NTRXU0dUa0ZsdlpYNG1hbkF4a1g2ekQxS0NWaEFMdEJnSDgzdkhxam9uc0lwOFMydHgwZ0tiYzEreHVaRVppVWlNVVlVdTByQVF
sRFcrZHJoN3lVRHZqekFHSnBmTk01eThaMW45em93VzZ5YW5VZWFBNjhSZDd5TUxobFd0NVh6bGhBTVZDZmZYZ0pFelR1YzJEbENVOXNMLzVTVkRaV2N4R1E5aFM1cnJtK2VyQ1Jxd2FJQk1DNUtza0RCZHdOWmh2Q0FCdEpqS2Vla1FUSjd5MFp4SGNhbGVCaU1rbkYwZVRDZzFvUEhPUVZLQ3V3NE94cHRZUS9xS1V0TEFIWFZ2OTlLMGRWcWZDMmpVQWlHQmVYa0t3aGRYTGtJYlZxU0EyZmxraXBBeEhYNnByUEExQjF3eTVab3hPUFg4RVExOW92eXpBbFg1dHU0OXEwWC9PSExFN1o5T1cxenltRXR6ZFpyNXJZbWtFcVdtcHVSNU5jeHFwTWlZam93dUNXZWhubzIyeG5JM09IQ0xDZkFKaHRrcklhL1hPc0tZRFpCRzFJMGJsN2taR2R5cEtUQlhYdXl6WE5WUlU5L005ejhaVytwdG1oZ2NOUzBJS2VaaSs5bFl4cWRlS3lnbldTTTV3czdSYUpmNlRRZTNSaWJZUjFvNkhwRzB2VHpiTEtQZTZnRjJGODdiWlBJei9mcTNLWnZiM3UrSnhZcCtJVjBtQi9VN29YelhRRk1RK3VmWllpNzUxbkx6WlVxRE1ybU53TFJPVUFNUk8rVnJtblkwSVB1cFBVMXc0b0hBb1dnVGRnTk5pNk1uTFQ4V0pmUlhjT0pKMk1lbUc2K2ZNeHNZUU52UVJwa1RGY05vaFV6Y3ZjcHJ3NUV3WEVZQTJzbzczL2MvY3RIRGcreU05YlF4REppUlltRnFydkhYb29hS1JyekxnUjZLVWdoM3ltaWxaQ0lSSm9KbTE3aEtHM1pxTTE0Lzl5OUc5OE9BZjNkVTlqMDk3aUNlaEc3a2VxYXRJQ2hFWmJqbmQ4Y00rS3djN2FtVWp2ekQzQmNvMHl3MDJxT054OWF3OGhSblZiWDZhdkRJ
bGhySHZ6SU44MzFvUjljRHBwMG1DUEJXZFVDQlNqVGJ1RkZqRC90WElSbGxlT2JraFFKSUdSNlE2U1MxcXkzT29WT1VheFl6THY0U2s3dndrQUMwUitGREVIeVFZbFVhbVVkTWcyUmdwRUdhSVd1V3IxaGNnRm10QmREV2g3ZFBuWTF0U3VKOC95MXp4NkRvN2ZJYmNFenBBK2E0ODNtRG5vemdld3VmaFdqVCsvUS85WlEreFQ5UWJBT1pQSXhHV3VhSXVrVk8zSWxvZDhJM1NGZFJCTHY5ZXBDNzFLeXpSdVlpMktkOHJ5NVNINit1WnMxUHlZUlpRakdDK3Q4VzRtSE82Z1lFRWVXSkJ1UWhnSHdmV2xhZXlWb3hac0NBQVZKRUllT3hPZDZtNW45OHRCUDdHTmgxT1M0eDRCS2FVN1A0UVQzNVVIZW5meE84WWFQUThmbXlobUJhSVJVZklBTVN2ZTJZRFp5SWNNTTkrN0tNSVVabzJ0eXRvYzdCOGVvZzBNaUkrVkpFdFg0c29FRjFSWkhQZVV3NWlCTjI4OTh2MmVTcGNnVUJhWHFzOUN5VlZtTVJQMEtLUDJ1REt4MUdJcUhjS0ZCOXVQVWRkQS9vT3dNa0tVUWsraFZVVDVPbEVMdjd1a0FBUEE0eE4rZkczVmYxeUVKV0FiVGx5dWtGcThjNXBTRkY1cXVHbUgwVmVpQzVvVEFka1VES3Z6WGhWWUs5c3BRYjNVZ1Z0Qld6N1ZScnlOUVVST3BIZU5xeDlhZHA4YWREWCtRSHJUKytYblN4VVI3SVdGanlNTkZJRWlMWmkxdks1UVVrZlRDUU9qdjh2SHdiUi9MRHF3Z3M5bXdsT3pPY0RLdVBVK0dTb2lnVFdRejRWN0N2SHRaVDI3WUdKVG44RFFFM3IzdjB4aWxvODJ2U3VXSDg0WEU3VEJsTUpFb2R5eDNDRngwVUVkc3VhRHBPSEV3UjZYNlUyU0xseERYS
XVZeEhlNXh2NjI4bXU0bDRMSnBYUjhkYmljTEZKQW55Q0FVeDJLb2dDamt1cmU4bXNUZktDbG8wamFlN1hNR05PSk15b0ZYbVlHZUh2eGhNUGMzTEtYLy9VY1p0c3p3dFJrQmNFdURXQysvQWNWZVBOSHVOWWI5MEpIcnRucGg1ZDlhL1lpTkpzY1N3QTFwUVZrdW1TQWtPQWdLdWRzcnl3c0N3Zkg1anNydVpHUTJDd1hKRXQzUU4wU2NLUlVnT1NCQ3FYa1BqZDVSVzJuOFZpamt4anovbWptakhCNmk0eHM5NEU2Nzk5STAyaldYNVd3UDZhTFRaTGt5TjhxNDUxT0RmeUZVZEY5WWsyZXQ5VUpsV1NzRFJMSWVCd0ZyQkEyZTdyRWsybWFLVUNCRW5PUWM2bUhVMXQvZ3gzK1VXVVFXbkpMZVUxbWUvbkFEdy96UGUwd3d0Vm9BaERZdDBoR1hQblJydjFoUHRGS01CeWtqckg3a0J5U0R3WDlQMi9XZkNkQlE5K1J4cHRsR2hvRmdpMUs0NVlOeEpEd05wTmd5MDV2WXUzVUtrMkpRYVNGUzcwK0Y1NzluRE5RenZpK0pPRlRsdDFmWDJGNXk5NEV2NHZobWRQSmRVOFVVRjU2Ymx0emxKREVFdmsySlFrOTM0aHpwTXJGZ1d3ZHUxUkxxSEhCN2h2T2hnaHNqV0ZGY01zNjZaRUtWcVhKUytxWWNVMHk0akwySVQrNlF2N2pvQ3BWbUdzUWtGY1FyblhxOUJiOTdaUS96UCtwaldmWTU0UmNRVlMydUU1YURObVVyVkdLK3E0d0xRcUhuRVViT2puSHFFeGlacUtxOVdRaUtUK2c3QS96bVlIQ2k0YzFTejRNVWhHb0t6U2l4aXoxYUNJUEJXdy9vczR2cUVqbXgzOGx6YnV0OWNWbElzeGNkTUpUTERRK3ZOZ0YyY1ZRaVcxRTQ0d3lWcnI3TUFaOE9KRVpFSzlEZW
t5MzJQUkFuSkRUVXVqdGFscmJ0T2VOczhyS09uTjcvNFRqUEwvZmRlbEI4bjA4WXdSNXdmbU42VGpGWUhRSDFjbUZmK1AvNUxVMTI4Q1pEYjNQUStxMlFJazV3aE40eGwvcy9lb29pallmeWtDcm5aSEhHWkluTGhoU2pWbk5ISWdTL203VWV0NlhBTDdvZUl5UFRLeHVnbDJzRWtUQzNnZ0tjTnFZR0E5U3ZlYVlaQ00vWHNQRUtQbWs3QmlRNmprWFBKaE1yREd4Vkc0SW9aSDgrYjBrUWJYR2l0Mkw0L3hZdHh1bTVzcFNPSjdsTDltVFpRNnBxM2JOaTEwZU1mZ0ZWaDc3NU5JRlc0SEp3U1FtaTU0bk11blZTQjhxdjZKc0w3SGlsZ2N0ZHFSNThTTjVad1lCa2dOR1hzYjA1QXJWemVXbHh1Y21BSHNPT3dyczFnMzh6bTRZN2ZPZmducmFhV1kxanZZOFlEODZQZThkZzR4cE5paTg3UnNDZk5WK2NKVmMraktFdnpuZVY1Zzd0RmlxZCtsZHp4STlKemdSS2t0WUV6RUpRSVU5M2UvclJaN1lrVkZtNVV1cjVhMWYzcG83T0VtYkJUc2MrQ1FaOGNnYmIvbUphRXJoa3NyL3JURjBNcjNxeDl5SlJWSEJ6YWNWd0dScEFRaURPdnJkWU4xQXBVOTRyR1lrVFVzdWs1YjE1Wll2QVZxRlRzVlVMaS9HY29mbEljMm01Z2RFTFZOblRmdXY1Zlk5S1NlWHFoUU80S0pOYVZmbHAwQ0VKYWFFZFNLUXJJNXRaT2w1RkE4VXZlNmxTWVd5TVk0REl4a1RiT1JoWHVBdzR6b1RTMjgrN3d2TXhydVBkZnlKbUJCTkhQdCtEYmdKNHovcHJZWUhpTmFMTXNZamtQZE44ajNKZDczQXJFZk92Um52MzYxSVVVMFg1RDc1dlRSdlpkbzMzWERzanRlOU4weUo3K2lIQnF1a1F
JY2pIVW9ic2RQN0hOajBVYWNSMHIvTmRlVTlGNFBNc1VLY2t6Tk4rZGhyMVI2d1J2R1VZb1pDRWJaWlJMWEt4QnA3SElUNEVQUktHakIvdW1xTFhhMXl6RWx2QW1WQUJhMDFZN3dGdk4wM2Ywb25FbUhTM2w1d1paRmV6cjVibnN5T01XVGxhMU5kaW1ZNXNVeE15VFliZmc4dzB2cXNEc28zWFAxYndLdzZ3M3VIRGQ1UHBSWnVDSnR0eWk0ZzJGeWI0Ymg1UU42ZkdORTI2ekRGN1Y4QmJwZXJLNkFKQ0xTWm5kaDZMMTlPUTBram4xUGpEMGk4c1BZcGFXOWxVeVJkZElPKzRWQS9LemxPUzJ4M2s5VUtUdElsTTBUSVdtZXFIS0dYUVpocGpvVGI2VlNKN203cjZaaVlQMnVsQVVvZmVWL0o2eCtzckxEQXkyQ2ZFNnFrREZ1OU9NWDBBSXVnN3loQUtOMDRyT3hVNk5tcGtjOUZ4bXUvVS9vR3hHdmIzeFVFTDYwdE1sSE9EaWtqY1I5RDJrKzRwbEc1WnV0d0FIY2kwRU02WHRrVEhQOU5QMlRTR1VFN1E5SGYvU0VEc2V0a25hZXhvWmhDczJLWDFMeU5JS0U0N2pkMkR3MTUreDRRVXV0VUFTbzU5Q1lHMVFBeW9BVVhrV3dtbXkzTGdTUWp5T3ZLV25qaE8veWpPd0FyWGd0NFBrSVVnZDQ1N05ReFpMbU41K0J4NVJoQ0FHdkUxYmxOZjlMek9keGJiaG5VZ2Z1RDM5MXVSRkhjS2RYREY3ZmVqb3gveThtaWZJcTRWVzQyajBHQnFOQUtkK0prMnJCMW9hOTRiT2hxcVVzanhqWnlRaGRXTzhNblR6T2tOaGVpZXU2blYxcW5yZ3JHU2huWTNJMlczb29GNFNnczRjZ3drZ2h2dHpFa0xUbU5OUm83RTdudVRuMkxJcmlGSnlvTmZQdUp0aWN0S0JtNzRGZytk
WVBTMlIzTzNmOWxBZWxiVWZjbzZGNU9EL3hkS1VuRTh0V3FOMExVcDlWQUptWVZYZFVDaGJ4MjM4MWtDaStLNDJoRzUydFNQYU1hb1dTb0xQY2Zrb24rc1pYdjdEdEtwZi9HTzdhcUMza1pzRGpva29haHJGZGJWSlNTZWhrNGp5K3RzRHplQnJKSjBrMVZrUnJHN1NoVHZjTmd1cjVucVRUTEE5dlJMQmJNTTlhNlI1NEZ0Z1pQOWFKMU1aMEdCcUVpMnF6Ui8yd2tYQlhwcFhZdi9TcU1RV1dhbTVsSHBMVktxaDN4ZHRjNFdmck9mYldsbU1PNXA5Z0JUSFp1YUcxVGFkZXFRVVpKQmZBS01ENFdSR0NsMDFaeDRTVzE0YzZrdnFKdXExL080N215L3RsVHlLWndpYlBkQTNRMVVGd0I3R2Z4anEwaDN2ckxFbUNrS3Vsc0VBUkN6UnZNVjJSVnBVbFpUV240Y1Boc0hjcTNROElHSUYyKy9nOENFSU4vMU8xcVMvMkpXcXlDNmtIb0w4Y2R2R0VHbmkxSTNDTk1JcXhxaHhJL1V0R3REc2VwYmwrSHI0elh4MzZna3BCbXBoT2xkTFVYTHAzVEtibVVZRWJSWHcvZmRmeFQ3WDdZUFhHQ0hHVG1uTzk4WkxDOTA2Zmkvekd2b04rNlpzbCs3MkpWMGxJWEo0V3dZdWxFUmZHbkFDWGNoa0Yzei9ITWR3elcwTUFFaXptQmwvREo2ZUoyU01PSG1Uc25YbElGRDRlcFRrYnFBQ0dpZ2I1UExFdHdQRVRjYkNRckM5YUtTU1FnSTdEZXd1aWlxM2J0Y0RUWkIzeEI5WWxlbmhpU0FXNjIwcmwzc2ZjY3d3eGFSOHBDV2Rzd0x3dmFxcDhjM01PV3RCc2xPcmVTSkNEcWgvdzBYbm1WMFJVWFpNM2JvUmkwVXhsaHVUeDFlM1NTd09pbTlOczNYV3NoTmI4Lzc3VkhnUWhRV
FlSUU1NRllYaWRmMElCKzBtSUpocWNoQTlUeUY3dGRjSDhrUUJUSHNEWS96bFpqK3EwNlFMd0JkbTkxc3IyK3VzZmxlaXB3WUMrcmdiNHROVnA3VU5rYkVqTnR6ZWZsTi9VRTlkbHZtT2x6V1dtZkh2NGVkUGkzMmJmeUNRS1d6SGJVVEV3NU0yVFpsZnpNaTFWUjVsaDBxQ1lqaDNITUlmL2MwcHBKd2I1b1lFTnBBenlxbnlmdmlTV3lBYzc2L1l1VWwvb2FVaysrYzBZc2d1TGo5ZGFQdVVvemhoZ3VjSytQRGlNckI0ODU1Mk83VWg0aHRwNmZ3S2dJa1JCTVFIUTd6MmV5WXovV1AwQm9ZZVhjOGc3aUprclhFNzA1bFo1bXhGU0poT3E1WlNleVJSb21pUm41K3VRemM5ZFdWQjBYb2JURXdOc0VRM2FIZ25JY29BczY2UGplUT09PC94ZW5jOkNpcGhlclZhbHVlPjwveGVuYzpDaXBoZXJEYXRhPjwveGVuYzpFbmNyeXB0ZWREYXRhPjwvc2FtbDI6RW5jcnlwdGVkQXNzZXJ0aW9uPjwvc2FtbDJwOlJlc3BvbnNlPg==
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/backends/data/saml_response_legacy.txt
new/social-core-4.5.1/social_core/tests/backends/data/saml_response_legacy.txt
---
old/social-core-4.5.0/social_core/tests/backends/data/saml_response_legacy.txt
1970-01-01 01:00:00.000000000 +0100
+++
new/social-core-4.5.1/social_core/tests/backends/data/saml_response_legacy.txt
2023-11-29 09:52:23.000000000 +0100
@@ -0,0 +1 @@
+http://myapp.com/?RelayState=testshib&SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJlc3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBEZXN0aW5hdGlvbj0iaHR0cDovL215YXBwLmNvbSIgSUQ9Il8yNTk2NTFlOTY3ZGIwOGZjYTQ4MjdkODI3YWY1M2RkMCIgSW5SZXNwb25zZVRvPSJURVNUX0lEIiBJc3N1ZUluc3RhbnQ9IjIwMTUtMDUtMDlUMDM6NTc6NDMuNzkyWiIgVmVyc2lvbj0iMi4wIj48c2FtbDI6SXNzdWVyIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI%2BaHR0cHM6Ly9pZHAudGVzdHNoaWIub3JnL2lkcC9zaGliYm9sZXRoPC9zYW1sMjpJc3N1ZXI%2BPHNhbWwycDpTdGF0dXM%2BPHNhbWwycDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz48L3NhbWwycDpTdGF0dXM%2BPHNhbWwyOkVuY3J5cHRlZEFzc2VydGlvbiB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BPHhlbmM6RW5jcnlwdGVkRGF0YSB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiIElkPSJfMGM0NzYzNzIyOWFkNmEzMTY1
OGU0MDc2ZDNlYzBmNmQiIFR5cGU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI0VsZW1lbnQiPjx4ZW5jOkVuY3J5cHRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNhZXMxMjgtY2JjIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiLz48ZHM6S2V5SW5mbyB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI%2BPHhlbmM6RW5jcnlwdGVkS2V5IElkPSJfYjZmNmU2YWZjMzYyNGI3NmM1N2JmOWZhODA5YzAzNmMiIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6RW5jcnlwdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3JzYS1vYWVwLW1nZjFwIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiLz48L3hlbmM6RW5jcnlwdGlvbk1ldGhvZD48ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE%2BPGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDc0RDQ0FobWdBd0lCQWdJSkFPN0J3ZGpEWmNVV01BMEdDU3FHU0liM0RRRUJCUVVBTUVVeEN6QUpCZ05WQkFZVEFrTkJNUmt
3CkZ3WURWUVFJRXhCQ2NtbDBhWE5vSUVOdmJIVnRZbWxoTVJzd0dRWURWUVFLRXhKd2VYUm9iMjR0YzI5amFXRnNMV0YxZEdnd0hoY04KTVRVd05UQTRNRGMxT0RRMldoY05NalV3TlRBM01EYzFPRFEyV2pCRk1Rc3dDUVlEVlFRR0V3SkRRVEVaTUJjR0ExVUVDQk1RUW5KcApkR2x6YUNCRGIyeDFiV0pwWVRFYk1Ca0dBMVVFQ2hNU2NIbDBhRzl1TFhOdlkybGhiQzFoZFhSb01JR2ZNQTBHQ1NxR1NJYjNEUUVCCkFRVUFBNEdOQURDQmlRS0JnUUNxM2cxQ2wrM3VSNXZDbk40SGJnalRnK20zbkhodGVFTXliKyt5Y1pZcmUyYnhVZnNzaEVSNngzM2wKMjN0SGNrUll3bTdNZEJicnAzTHJWb2lPQ2RQYmxUbWwxSWhFUFRDd0tNaEJLdnZXcVR2Z2ZjU1NuUnpBV2tMbFFZU3VzYXl5Wks0bgo5cWNZa1Y1TUZuaTFyYmp4K01yNWFPRW1iNXUzM2FtTUtMd1NUd0lEQVFBQm80R25NSUdrTUIwR0ExVWREZ1FXQkJSUmlCUjZ6UzY2CmZLVm9rcDB5SkhiZ3YzUlltakIxQmdOVkhTTUViakJzZ0JSUmlCUjZ6UzY2ZktWb2twMHlKSGJndjNSWW1xRkpwRWN3UlRFTE1Ba0cKQTFVRUJoTUNRMEV4R1RBWEJnTlZCQWdURUVKeWFYUnBjMmdnUTI5c2RXMWlhV0V4R3pBWkJnTlZCQW9URW5CNWRHaHZiaTF6YjJOcApZV3d0WVhWMGFJSUpBTzdCd2RqRFpjVVdNQXdHQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUp3c01VM1lTCmF5YlZqdUo4VVMwZlVobFBPbE00MFFGQ0dMNHZCM1RFYmIyNE1xOEhyalV3clUwSkZQR2xz
OWEyT1l6TjJCM2UzNU5vck11eHMrZ3IKR3RyMnlQNkx2dVgrblY2QTkzd2I0b29HSG9HZkM3VkxseXhTU25zOTM3U1M1UjFwelE0Z1d6Wm1hMktHV0tJQ1dwaDV6UTBBUlZoTAo2Mzk2N21HTG1vST08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BTElQdkVNVUVGeXhrVHowQ2N4QVA5TjV4Y3NYT2V4aVV4cXBvR2VIeVFMV0R5RVBBUDVnZ1daL3NLZ1ViL2xWSk92bCtuQXhSdVhXUlc5dGxSWWx3R2orRVhIOWhIbmdEY1BWMDNqSUJMQnFJbElBL1RmMGw4cVliOHFKRy9ZM0RTS2RQNkwvUURtYXBtTXpFM29YOEJxMW5Ea3YrUWh4cmQwMGVGK2ZMYVQ0PTwveGVuYzpDaXBoZXJWYWx1ZT48L3hlbmM6Q2lwaGVyRGF0YT48L3hlbmM6RW5jcnlwdGVkS2V5PjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BRVpUWDhHTkM0My9yWStTUVlBMXRudHlUTTVVNkN2dUNCaktsVEVlekZPRjBZZHhCWUdFQVVjYU8xNVNKOXBMemJ1L1h0WGxzTkVMZTdKdEx4RUpwYUxubWFENnIranNWczdLaTBLNHRTMGNBUERDWHV2R1FoMmFOVjVQOGJ3N1JWUGhLOGQwYlJ1RklGR09FOHMwTTZYOUpxWDN4S0MvL1lSbVVoeDlybnU3ZWlwM
Gh5ZitPaUZiVGR2SDY2NTB2LzQ3aVdKcDNZeFlUV0QyMHBNbVRJMUpwWUEwYjByWVFQRkR0RU93d0JxYktxanRJc3ZYVFJzeXJhQkxvbnFOeHN5dHpEWHEra0JsMXp3WGUvSE5QcUVQblczdnNxaFhZcDVGM3dkWThkKzNCOTRMZlpOdUd4a0p3VDNzdVR0OGY5VHRBSlI4VytBUmtzT2M4eDBVaVNsVG5BNHFHOTBLMTR5dkVoVHcvd2drZjFXV01RT3dpZDNpakFYbUV4MU5MbVZvYUxYb3p4VExkTjN6YnJ6VEJIRXc3R2J3ZEdrdU5pMlhZOW16YUgwaWtGRm51VUxjMHUwc0pycEdGdzlaK0VlUk44RzNVUVZ5MjhtS2g3ZFBwWU5KbzhyajIxZFFaK2JaeUtTUHZablU3REkyakdJRE5US1g2ZkVyVWFINGlOTzN4cUU2Vk90L2d4T3BMNE5VNUhLV0Q0bG93VzcwdUJjVEVQRmhwaThpYUovdTB6YzUvTEhvdVBjMzByc1RLZFc5cmJLL2NWaHNQUHErZzA5WHZpZ0QweTJvN2tOc1pVL25tRXFiSzBKOTBrazhCR3I5cXRSczY4bUJnSURtUHVwUkhwWjM4eXNnU2VZN3V0VlVaSG5tQ0dzTzZ2NDJ6OTVOK05Pb3RCTEVZbFd1ZEdzYnowQWc4VkRDSlY5ak95QW95MDZyL1AyUHBsOFhjdmJza2d2T1BMMWdDNnVYbVJJS1lmOEw4UDJCNXVjN0haK0dtUHNOWXRLS2VKRDFFUHovdCt2NlBIbXNVb3dsSDhSd3FMRHdtMUF4dlNLQTR3UXBlQ0dQd3A5YXRYS0lWMS84NUZzRWMzajVzNjd6VlRybThrVEpydXV2MDZEdFVRZDNMOFdwTkV4cWhQait6RUp6U3RxSG04ckhNMVhNQUVxdVozc0xycTVqLzFSNlpqS0dOdFJCbjhwOE5ERGtrWm0vWTV5TXlJNX
JJS3U5bnA3bXdaaEVpeWVHeHdxblV3VVMvUzVDRjNnMHVidnd4eVVnalVvd1ZvTkNqYktBbkdtT2VCSW5abkh0eGdIVUhVOUVlTFdyd2pRc3JtUmpJV0R2RkZQa3l6SzJDL20yaitubmNxc2E1OGRLVXZxcGR1VTRJYnNPQng3UGpXdXRBNmY5bXd6YWxyRU1NK0lGR3VPdk9HMC93eUdzQjZLREV6bldjUC83NkQ4angzaHZFSlAzN3REbFgreGM4Qno5TXdKdkd6VG4xbTdCb2xoR0lzSXlCTys1ZXpXa3RDWVVIUURGVE9wbXA0MDlOWHp6ZUNTUGY1U2NDWG5YYjRPd01ULy9VM1JFUnRRbGMrNmU2WG1JRjhoRkJVc0taUUJsS2ppSDkwZHlzYWlsNmN2V3UyQW55Q3QxbWxXcHFLc0MzU2RTRVZDTG1qRjlUQUFUMEtFSGdZQjg3RjZtZUpTTysvOXkyZkRuYVVvUUlUVzdubnVuSCtkT3dWSGZMU0wyL2N5YTltNlQzR29TSVNMbGJPMVRzalhKclVkZW55OTcvM2tkNmhFQlphdGY1U3NETFQ3SjNsQUVJNDROeXJ0NkIxQWdod2JNdkpqd1JNTXRNdUJLc3ltUytKVzc4UFNEWXQ4MG9waDJQTTc1N0tBNCtUMTAvYnZaQkE5Vk1OdVpqNVV3NXRWMnFIS3dwS0t6ZVVETUFiQlBRaGpYcXlQZzFKa09rd2RQMUpnOHRITjJTelBZQTlmT1htV0pBZGJDS2tMb0F4ZTV6cDZBUzYzS3FXMmFmSUt6SHJ3RTJmS1VtamppeURvMnNuMkJHbWtBaTRzbnpiVzc2SUQvSVgwd044aDBaQ2VRc29vKzdtb1RCMEJxSnBkS1MycXlsUktoc3BSTC9henVQdmxaK1pwckJxdXpJdEZkNFVLMkpzQkp6VXcwZkpxcTV1bk9PZENzVWM3SUU3QTNmZ1NmZ3NBd1R3WFZJMEV
oME5ySWZpMkFKV1Z2VFpEMys2eFZ3dS96WWhuVjc0VXkvMFE4Mi8yQWtpSGpFRjNJVGNLWHdTNTB6bWtLakxjZDJqa2h5TUFYMWRoQ0wwZElFMUJoN0RNamVvNC9YbjBqSlpPL3Rrbi9xZmYzc3RNb1BYVG9KTnBIU1RjR2ZheGtaMzJYNCt3Q0xPc0VBRWxlMVZSY0kwUkZyOFhHTSsxWU9BTjBodFdGcFMxaG9kSi9OczJqL1FnUVNEemNpQ1FZeUFDd3lFRWZDZjZybnR0VmJyTlJQZWlmSHhBM3B2UnZ5ZGRhNDE5cXl0ZXI0akJ3cmw3ZUpuVnJ2VEprR2VhU2FRbDdXWk5SQXBscXRnNnZPYmpiMHZDRWlFaFhKbmNzQUhxcXp5QTRGeWFUVGQ2R0FySU9adUNxRWVoWk51T01lOVlrMVpya0VkR3pIalJESWk3Q1BKQk12NEZ4ZHI3bnJvN0I1WEhKb0ZMNE1DSUtOWWU2aWZiTUtYOU5uN1FWdnphUmY2UXlaSW1BWENQZndvU1BkN2x6NXl3UDJLSUIyaGhFMWt5eVZ5YVc5T0praWpUY3dvUnZrSXhIU0RqMXFqeGxueXh0QzhVZ1pNWmlwcGgzQXJpcjRiekIzUDhIbGIzejZ0OW51KzZMemNiN2ZObVo0UHluaU50Vk9OQ0lHbEh4dTBSY3hQK3cwUXNsM1BtTzJLaHBpc2RIanhvSUJ1YVY1NXdoTlFFNmdNNFBrT0xINDc4Rzg4bUxkd2s2RFpkWVl4L2d6RWE3b3ZIL0pReFp2TzRLdFVTNmZjZHJxV2thTFg1cEhkNkdneFBGZ2NFc2Nad1ZqM2hCS0xFQmE5L0dodERINEhzRnNRbmpPZnNDQkNzN0tjRitmTi9oSUdUeHFqTVlKVHJRYmNtdWF5dk9xR3RQMDFPcXltR24rVm5FSVkzKytQcm95SFN3K0Q0b0JIVG1maFNXRmJLZCtuTlVFS3BhRVIx
NkdCU256WktQRVRVSmdRWEw5QWJRQ3RXVjFHb0UzRWNnMDZYaVd2aHFHakpGNldtdEU4dHY4Q25rZmxMNm91TDRvNldpbmx2WnNEdkZrS0R6TDkwUTNsWC9NanBtRTFpWU9uYzdISXdEVGwraFRRcHdsYXJiTDVUNGNkZTg1akNwYU0xU3p1TStiQU5zMHlXVDA0ZXJUVFc2cnhlbXFDTHAra202TVVMTlZOcE1CazBiQjJpRU82UlRtc3VpRlhDUU1xdU5xZjdkWXUwTFFCZzQ0MkJzU1pBV1ZrWEVZblduOURLdTRSby8veEFsb2h5VHozWlZmSkhuWVBSdDloSUErRHVUL3c4T2ZzTURIWnlCelUvL0JEa1NiNkxjMHdraVA3QlhIdjBoNVdud2dNWUxlZDBPalR5UWI2aGxpVnQ5b0FjaDRFVy9EZUlBdkpaQ1BYVm1pUFFYTGVsOVJIRko2bXFiYVo0TCtaZG1ONmQwcFZNZ1FveXhmQTR3dEwwYVpiNnFZYkhibjJMd2VBQVZwL3M2TzVlMVExdnZpZDRTWHo0a2l3RW1LSStIeXZEQ1pnekpQQVN5Z1gvWDJFWEZ0NGV3SjVmUFQyVXZmWnhQWlpqMFZGSFpyUFQwWVd2VE16bjUva3hoT09oM2drVGdDSmNwNWVsZnp4cEFPNFl1a0NoNHJXdVNndDRqVUJyaWNYbFdWdWo5U3JSZVhUalNHTktLK202NWovUDllNHRHT0RkMk9BbjNKTVQ3Q3FuaDhreTZpZjVjbmpVMmU3UDhTZnBONGwxWEFiZEZEcGk5bVJYamEyTzR1RWFHNGNvNW4xcWNDT3ZNMWYyblFBY1ZGNUFoSXhueS96TWhmU2l2RXdOQ0Zyd2tBWDRyQVE0WldUNldFakFyUG5jb1Y4Z1VRclhxQVA4NDJmK1lNWWI5RHFncmFicEg1a3ZuMnQzcWRldGJHODJ0QWlTamhPcUxNYW9iU2F4cXdWa
1lUOHRTMW9rUUt2MWZoZ2t6elpEOE5IQnVQQzdNVHdXS0VCS2tDRUUzRWRFMXhNQURLd1B1M3NSaGpSaExXZyszZ2srejJtdlU4cTBhTlc0Y3hObUdoekx4eEY0Q3NFNStMQ1cwOWFpUVJOM1VvWmg1aktBZzBiMlh3WHBLS3pycUVTY1BYdnI0L1dWUTMyMm5qRWRvQVdXR0t2WnBKMlRlREo0eDdiT21LVElFc2RHWU1UZzFVaEU2eFFQcnhqS3dWeGFJNVJyaVE4a0xpaGgwa0t0WHQvYTVsSDhzUjVwR0ZISGZ3dlNVb3liQTB1eUVDNnNRVitPbTVReUZmRmpqZHFCOGNpOGxQS1hLTHFCTHJ6bjNmUkh3TmQwbzFiRTg0aGllTkx5UlhZVmhrRCtFNEpGaVd3ZWt3U3VWM3BjQk9ybnRVU3RoWmx6M3hIUURUVGNJNWliOFJyQ2swZEZ6YTgvQmw3VUdtWlUwSXZ2UmdvVXF2TXNHT2dMY3pGWmRpZnJ5aGNiUTY4a2ZzZ3lCMHppdC9MN1BSV3V4RkdYdDFoTVZSVUZ3WXBJS04zVkI3cXVKZlgwamZsU1JaRndMaXdlK3VhYndmTVZ6c2doajUvOXZNNzcwK0JaMGtJcE45NzBTMG5BbHl6R0h0aW1nTUl1RXFhbUt5QTNTQlI1aHZIYmRyNENnTHFUbXIzbFFnWmpnSkNvN1FXYUJWTXdCR0RpdzVOVVhUUnBycWc4U3h2eDlnNWZwbXMrL0o2QjFEelNTM3ZRZzgxdHFRU1ZDWVJpc0Y3M2VqZlFuZk4zcUszd3RJRDkxQnRISmFvMEFaUUdKVFpKOXVsZ0kzV3hzdWR4ejB0VHVpNlJlSWpmSWsxekZRdFpwRExGMnB3NGpTQVdQTlJqNDBYdVIrRzFUVlI3OVFiME9FYkw4RDFoTU5zWmo3MTZNbUhSOTlKaUxNdm1FWHV5a1V4VGhGYjRMTzZVbW1kU3UwTl
BpMXQ2NmNkYURpQWhMaVBFTGdUNkZsenA2T2FGSGNSNjRncEtyemtTNDJONEhJeFpNa2R6M0FsYkRhK2pOWHZPR1l3UWl5K0xNNENZWGtrTWtHR3ZTWis5R2xWQ0l5RXBJaXIzbEQ3bmdzZGk4emxGWDYvekNaczlQSUtwZFZlSGJGZi9GS20wV3AreHI0Ykd0R0RrVHR2Nk1Manh2YU8zanFHaUFWeERKVWFkTVBlS2VHSm5uempTdnpKbGdOVHV3c3grRnF5L2dPMkwxMGowWmhDWi92dE9NelVjNjl3cGhKZm9FNzU3V3lOeFJOcThJc0Y1Tkg5Y0x0b3UvbUNxOTc3YnZPSkRrSURCN3lKWEJ6YUhVQkJuSXJra1Qyemg3bGJmUm5SREJUSFZraVZMazVESUxqeC9XL1BSZEZpUUM2SzRmZGx4Y29JbzlMcnM4ZFVWZkt2TTNNYnJ6c1hGT3ZtVVh0K3NsZldvd3UyTC9ndG9mRFhvTUJZZnlEcWIvWlRaRWZ0MC83blliRm1relBEUlZacU5SR0F3YWZVNTU1UjB2SWtNbGR2VjdKUzhNT1BNYWlXQVBpelNLRG4yRzNvcys1MzRFQytaOGZnWmFPVWpZL0xLME9vME9RMmhvNUV6MGNMYWpwUjFINk9FNEhvUm1ydjQzZkFjdGpYc0hYdi81RXg3emdrWk1NZXZhTFNEdjZtcjFGcDk4QXR4L296VTFGVDBoMDUxcVcwR0g2VWpRRXk5aExSZDBBMnFkUTRMZXpReDNvbDFTblhsamt2MG4zTXFlaFozOC94bzZhdHFDdkJtQkc3amlUdXd6YnlVUngzRm1TM0NCNllOYnFON3hPYVRZRnlkOEZDL01nY0xGQmMwS3F4MXllQ2VUd1hucldQb0dvdllVQlYxYjA1cWtIa1d5V0RUaCsveXJFNzF0RjNxbUQvd3F6cUJyNE04NERtWWVuQkdFOWxtb3FIZEMyWnRpK09
KVFZKcmlHZWxQQ3RjZnZRaUlQcHdDZ3BFNmg1ekZhRndLajRuZGtBUkRpTC95L1EwWTZxNU5rM1g5RURlTmdjY1pIcFdmOUpKQ3M2a29wdXRtYjdDczIrbVJYdER1S09DaGY5UVUyN3Bmb1NJaklYK3NGdHY1c0hhSms2aHBZMlpzUUhzaTBYbFowc3FMTnQ5ayszdTVnYnBSU1JCczlHaC9BaVY0dkNyYTRkOTh5U0dCdzRSR1FhSStpQ29RaG9YK3lxc3VrYkx6bXJUU3FXMVRXaXJReUlHZ1Q5VnFERE1mUzAxeGdQSlNFSTlIWlp6TGlFVXVGMm1CMi81Y2dqaEFUaWQrdGV1UVB4aldhN2NSc2t5YUhuTENjQURVUU9ESUFPVjJDWXROcnAwY29ZL091S3ZzaXlJT0lacVJ5dE1PMGVNZ1ZJWTBzWmdxeVEycXlubUx0NDBmWmd3SFVyV245Zm9TYTNtMkVRTy9uOS8yU2NuelJWdVZpVnNjM0tCSElQL3AzNlJlSWowTGlNcCtPQ0p3SHlLVW1UeDRBU1V0dXVhWktlRHl1QjlxcXJuUEFNWUVCeElsTGFvdXMzV1pHakIrcW9ub3QvNmk1UE40bUZjbHFDcUxhMGJHbks4ZnJxYy9yd2tuVGV0YUE0c2tXTEw1L21qNEd5MitFQkh3a0x3UXd2K0FKdmZTOXYvNDl1LzY0N1ZFYW15UzdZQ2ZEUHNBQUREQ1FFcWJNQ1h2Ui8xVmEwWi9YUWhoNlkrZUt0MEVpRDdpNmRZODJtQkFoNEJMRmRVV3VGZHVrdUVwaGZ2WXB3N2loVjNxTjB1NFM1NTRXU0dUa0ZsdlpYNG1hbkF4a1g2ekQxS0NWaEFMdEJnSDgzdkhxam9uc0lwOFMydHgwZ0tiYzEreHVaRVppVWlNVVlVdTByQVFsRFcrZHJoN3lVRHZqekFHSnBmTk01eThaMW45em93VzZ5YW5VZWFBNjhSZDd5
TUxobFd0NVh6bGhBTVZDZmZYZ0pFelR1YzJEbENVOXNMLzVTVkRaV2N4R1E5aFM1cnJtK2VyQ1Jxd2FJQk1DNUtza0RCZHdOWmh2Q0FCdEpqS2Vla1FUSjd5MFp4SGNhbGVCaU1rbkYwZVRDZzFvUEhPUVZLQ3V3NE94cHRZUS9xS1V0TEFIWFZ2OTlLMGRWcWZDMmpVQWlHQmVYa0t3aGRYTGtJYlZxU0EyZmxraXBBeEhYNnByUEExQjF3eTVab3hPUFg4RVExOW92eXpBbFg1dHU0OXEwWC9PSExFN1o5T1cxenltRXR6ZFpyNXJZbWtFcVdtcHVSNU5jeHFwTWlZam93dUNXZWhubzIyeG5JM09IQ0xDZkFKaHRrcklhL1hPc0tZRFpCRzFJMGJsN2taR2R5cEtUQlhYdXl6WE5WUlU5L005ejhaVytwdG1oZ2NOUzBJS2VaaSs5bFl4cWRlS3lnbldTTTV3czdSYUpmNlRRZTNSaWJZUjFvNkhwRzB2VHpiTEtQZTZnRjJGODdiWlBJei9mcTNLWnZiM3UrSnhZcCtJVjBtQi9VN29YelhRRk1RK3VmWllpNzUxbkx6WlVxRE1ybU53TFJPVUFNUk8rVnJtblkwSVB1cFBVMXc0b0hBb1dnVGRnTk5pNk1uTFQ4V0pmUlhjT0pKMk1lbUc2K2ZNeHNZUU52UVJwa1RGY05vaFV6Y3ZjcHJ3NUV3WEVZQTJzbzczL2MvY3RIRGcreU05YlF4REppUlltRnFydkhYb29hS1JyekxnUjZLVWdoM3ltaWxaQ0lSSm9KbTE3aEtHM1pxTTE0Lzl5OUc5OE9BZjNkVTlqMDk3aUNlaEc3a2VxYXRJQ2hFWmJqbmQ4Y00rS3djN2FtVWp2ekQzQmNvMHl3MDJxT054OWF3OGhSblZiWDZhdkRJbGhySHZ6SU44MzFvUjljRHBwMG1DUEJXZFVDQlNqVGJ1RkZqRC90WElSbGxlT
2JraFFKSUdSNlE2U1MxcXkzT29WT1VheFl6THY0U2s3dndrQUMwUitGREVIeVFZbFVhbVVkTWcyUmdwRUdhSVd1V3IxaGNnRm10QmREV2g3ZFBuWTF0U3VKOC95MXp4NkRvN2ZJYmNFenBBK2E0ODNtRG5vemdld3VmaFdqVCsvUS85WlEreFQ5UWJBT1pQSXhHV3VhSXVrVk8zSWxvZDhJM1NGZFJCTHY5ZXBDNzFLeXpSdVlpMktkOHJ5NVNINit1WnMxUHlZUlpRakdDK3Q4VzRtSE82Z1lFRWVXSkJ1UWhnSHdmV2xhZXlWb3hac0NBQVZKRUllT3hPZDZtNW45OHRCUDdHTmgxT1M0eDRCS2FVN1A0UVQzNVVIZW5meE84WWFQUThmbXlobUJhSVJVZklBTVN2ZTJZRFp5SWNNTTkrN0tNSVVabzJ0eXRvYzdCOGVvZzBNaUkrVkpFdFg0c29FRjFSWkhQZVV3NWlCTjI4OTh2MmVTcGNnVUJhWHFzOUN5VlZtTVJQMEtLUDJ1REt4MUdJcUhjS0ZCOXVQVWRkQS9vT3dNa0tVUWsraFZVVDVPbEVMdjd1a0FBUEE0eE4rZkczVmYxeUVKV0FiVGx5dWtGcThjNXBTRkY1cXVHbUgwVmVpQzVvVEFka1VES3Z6WGhWWUs5c3BRYjNVZ1Z0Qld6N1ZScnlOUVVST3BIZU5xeDlhZHA4YWREWCtRSHJUKytYblN4VVI3SVdGanlNTkZJRWlMWmkxdks1UVVrZlRDUU9qdjh2SHdiUi9MRHF3Z3M5bXdsT3pPY0RLdVBVK0dTb2lnVFdRejRWN0N2SHRaVDI3WUdKVG44RFFFM3IzdjB4aWxvODJ2U3VXSDg0WEU3VEJsTUpFb2R5eDNDRngwVUVkc3VhRHBPSEV3UjZYNlUyU0xseERYSXVZeEhlNXh2NjI4bXU0bDRMSnBYUjhkYmljTEZKQW55Q0FVeDJLb2dDamt1cm
U4bXNUZktDbG8wamFlN1hNR05PSk15b0ZYbVlHZUh2eGhNUGMzTEtYLy9VY1p0c3p3dFJrQmNFdURXQysvQWNWZVBOSHVOWWI5MEpIcnRucGg1ZDlhL1lpTkpzY1N3QTFwUVZrdW1TQWtPQWdLdWRzcnl3c0N3Zkg1anNydVpHUTJDd1hKRXQzUU4wU2NLUlVnT1NCQ3FYa1BqZDVSVzJuOFZpamt4anovbWptakhCNmk0eHM5NEU2Nzk5STAyaldYNVd3UDZhTFRaTGt5TjhxNDUxT0RmeUZVZEY5WWsyZXQ5VUpsV1NzRFJMSWVCd0ZyQkEyZTdyRWsybWFLVUNCRW5PUWM2bUhVMXQvZ3gzK1VXVVFXbkpMZVUxbWUvbkFEdy96UGUwd3d0Vm9BaERZdDBoR1hQblJydjFoUHRGS01CeWtqckg3a0J5U0R3WDlQMi9XZkNkQlE5K1J4cHRsR2hvRmdpMUs0NVlOeEpEd05wTmd5MDV2WXUzVUtrMkpRYVNGUzcwK0Y1NzluRE5RenZpK0pPRlRsdDFmWDJGNXk5NEV2NHZobWRQSmRVOFVVRjU2Ymx0emxKREVFdmsySlFrOTM0aHpwTXJGZ1d3ZHUxUkxxSEhCN2h2T2hnaHNqV0ZGY01zNjZaRUtWcVhKUytxWWNVMHk0akwySVQrNlF2N2pvQ3BWbUdzUWtGY1FyblhxOUJiOTdaUS96UCtwaldmWTU0UmNRVlMydUU1YURObVVyVkdLK3E0d0xRcUhuRVViT2puSHFFeGlacUtxOVdRaUtUK2c3QS96bVlIQ2k0YzFTejRNVWhHb0t6U2l4aXoxYUNJUEJXdy9vczR2cUVqbXgzOGx6YnV0OWNWbElzeGNkTUpUTERRK3ZOZ0YyY1ZRaVcxRTQ0d3lWcnI3TUFaOE9KRVpFSzlEZWt5MzJQUkFuSkRUVXVqdGFscmJ0T2VOczhyS09uTjcvNFRqUEwvZmRlbEI4bjA
4WXdSNXdmbU42VGpGWUhRSDFjbUZmK1AvNUxVMTI4Q1pEYjNQUStxMlFJazV3aE40eGwvcy9lb29pallmeWtDcm5aSEhHWkluTGhoU2pWbk5ISWdTL203VWV0NlhBTDdvZUl5UFRLeHVnbDJzRWtUQzNnZ0tjTnFZR0E5U3ZlYVlaQ00vWHNQRUtQbWs3QmlRNmprWFBKaE1yREd4Vkc0SW9aSDgrYjBrUWJYR2l0Mkw0L3hZdHh1bTVzcFNPSjdsTDltVFpRNnBxM2JOaTEwZU1mZ0ZWaDc3NU5JRlc0SEp3U1FtaTU0bk11blZTQjhxdjZKc0w3SGlsZ2N0ZHFSNThTTjVad1lCa2dOR1hzYjA1QXJWemVXbHh1Y21BSHNPT3dyczFnMzh6bTRZN2ZPZmducmFhV1kxanZZOFlEODZQZThkZzR4cE5paTg3UnNDZk5WK2NKVmMraktFdnpuZVY1Zzd0RmlxZCtsZHp4STlKemdSS2t0WUV6RUpRSVU5M2UvclJaN1lrVkZtNVV1cjVhMWYzcG83T0VtYkJUc2MrQ1FaOGNnYmIvbUphRXJoa3NyL3JURjBNcjNxeDl5SlJWSEJ6YWNWd0dScEFRaURPdnJkWU4xQXBVOTRyR1lrVFVzdWs1YjE1Wll2QVZxRlRzVlVMaS9HY29mbEljMm01Z2RFTFZOblRmdXY1Zlk5S1NlWHFoUU80S0pOYVZmbHAwQ0VKYWFFZFNLUXJJNXRaT2w1RkE4VXZlNmxTWVd5TVk0REl4a1RiT1JoWHVBdzR6b1RTMjgrN3d2TXhydVBkZnlKbUJCTkhQdCtEYmdKNHovcHJZWUhpTmFMTXNZamtQZE44ajNKZDczQXJFZk92Um52MzYxSVVVMFg1RDc1dlRSdlpkbzMzWERzanRlOU4weUo3K2lIQnF1a1FJY2pIVW9ic2RQN0hOajBVYWNSMHIvTmRlVTlGNFBNc1VLY2t6Tk4rZGhyMVI2
d1J2R1VZb1pDRWJaWlJMWEt4QnA3SElUNEVQUktHakIvdW1xTFhhMXl6RWx2QW1WQUJhMDFZN3dGdk4wM2Ywb25FbUhTM2w1d1paRmV6cjVibnN5T01XVGxhMU5kaW1ZNXNVeE15VFliZmc4dzB2cXNEc28zWFAxYndLdzZ3M3VIRGQ1UHBSWnVDSnR0eWk0ZzJGeWI0Ymg1UU42ZkdORTI2ekRGN1Y4QmJwZXJLNkFKQ0xTWm5kaDZMMTlPUTBram4xUGpEMGk4c1BZcGFXOWxVeVJkZElPKzRWQS9LemxPUzJ4M2s5VUtUdElsTTBUSVdtZXFIS0dYUVpocGpvVGI2VlNKN203cjZaaVlQMnVsQVVvZmVWL0o2eCtzckxEQXkyQ2ZFNnFrREZ1OU9NWDBBSXVnN3loQUtOMDRyT3hVNk5tcGtjOUZ4bXUvVS9vR3hHdmIzeFVFTDYwdE1sSE9EaWtqY1I5RDJrKzRwbEc1WnV0d0FIY2kwRU02WHRrVEhQOU5QMlRTR1VFN1E5SGYvU0VEc2V0a25hZXhvWmhDczJLWDFMeU5JS0U0N2pkMkR3MTUreDRRVXV0VUFTbzU5Q1lHMVFBeW9BVVhrV3dtbXkzTGdTUWp5T3ZLV25qaE8veWpPd0FyWGd0NFBrSVVnZDQ1N05ReFpMbU41K0J4NVJoQ0FHdkUxYmxOZjlMek9keGJiaG5VZ2Z1RDM5MXVSRkhjS2RYREY3ZmVqb3gveThtaWZJcTRWVzQyajBHQnFOQUtkK0prMnJCMW9hOTRiT2hxcVVzanhqWnlRaGRXTzhNblR6T2tOaGVpZXU2blYxcW5yZ3JHU2huWTNJMlczb29GNFNnczRjZ3drZ2h2dHpFa0xUbU5OUm83RTdudVRuMkxJcmlGSnlvTmZQdUp0aWN0S0JtNzRGZytkWVBTMlIzTzNmOWxBZWxiVWZjbzZGNU9EL3hkS1VuRTh0V3FOMExVcDlWQUptW
VZYZFVDaGJ4MjM4MWtDaStLNDJoRzUydFNQYU1hb1dTb0xQY2Zrb24rc1pYdjdEdEtwZi9HTzdhcUMza1pzRGpva29haHJGZGJWSlNTZWhrNGp5K3RzRHplQnJKSjBrMVZrUnJHN1NoVHZjTmd1cjVucVRUTEE5dlJMQmJNTTlhNlI1NEZ0Z1pQOWFKMU1aMEdCcUVpMnF6Ui8yd2tYQlhwcFhZdi9TcU1RV1dhbTVsSHBMVktxaDN4ZHRjNFdmck9mYldsbU1PNXA5Z0JUSFp1YUcxVGFkZXFRVVpKQmZBS01ENFdSR0NsMDFaeDRTVzE0YzZrdnFKdXExL080N215L3RsVHlLWndpYlBkQTNRMVVGd0I3R2Z4anEwaDN2ckxFbUNrS3Vsc0VBUkN6UnZNVjJSVnBVbFpUV240Y1Boc0hjcTNROElHSUYyKy9nOENFSU4vMU8xcVMvMkpXcXlDNmtIb0w4Y2R2R0VHbmkxSTNDTk1JcXhxaHhJL1V0R3REc2VwYmwrSHI0elh4MzZna3BCbXBoT2xkTFVYTHAzVEtibVVZRWJSWHcvZmRmeFQ3WDdZUFhHQ0hHVG1uTzk4WkxDOTA2Zmkvekd2b04rNlpzbCs3MkpWMGxJWEo0V3dZdWxFUmZHbkFDWGNoa0Yzei9ITWR3elcwTUFFaXptQmwvREo2ZUoyU01PSG1Uc25YbElGRDRlcFRrYnFBQ0dpZ2I1UExFdHdQRVRjYkNRckM5YUtTU1FnSTdEZXd1aWlxM2J0Y0RUWkIzeEI5WWxlbmhpU0FXNjIwcmwzc2ZjY3d3eGFSOHBDV2Rzd0x3dmFxcDhjM01PV3RCc2xPcmVTSkNEcWgvdzBYbm1WMFJVWFpNM2JvUmkwVXhsaHVUeDFlM1NTd09pbTlOczNYV3NoTmI4Lzc3VkhnUWhRVFlSUU1NRllYaWRmMElCKzBtSUpocWNoQTlUeUY3dGRjSDhrUUJUSHNEWS96bF
pqK3EwNlFMd0JkbTkxc3IyK3VzZmxlaXB3WUMrcmdiNHROVnA3VU5rYkVqTnR6ZWZsTi9VRTlkbHZtT2x6V1dtZkh2NGVkUGkzMmJmeUNRS1d6SGJVVEV3NU0yVFpsZnpNaTFWUjVsaDBxQ1lqaDNITUlmL2MwcHBKd2I1b1lFTnBBenlxbnlmdmlTV3lBYzc2L1l1VWwvb2FVaysrYzBZc2d1TGo5ZGFQdVVvemhoZ3VjSytQRGlNckI0ODU1Mk83VWg0aHRwNmZ3S2dJa1JCTVFIUTd6MmV5WXovV1AwQm9ZZVhjOGc3aUprclhFNzA1bFo1bXhGU0poT3E1WlNleVJSb21pUm41K3VRemM5ZFdWQjBYb2JURXdOc0VRM2FIZ25JY29BczY2UGplUT09PC94ZW5jOkNpcGhlclZhbHVlPjwveGVuYzpDaXBoZXJEYXRhPjwveGVuYzpFbmNyeXB0ZWREYXRhPjwvc2FtbDI6RW5jcnlwdGVkQXNzZXJ0aW9uPjwvc2FtbDJwOlJlc3BvbnNlPg==
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/backends/data/saml_response_no_idp_name.txt
new/social-core-4.5.1/social_core/tests/backends/data/saml_response_no_idp_name.txt
---
old/social-core-4.5.0/social_core/tests/backends/data/saml_response_no_idp_name.txt
1970-01-01 01:00:00.000000000 +0100
+++
new/social-core-4.5.1/social_core/tests/backends/data/saml_response_no_idp_name.txt
2023-11-29 09:52:23.000000000 +0100
@@ -0,0 +1 @@
+http://myapp.com/?RelayState=%7b%7d&SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJlc3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBEZXN0aW5hdGlvbj0iaHR0cDovL215YXBwLmNvbSIgSUQ9Il8yNTk2NTFlOTY3ZGIwOGZjYTQ4MjdkODI3YWY1M2RkMCIgSW5SZXNwb25zZVRvPSJURVNUX0lEIiBJc3N1ZUluc3RhbnQ9IjIwMTUtMDUtMDlUMDM6NTc6NDMuNzkyWiIgVmVyc2lvbj0iMi4wIj48c2FtbDI6SXNzdWVyIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI%2BaHR0cHM6Ly9pZHAudGVzdHNoaWIub3JnL2lkcC9zaGliYm9sZXRoPC9zYW1sMjpJc3N1ZXI%2BPHNhbWwycDpTdGF0dXM%2BPHNhbWwycDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz48L3NhbWwycDpTdGF0dXM%2BPHNhbWwyOkVuY3J5cHRlZEFzc2VydGlvbiB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BPHhlbmM6RW5jcnlwdGVkRGF0YSB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiIElkPSJfMGM0NzYzNzIyOWFkNmEzMTY1OG
U0MDc2ZDNlYzBmNmQiIFR5cGU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI0VsZW1lbnQiPjx4ZW5jOkVuY3J5cHRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNhZXMxMjgtY2JjIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiLz48ZHM6S2V5SW5mbyB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI%2BPHhlbmM6RW5jcnlwdGVkS2V5IElkPSJfYjZmNmU2YWZjMzYyNGI3NmM1N2JmOWZhODA5YzAzNmMiIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6RW5jcnlwdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3JzYS1vYWVwLW1nZjFwIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiLz48L3hlbmM6RW5jcnlwdGlvbk1ldGhvZD48ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE%2BPGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDc0RDQ0FobWdBd0lCQWdJSkFPN0J3ZGpEWmNVV01BMEdDU3FHU0liM0RRRUJCUVVBTUVVeEN6QUpCZ05WQkFZVEFrTkJNUmt3C
kZ3WURWUVFJRXhCQ2NtbDBhWE5vSUVOdmJIVnRZbWxoTVJzd0dRWURWUVFLRXhKd2VYUm9iMjR0YzI5amFXRnNMV0YxZEdnd0hoY04KTVRVd05UQTRNRGMxT0RRMldoY05NalV3TlRBM01EYzFPRFEyV2pCRk1Rc3dDUVlEVlFRR0V3SkRRVEVaTUJjR0ExVUVDQk1RUW5KcApkR2x6YUNCRGIyeDFiV0pwWVRFYk1Ca0dBMVVFQ2hNU2NIbDBhRzl1TFhOdlkybGhiQzFoZFhSb01JR2ZNQTBHQ1NxR1NJYjNEUUVCCkFRVUFBNEdOQURDQmlRS0JnUUNxM2cxQ2wrM3VSNXZDbk40SGJnalRnK20zbkhodGVFTXliKyt5Y1pZcmUyYnhVZnNzaEVSNngzM2wKMjN0SGNrUll3bTdNZEJicnAzTHJWb2lPQ2RQYmxUbWwxSWhFUFRDd0tNaEJLdnZXcVR2Z2ZjU1NuUnpBV2tMbFFZU3VzYXl5Wks0bgo5cWNZa1Y1TUZuaTFyYmp4K01yNWFPRW1iNXUzM2FtTUtMd1NUd0lEQVFBQm80R25NSUdrTUIwR0ExVWREZ1FXQkJSUmlCUjZ6UzY2CmZLVm9rcDB5SkhiZ3YzUlltakIxQmdOVkhTTUViakJzZ0JSUmlCUjZ6UzY2ZktWb2twMHlKSGJndjNSWW1xRkpwRWN3UlRFTE1Ba0cKQTFVRUJoTUNRMEV4R1RBWEJnTlZCQWdURUVKeWFYUnBjMmdnUTI5c2RXMWlhV0V4R3pBWkJnTlZCQW9URW5CNWRHaHZiaTF6YjJOcApZV3d0WVhWMGFJSUpBTzdCd2RqRFpjVVdNQXdHQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUp3c01VM1lTCmF5YlZqdUo4VVMwZlVobFBPbE00MFFGQ0dMNHZCM1RFYmIyNE1xOEhyalV3clUwSkZQR2xzOW
EyT1l6TjJCM2UzNU5vck11eHMrZ3IKR3RyMnlQNkx2dVgrblY2QTkzd2I0b29HSG9HZkM3VkxseXhTU25zOTM3U1M1UjFwelE0Z1d6Wm1hMktHV0tJQ1dwaDV6UTBBUlZoTAo2Mzk2N21HTG1vST08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BTElQdkVNVUVGeXhrVHowQ2N4QVA5TjV4Y3NYT2V4aVV4cXBvR2VIeVFMV0R5RVBBUDVnZ1daL3NLZ1ViL2xWSk92bCtuQXhSdVhXUlc5dGxSWWx3R2orRVhIOWhIbmdEY1BWMDNqSUJMQnFJbElBL1RmMGw4cVliOHFKRy9ZM0RTS2RQNkwvUURtYXBtTXpFM29YOEJxMW5Ea3YrUWh4cmQwMGVGK2ZMYVQ0PTwveGVuYzpDaXBoZXJWYWx1ZT48L3hlbmM6Q2lwaGVyRGF0YT48L3hlbmM6RW5jcnlwdGVkS2V5PjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BRVpUWDhHTkM0My9yWStTUVlBMXRudHlUTTVVNkN2dUNCaktsVEVlekZPRjBZZHhCWUdFQVVjYU8xNVNKOXBMemJ1L1h0WGxzTkVMZTdKdEx4RUpwYUxubWFENnIranNWczdLaTBLNHRTMGNBUERDWHV2R1FoMmFOVjVQOGJ3N1JWUGhLOGQwYlJ1RklGR09FOHMwTTZYOUpxWDN4S0MvL1lSbVVoeDlybnU3ZWlwMGh
5ZitPaUZiVGR2SDY2NTB2LzQ3aVdKcDNZeFlUV0QyMHBNbVRJMUpwWUEwYjByWVFQRkR0RU93d0JxYktxanRJc3ZYVFJzeXJhQkxvbnFOeHN5dHpEWHEra0JsMXp3WGUvSE5QcUVQblczdnNxaFhZcDVGM3dkWThkKzNCOTRMZlpOdUd4a0p3VDNzdVR0OGY5VHRBSlI4VytBUmtzT2M4eDBVaVNsVG5BNHFHOTBLMTR5dkVoVHcvd2drZjFXV01RT3dpZDNpakFYbUV4MU5MbVZvYUxYb3p4VExkTjN6YnJ6VEJIRXc3R2J3ZEdrdU5pMlhZOW16YUgwaWtGRm51VUxjMHUwc0pycEdGdzlaK0VlUk44RzNVUVZ5MjhtS2g3ZFBwWU5KbzhyajIxZFFaK2JaeUtTUHZablU3REkyakdJRE5US1g2ZkVyVWFINGlOTzN4cUU2Vk90L2d4T3BMNE5VNUhLV0Q0bG93VzcwdUJjVEVQRmhwaThpYUovdTB6YzUvTEhvdVBjMzByc1RLZFc5cmJLL2NWaHNQUHErZzA5WHZpZ0QweTJvN2tOc1pVL25tRXFiSzBKOTBrazhCR3I5cXRSczY4bUJnSURtUHVwUkhwWjM4eXNnU2VZN3V0VlVaSG5tQ0dzTzZ2NDJ6OTVOK05Pb3RCTEVZbFd1ZEdzYnowQWc4VkRDSlY5ak95QW95MDZyL1AyUHBsOFhjdmJza2d2T1BMMWdDNnVYbVJJS1lmOEw4UDJCNXVjN0haK0dtUHNOWXRLS2VKRDFFUHovdCt2NlBIbXNVb3dsSDhSd3FMRHdtMUF4dlNLQTR3UXBlQ0dQd3A5YXRYS0lWMS84NUZzRWMzajVzNjd6VlRybThrVEpydXV2MDZEdFVRZDNMOFdwTkV4cWhQait6RUp6U3RxSG04ckhNMVhNQUVxdVozc0xycTVqLzFSNlpqS0dOdFJCbjhwOE5ERGtrWm0vWTV5TXlJNXJJ
S3U5bnA3bXdaaEVpeWVHeHdxblV3VVMvUzVDRjNnMHVidnd4eVVnalVvd1ZvTkNqYktBbkdtT2VCSW5abkh0eGdIVUhVOUVlTFdyd2pRc3JtUmpJV0R2RkZQa3l6SzJDL20yaitubmNxc2E1OGRLVXZxcGR1VTRJYnNPQng3UGpXdXRBNmY5bXd6YWxyRU1NK0lGR3VPdk9HMC93eUdzQjZLREV6bldjUC83NkQ4angzaHZFSlAzN3REbFgreGM4Qno5TXdKdkd6VG4xbTdCb2xoR0lzSXlCTys1ZXpXa3RDWVVIUURGVE9wbXA0MDlOWHp6ZUNTUGY1U2NDWG5YYjRPd01ULy9VM1JFUnRRbGMrNmU2WG1JRjhoRkJVc0taUUJsS2ppSDkwZHlzYWlsNmN2V3UyQW55Q3QxbWxXcHFLc0MzU2RTRVZDTG1qRjlUQUFUMEtFSGdZQjg3RjZtZUpTTysvOXkyZkRuYVVvUUlUVzdubnVuSCtkT3dWSGZMU0wyL2N5YTltNlQzR29TSVNMbGJPMVRzalhKclVkZW55OTcvM2tkNmhFQlphdGY1U3NETFQ3SjNsQUVJNDROeXJ0NkIxQWdod2JNdkpqd1JNTXRNdUJLc3ltUytKVzc4UFNEWXQ4MG9waDJQTTc1N0tBNCtUMTAvYnZaQkE5Vk1OdVpqNVV3NXRWMnFIS3dwS0t6ZVVETUFiQlBRaGpYcXlQZzFKa09rd2RQMUpnOHRITjJTelBZQTlmT1htV0pBZGJDS2tMb0F4ZTV6cDZBUzYzS3FXMmFmSUt6SHJ3RTJmS1VtamppeURvMnNuMkJHbWtBaTRzbnpiVzc2SUQvSVgwd044aDBaQ2VRc29vKzdtb1RCMEJxSnBkS1MycXlsUktoc3BSTC9henVQdmxaK1pwckJxdXpJdEZkNFVLMkpzQkp6VXcwZkpxcTV1bk9PZENzVWM3SUU3QTNmZ1NmZ3NBd1R3WFZJMEVoM
E5ySWZpMkFKV1Z2VFpEMys2eFZ3dS96WWhuVjc0VXkvMFE4Mi8yQWtpSGpFRjNJVGNLWHdTNTB6bWtLakxjZDJqa2h5TUFYMWRoQ0wwZElFMUJoN0RNamVvNC9YbjBqSlpPL3Rrbi9xZmYzc3RNb1BYVG9KTnBIU1RjR2ZheGtaMzJYNCt3Q0xPc0VBRWxlMVZSY0kwUkZyOFhHTSsxWU9BTjBodFdGcFMxaG9kSi9OczJqL1FnUVNEemNpQ1FZeUFDd3lFRWZDZjZybnR0VmJyTlJQZWlmSHhBM3B2UnZ5ZGRhNDE5cXl0ZXI0akJ3cmw3ZUpuVnJ2VEprR2VhU2FRbDdXWk5SQXBscXRnNnZPYmpiMHZDRWlFaFhKbmNzQUhxcXp5QTRGeWFUVGQ2R0FySU9adUNxRWVoWk51T01lOVlrMVpya0VkR3pIalJESWk3Q1BKQk12NEZ4ZHI3bnJvN0I1WEhKb0ZMNE1DSUtOWWU2aWZiTUtYOU5uN1FWdnphUmY2UXlaSW1BWENQZndvU1BkN2x6NXl3UDJLSUIyaGhFMWt5eVZ5YVc5T0praWpUY3dvUnZrSXhIU0RqMXFqeGxueXh0QzhVZ1pNWmlwcGgzQXJpcjRiekIzUDhIbGIzejZ0OW51KzZMemNiN2ZObVo0UHluaU50Vk9OQ0lHbEh4dTBSY3hQK3cwUXNsM1BtTzJLaHBpc2RIanhvSUJ1YVY1NXdoTlFFNmdNNFBrT0xINDc4Rzg4bUxkd2s2RFpkWVl4L2d6RWE3b3ZIL0pReFp2TzRLdFVTNmZjZHJxV2thTFg1cEhkNkdneFBGZ2NFc2Nad1ZqM2hCS0xFQmE5L0dodERINEhzRnNRbmpPZnNDQkNzN0tjRitmTi9oSUdUeHFqTVlKVHJRYmNtdWF5dk9xR3RQMDFPcXltR24rVm5FSVkzKytQcm95SFN3K0Q0b0JIVG1maFNXRmJLZCtuTlVFS3BhRVIxNk
dCU256WktQRVRVSmdRWEw5QWJRQ3RXVjFHb0UzRWNnMDZYaVd2aHFHakpGNldtdEU4dHY4Q25rZmxMNm91TDRvNldpbmx2WnNEdkZrS0R6TDkwUTNsWC9NanBtRTFpWU9uYzdISXdEVGwraFRRcHdsYXJiTDVUNGNkZTg1akNwYU0xU3p1TStiQU5zMHlXVDA0ZXJUVFc2cnhlbXFDTHAra202TVVMTlZOcE1CazBiQjJpRU82UlRtc3VpRlhDUU1xdU5xZjdkWXUwTFFCZzQ0MkJzU1pBV1ZrWEVZblduOURLdTRSby8veEFsb2h5VHozWlZmSkhuWVBSdDloSUErRHVUL3c4T2ZzTURIWnlCelUvL0JEa1NiNkxjMHdraVA3QlhIdjBoNVdud2dNWUxlZDBPalR5UWI2aGxpVnQ5b0FjaDRFVy9EZUlBdkpaQ1BYVm1pUFFYTGVsOVJIRko2bXFiYVo0TCtaZG1ONmQwcFZNZ1FveXhmQTR3dEwwYVpiNnFZYkhibjJMd2VBQVZwL3M2TzVlMVExdnZpZDRTWHo0a2l3RW1LSStIeXZEQ1pnekpQQVN5Z1gvWDJFWEZ0NGV3SjVmUFQyVXZmWnhQWlpqMFZGSFpyUFQwWVd2VE16bjUva3hoT09oM2drVGdDSmNwNWVsZnp4cEFPNFl1a0NoNHJXdVNndDRqVUJyaWNYbFdWdWo5U3JSZVhUalNHTktLK202NWovUDllNHRHT0RkMk9BbjNKTVQ3Q3FuaDhreTZpZjVjbmpVMmU3UDhTZnBONGwxWEFiZEZEcGk5bVJYamEyTzR1RWFHNGNvNW4xcWNDT3ZNMWYyblFBY1ZGNUFoSXhueS96TWhmU2l2RXdOQ0Zyd2tBWDRyQVE0WldUNldFakFyUG5jb1Y4Z1VRclhxQVA4NDJmK1lNWWI5RHFncmFicEg1a3ZuMnQzcWRldGJHODJ0QWlTamhPcUxNYW9iU2F4cXdWa1l
UOHRTMW9rUUt2MWZoZ2t6elpEOE5IQnVQQzdNVHdXS0VCS2tDRUUzRWRFMXhNQURLd1B1M3NSaGpSaExXZyszZ2srejJtdlU4cTBhTlc0Y3hObUdoekx4eEY0Q3NFNStMQ1cwOWFpUVJOM1VvWmg1aktBZzBiMlh3WHBLS3pycUVTY1BYdnI0L1dWUTMyMm5qRWRvQVdXR0t2WnBKMlRlREo0eDdiT21LVElFc2RHWU1UZzFVaEU2eFFQcnhqS3dWeGFJNVJyaVE4a0xpaGgwa0t0WHQvYTVsSDhzUjVwR0ZISGZ3dlNVb3liQTB1eUVDNnNRVitPbTVReUZmRmpqZHFCOGNpOGxQS1hLTHFCTHJ6bjNmUkh3TmQwbzFiRTg0aGllTkx5UlhZVmhrRCtFNEpGaVd3ZWt3U3VWM3BjQk9ybnRVU3RoWmx6M3hIUURUVGNJNWliOFJyQ2swZEZ6YTgvQmw3VUdtWlUwSXZ2UmdvVXF2TXNHT2dMY3pGWmRpZnJ5aGNiUTY4a2ZzZ3lCMHppdC9MN1BSV3V4RkdYdDFoTVZSVUZ3WXBJS04zVkI3cXVKZlgwamZsU1JaRndMaXdlK3VhYndmTVZ6c2doajUvOXZNNzcwK0JaMGtJcE45NzBTMG5BbHl6R0h0aW1nTUl1RXFhbUt5QTNTQlI1aHZIYmRyNENnTHFUbXIzbFFnWmpnSkNvN1FXYUJWTXdCR0RpdzVOVVhUUnBycWc4U3h2eDlnNWZwbXMrL0o2QjFEelNTM3ZRZzgxdHFRU1ZDWVJpc0Y3M2VqZlFuZk4zcUszd3RJRDkxQnRISmFvMEFaUUdKVFpKOXVsZ0kzV3hzdWR4ejB0VHVpNlJlSWpmSWsxekZRdFpwRExGMnB3NGpTQVdQTlJqNDBYdVIrRzFUVlI3OVFiME9FYkw4RDFoTU5zWmo3MTZNbUhSOTlKaUxNdm1FWHV5a1V4VGhGYjRMTzZVbW1kU3UwTlBp
MXQ2NmNkYURpQWhMaVBFTGdUNkZsenA2T2FGSGNSNjRncEtyemtTNDJONEhJeFpNa2R6M0FsYkRhK2pOWHZPR1l3UWl5K0xNNENZWGtrTWtHR3ZTWis5R2xWQ0l5RXBJaXIzbEQ3bmdzZGk4emxGWDYvekNaczlQSUtwZFZlSGJGZi9GS20wV3AreHI0Ykd0R0RrVHR2Nk1Manh2YU8zanFHaUFWeERKVWFkTVBlS2VHSm5uempTdnpKbGdOVHV3c3grRnF5L2dPMkwxMGowWmhDWi92dE9NelVjNjl3cGhKZm9FNzU3V3lOeFJOcThJc0Y1Tkg5Y0x0b3UvbUNxOTc3YnZPSkRrSURCN3lKWEJ6YUhVQkJuSXJra1Qyemg3bGJmUm5SREJUSFZraVZMazVESUxqeC9XL1BSZEZpUUM2SzRmZGx4Y29JbzlMcnM4ZFVWZkt2TTNNYnJ6c1hGT3ZtVVh0K3NsZldvd3UyTC9ndG9mRFhvTUJZZnlEcWIvWlRaRWZ0MC83blliRm1relBEUlZacU5SR0F3YWZVNTU1UjB2SWtNbGR2VjdKUzhNT1BNYWlXQVBpelNLRG4yRzNvcys1MzRFQytaOGZnWmFPVWpZL0xLME9vME9RMmhvNUV6MGNMYWpwUjFINk9FNEhvUm1ydjQzZkFjdGpYc0hYdi81RXg3emdrWk1NZXZhTFNEdjZtcjFGcDk4QXR4L296VTFGVDBoMDUxcVcwR0g2VWpRRXk5aExSZDBBMnFkUTRMZXpReDNvbDFTblhsamt2MG4zTXFlaFozOC94bzZhdHFDdkJtQkc3amlUdXd6YnlVUngzRm1TM0NCNllOYnFON3hPYVRZRnlkOEZDL01nY0xGQmMwS3F4MXllQ2VUd1hucldQb0dvdllVQlYxYjA1cWtIa1d5V0RUaCsveXJFNzF0RjNxbUQvd3F6cUJyNE04NERtWWVuQkdFOWxtb3FIZEMyWnRpK09KV
FZKcmlHZWxQQ3RjZnZRaUlQcHdDZ3BFNmg1ekZhRndLajRuZGtBUkRpTC95L1EwWTZxNU5rM1g5RURlTmdjY1pIcFdmOUpKQ3M2a29wdXRtYjdDczIrbVJYdER1S09DaGY5UVUyN3Bmb1NJaklYK3NGdHY1c0hhSms2aHBZMlpzUUhzaTBYbFowc3FMTnQ5ayszdTVnYnBSU1JCczlHaC9BaVY0dkNyYTRkOTh5U0dCdzRSR1FhSStpQ29RaG9YK3lxc3VrYkx6bXJUU3FXMVRXaXJReUlHZ1Q5VnFERE1mUzAxeGdQSlNFSTlIWlp6TGlFVXVGMm1CMi81Y2dqaEFUaWQrdGV1UVB4aldhN2NSc2t5YUhuTENjQURVUU9ESUFPVjJDWXROcnAwY29ZL091S3ZzaXlJT0lacVJ5dE1PMGVNZ1ZJWTBzWmdxeVEycXlubUx0NDBmWmd3SFVyV245Zm9TYTNtMkVRTy9uOS8yU2NuelJWdVZpVnNjM0tCSElQL3AzNlJlSWowTGlNcCtPQ0p3SHlLVW1UeDRBU1V0dXVhWktlRHl1QjlxcXJuUEFNWUVCeElsTGFvdXMzV1pHakIrcW9ub3QvNmk1UE40bUZjbHFDcUxhMGJHbks4ZnJxYy9yd2tuVGV0YUE0c2tXTEw1L21qNEd5MitFQkh3a0x3UXd2K0FKdmZTOXYvNDl1LzY0N1ZFYW15UzdZQ2ZEUHNBQUREQ1FFcWJNQ1h2Ui8xVmEwWi9YUWhoNlkrZUt0MEVpRDdpNmRZODJtQkFoNEJMRmRVV3VGZHVrdUVwaGZ2WXB3N2loVjNxTjB1NFM1NTRXU0dUa0ZsdlpYNG1hbkF4a1g2ekQxS0NWaEFMdEJnSDgzdkhxam9uc0lwOFMydHgwZ0tiYzEreHVaRVppVWlNVVlVdTByQVFsRFcrZHJoN3lVRHZqekFHSnBmTk01eThaMW45em93VzZ5YW5VZWFBNjhSZDd5TU
xobFd0NVh6bGhBTVZDZmZYZ0pFelR1YzJEbENVOXNMLzVTVkRaV2N4R1E5aFM1cnJtK2VyQ1Jxd2FJQk1DNUtza0RCZHdOWmh2Q0FCdEpqS2Vla1FUSjd5MFp4SGNhbGVCaU1rbkYwZVRDZzFvUEhPUVZLQ3V3NE94cHRZUS9xS1V0TEFIWFZ2OTlLMGRWcWZDMmpVQWlHQmVYa0t3aGRYTGtJYlZxU0EyZmxraXBBeEhYNnByUEExQjF3eTVab3hPUFg4RVExOW92eXpBbFg1dHU0OXEwWC9PSExFN1o5T1cxenltRXR6ZFpyNXJZbWtFcVdtcHVSNU5jeHFwTWlZam93dUNXZWhubzIyeG5JM09IQ0xDZkFKaHRrcklhL1hPc0tZRFpCRzFJMGJsN2taR2R5cEtUQlhYdXl6WE5WUlU5L005ejhaVytwdG1oZ2NOUzBJS2VaaSs5bFl4cWRlS3lnbldTTTV3czdSYUpmNlRRZTNSaWJZUjFvNkhwRzB2VHpiTEtQZTZnRjJGODdiWlBJei9mcTNLWnZiM3UrSnhZcCtJVjBtQi9VN29YelhRRk1RK3VmWllpNzUxbkx6WlVxRE1ybU53TFJPVUFNUk8rVnJtblkwSVB1cFBVMXc0b0hBb1dnVGRnTk5pNk1uTFQ4V0pmUlhjT0pKMk1lbUc2K2ZNeHNZUU52UVJwa1RGY05vaFV6Y3ZjcHJ3NUV3WEVZQTJzbzczL2MvY3RIRGcreU05YlF4REppUlltRnFydkhYb29hS1JyekxnUjZLVWdoM3ltaWxaQ0lSSm9KbTE3aEtHM1pxTTE0Lzl5OUc5OE9BZjNkVTlqMDk3aUNlaEc3a2VxYXRJQ2hFWmJqbmQ4Y00rS3djN2FtVWp2ekQzQmNvMHl3MDJxT054OWF3OGhSblZiWDZhdkRJbGhySHZ6SU44MzFvUjljRHBwMG1DUEJXZFVDQlNqVGJ1RkZqRC90WElSbGxlT2J
raFFKSUdSNlE2U1MxcXkzT29WT1VheFl6THY0U2s3dndrQUMwUitGREVIeVFZbFVhbVVkTWcyUmdwRUdhSVd1V3IxaGNnRm10QmREV2g3ZFBuWTF0U3VKOC95MXp4NkRvN2ZJYmNFenBBK2E0ODNtRG5vemdld3VmaFdqVCsvUS85WlEreFQ5UWJBT1pQSXhHV3VhSXVrVk8zSWxvZDhJM1NGZFJCTHY5ZXBDNzFLeXpSdVlpMktkOHJ5NVNINit1WnMxUHlZUlpRakdDK3Q4VzRtSE82Z1lFRWVXSkJ1UWhnSHdmV2xhZXlWb3hac0NBQVZKRUllT3hPZDZtNW45OHRCUDdHTmgxT1M0eDRCS2FVN1A0UVQzNVVIZW5meE84WWFQUThmbXlobUJhSVJVZklBTVN2ZTJZRFp5SWNNTTkrN0tNSVVabzJ0eXRvYzdCOGVvZzBNaUkrVkpFdFg0c29FRjFSWkhQZVV3NWlCTjI4OTh2MmVTcGNnVUJhWHFzOUN5VlZtTVJQMEtLUDJ1REt4MUdJcUhjS0ZCOXVQVWRkQS9vT3dNa0tVUWsraFZVVDVPbEVMdjd1a0FBUEE0eE4rZkczVmYxeUVKV0FiVGx5dWtGcThjNXBTRkY1cXVHbUgwVmVpQzVvVEFka1VES3Z6WGhWWUs5c3BRYjNVZ1Z0Qld6N1ZScnlOUVVST3BIZU5xeDlhZHA4YWREWCtRSHJUKytYblN4VVI3SVdGanlNTkZJRWlMWmkxdks1UVVrZlRDUU9qdjh2SHdiUi9MRHF3Z3M5bXdsT3pPY0RLdVBVK0dTb2lnVFdRejRWN0N2SHRaVDI3WUdKVG44RFFFM3IzdjB4aWxvODJ2U3VXSDg0WEU3VEJsTUpFb2R5eDNDRngwVUVkc3VhRHBPSEV3UjZYNlUyU0xseERYSXVZeEhlNXh2NjI4bXU0bDRMSnBYUjhkYmljTEZKQW55Q0FVeDJLb2dDamt1cmU4
bXNUZktDbG8wamFlN1hNR05PSk15b0ZYbVlHZUh2eGhNUGMzTEtYLy9VY1p0c3p3dFJrQmNFdURXQysvQWNWZVBOSHVOWWI5MEpIcnRucGg1ZDlhL1lpTkpzY1N3QTFwUVZrdW1TQWtPQWdLdWRzcnl3c0N3Zkg1anNydVpHUTJDd1hKRXQzUU4wU2NLUlVnT1NCQ3FYa1BqZDVSVzJuOFZpamt4anovbWptakhCNmk0eHM5NEU2Nzk5STAyaldYNVd3UDZhTFRaTGt5TjhxNDUxT0RmeUZVZEY5WWsyZXQ5VUpsV1NzRFJMSWVCd0ZyQkEyZTdyRWsybWFLVUNCRW5PUWM2bUhVMXQvZ3gzK1VXVVFXbkpMZVUxbWUvbkFEdy96UGUwd3d0Vm9BaERZdDBoR1hQblJydjFoUHRGS01CeWtqckg3a0J5U0R3WDlQMi9XZkNkQlE5K1J4cHRsR2hvRmdpMUs0NVlOeEpEd05wTmd5MDV2WXUzVUtrMkpRYVNGUzcwK0Y1NzluRE5RenZpK0pPRlRsdDFmWDJGNXk5NEV2NHZobWRQSmRVOFVVRjU2Ymx0emxKREVFdmsySlFrOTM0aHpwTXJGZ1d3ZHUxUkxxSEhCN2h2T2hnaHNqV0ZGY01zNjZaRUtWcVhKUytxWWNVMHk0akwySVQrNlF2N2pvQ3BWbUdzUWtGY1FyblhxOUJiOTdaUS96UCtwaldmWTU0UmNRVlMydUU1YURObVVyVkdLK3E0d0xRcUhuRVViT2puSHFFeGlacUtxOVdRaUtUK2c3QS96bVlIQ2k0YzFTejRNVWhHb0t6U2l4aXoxYUNJUEJXdy9vczR2cUVqbXgzOGx6YnV0OWNWbElzeGNkTUpUTERRK3ZOZ0YyY1ZRaVcxRTQ0d3lWcnI3TUFaOE9KRVpFSzlEZWt5MzJQUkFuSkRUVXVqdGFscmJ0T2VOczhyS09uTjcvNFRqUEwvZmRlbEI4bjA4W
XdSNXdmbU42VGpGWUhRSDFjbUZmK1AvNUxVMTI4Q1pEYjNQUStxMlFJazV3aE40eGwvcy9lb29pallmeWtDcm5aSEhHWkluTGhoU2pWbk5ISWdTL203VWV0NlhBTDdvZUl5UFRLeHVnbDJzRWtUQzNnZ0tjTnFZR0E5U3ZlYVlaQ00vWHNQRUtQbWs3QmlRNmprWFBKaE1yREd4Vkc0SW9aSDgrYjBrUWJYR2l0Mkw0L3hZdHh1bTVzcFNPSjdsTDltVFpRNnBxM2JOaTEwZU1mZ0ZWaDc3NU5JRlc0SEp3U1FtaTU0bk11blZTQjhxdjZKc0w3SGlsZ2N0ZHFSNThTTjVad1lCa2dOR1hzYjA1QXJWemVXbHh1Y21BSHNPT3dyczFnMzh6bTRZN2ZPZmducmFhV1kxanZZOFlEODZQZThkZzR4cE5paTg3UnNDZk5WK2NKVmMraktFdnpuZVY1Zzd0RmlxZCtsZHp4STlKemdSS2t0WUV6RUpRSVU5M2UvclJaN1lrVkZtNVV1cjVhMWYzcG83T0VtYkJUc2MrQ1FaOGNnYmIvbUphRXJoa3NyL3JURjBNcjNxeDl5SlJWSEJ6YWNWd0dScEFRaURPdnJkWU4xQXBVOTRyR1lrVFVzdWs1YjE1Wll2QVZxRlRzVlVMaS9HY29mbEljMm01Z2RFTFZOblRmdXY1Zlk5S1NlWHFoUU80S0pOYVZmbHAwQ0VKYWFFZFNLUXJJNXRaT2w1RkE4VXZlNmxTWVd5TVk0REl4a1RiT1JoWHVBdzR6b1RTMjgrN3d2TXhydVBkZnlKbUJCTkhQdCtEYmdKNHovcHJZWUhpTmFMTXNZamtQZE44ajNKZDczQXJFZk92Um52MzYxSVVVMFg1RDc1dlRSdlpkbzMzWERzanRlOU4weUo3K2lIQnF1a1FJY2pIVW9ic2RQN0hOajBVYWNSMHIvTmRlVTlGNFBNc1VLY2t6Tk4rZGhyMVI2d1
J2R1VZb1pDRWJaWlJMWEt4QnA3SElUNEVQUktHakIvdW1xTFhhMXl6RWx2QW1WQUJhMDFZN3dGdk4wM2Ywb25FbUhTM2w1d1paRmV6cjVibnN5T01XVGxhMU5kaW1ZNXNVeE15VFliZmc4dzB2cXNEc28zWFAxYndLdzZ3M3VIRGQ1UHBSWnVDSnR0eWk0ZzJGeWI0Ymg1UU42ZkdORTI2ekRGN1Y4QmJwZXJLNkFKQ0xTWm5kaDZMMTlPUTBram4xUGpEMGk4c1BZcGFXOWxVeVJkZElPKzRWQS9LemxPUzJ4M2s5VUtUdElsTTBUSVdtZXFIS0dYUVpocGpvVGI2VlNKN203cjZaaVlQMnVsQVVvZmVWL0o2eCtzckxEQXkyQ2ZFNnFrREZ1OU9NWDBBSXVnN3loQUtOMDRyT3hVNk5tcGtjOUZ4bXUvVS9vR3hHdmIzeFVFTDYwdE1sSE9EaWtqY1I5RDJrKzRwbEc1WnV0d0FIY2kwRU02WHRrVEhQOU5QMlRTR1VFN1E5SGYvU0VEc2V0a25hZXhvWmhDczJLWDFMeU5JS0U0N2pkMkR3MTUreDRRVXV0VUFTbzU5Q1lHMVFBeW9BVVhrV3dtbXkzTGdTUWp5T3ZLV25qaE8veWpPd0FyWGd0NFBrSVVnZDQ1N05ReFpMbU41K0J4NVJoQ0FHdkUxYmxOZjlMek9keGJiaG5VZ2Z1RDM5MXVSRkhjS2RYREY3ZmVqb3gveThtaWZJcTRWVzQyajBHQnFOQUtkK0prMnJCMW9hOTRiT2hxcVVzanhqWnlRaGRXTzhNblR6T2tOaGVpZXU2blYxcW5yZ3JHU2huWTNJMlczb29GNFNnczRjZ3drZ2h2dHpFa0xUbU5OUm83RTdudVRuMkxJcmlGSnlvTmZQdUp0aWN0S0JtNzRGZytkWVBTMlIzTzNmOWxBZWxiVWZjbzZGNU9EL3hkS1VuRTh0V3FOMExVcDlWQUptWVZ
YZFVDaGJ4MjM4MWtDaStLNDJoRzUydFNQYU1hb1dTb0xQY2Zrb24rc1pYdjdEdEtwZi9HTzdhcUMza1pzRGpva29haHJGZGJWSlNTZWhrNGp5K3RzRHplQnJKSjBrMVZrUnJHN1NoVHZjTmd1cjVucVRUTEE5dlJMQmJNTTlhNlI1NEZ0Z1pQOWFKMU1aMEdCcUVpMnF6Ui8yd2tYQlhwcFhZdi9TcU1RV1dhbTVsSHBMVktxaDN4ZHRjNFdmck9mYldsbU1PNXA5Z0JUSFp1YUcxVGFkZXFRVVpKQmZBS01ENFdSR0NsMDFaeDRTVzE0YzZrdnFKdXExL080N215L3RsVHlLWndpYlBkQTNRMVVGd0I3R2Z4anEwaDN2ckxFbUNrS3Vsc0VBUkN6UnZNVjJSVnBVbFpUV240Y1Boc0hjcTNROElHSUYyKy9nOENFSU4vMU8xcVMvMkpXcXlDNmtIb0w4Y2R2R0VHbmkxSTNDTk1JcXhxaHhJL1V0R3REc2VwYmwrSHI0elh4MzZna3BCbXBoT2xkTFVYTHAzVEtibVVZRWJSWHcvZmRmeFQ3WDdZUFhHQ0hHVG1uTzk4WkxDOTA2Zmkvekd2b04rNlpzbCs3MkpWMGxJWEo0V3dZdWxFUmZHbkFDWGNoa0Yzei9ITWR3elcwTUFFaXptQmwvREo2ZUoyU01PSG1Uc25YbElGRDRlcFRrYnFBQ0dpZ2I1UExFdHdQRVRjYkNRckM5YUtTU1FnSTdEZXd1aWlxM2J0Y0RUWkIzeEI5WWxlbmhpU0FXNjIwcmwzc2ZjY3d3eGFSOHBDV2Rzd0x3dmFxcDhjM01PV3RCc2xPcmVTSkNEcWgvdzBYbm1WMFJVWFpNM2JvUmkwVXhsaHVUeDFlM1NTd09pbTlOczNYV3NoTmI4Lzc3VkhnUWhRVFlSUU1NRllYaWRmMElCKzBtSUpocWNoQTlUeUY3dGRjSDhrUUJUSHNEWS96bFpq
K3EwNlFMd0JkbTkxc3IyK3VzZmxlaXB3WUMrcmdiNHROVnA3VU5rYkVqTnR6ZWZsTi9VRTlkbHZtT2x6V1dtZkh2NGVkUGkzMmJmeUNRS1d6SGJVVEV3NU0yVFpsZnpNaTFWUjVsaDBxQ1lqaDNITUlmL2MwcHBKd2I1b1lFTnBBenlxbnlmdmlTV3lBYzc2L1l1VWwvb2FVaysrYzBZc2d1TGo5ZGFQdVVvemhoZ3VjSytQRGlNckI0ODU1Mk83VWg0aHRwNmZ3S2dJa1JCTVFIUTd6MmV5WXovV1AwQm9ZZVhjOGc3aUprclhFNzA1bFo1bXhGU0poT3E1WlNleVJSb21pUm41K3VRemM5ZFdWQjBYb2JURXdOc0VRM2FIZ25JY29BczY2UGplUT09PC94ZW5jOkNpcGhlclZhbHVlPjwveGVuYzpDaXBoZXJEYXRhPjwveGVuYzpFbmNyeXB0ZWREYXRhPjwvc2FtbDI6RW5jcnlwdGVkQXNzZXJ0aW9uPjwvc2FtbDJwOlJlc3BvbnNlPg==
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/backends/data/saml_response_no_next_url.txt
new/social-core-4.5.1/social_core/tests/backends/data/saml_response_no_next_url.txt
---
old/social-core-4.5.0/social_core/tests/backends/data/saml_response_no_next_url.txt
1970-01-01 01:00:00.000000000 +0100
+++
new/social-core-4.5.1/social_core/tests/backends/data/saml_response_no_next_url.txt
2023-11-29 09:52:23.000000000 +0100
@@ -0,0 +1 @@
+http://myapp.com/?RelayState=%7b%22idp%22%3a+%22testshib%22%7d&SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJlc3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBEZXN0aW5hdGlvbj0iaHR0cDovL215YXBwLmNvbSIgSUQ9Il8yNTk2NTFlOTY3ZGIwOGZjYTQ4MjdkODI3YWY1M2RkMCIgSW5SZXNwb25zZVRvPSJURVNUX0lEIiBJc3N1ZUluc3RhbnQ9IjIwMTUtMDUtMDlUMDM6NTc6NDMuNzkyWiIgVmVyc2lvbj0iMi4wIj48c2FtbDI6SXNzdWVyIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI%2BaHR0cHM6Ly9pZHAudGVzdHNoaWIub3JnL2lkcC9zaGliYm9sZXRoPC9zYW1sMjpJc3N1ZXI%2BPHNhbWwycDpTdGF0dXM%2BPHNhbWwycDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz48L3NhbWwycDpTdGF0dXM%2BPHNhbWwyOkVuY3J5cHRlZEFzc2VydGlvbiB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BPHhlbmM6RW5jcnlwdGVkRGF0YSB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiIElkPSJ
fMGM0NzYzNzIyOWFkNmEzMTY1OGU0MDc2ZDNlYzBmNmQiIFR5cGU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI0VsZW1lbnQiPjx4ZW5jOkVuY3J5cHRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNhZXMxMjgtY2JjIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiLz48ZHM6S2V5SW5mbyB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI%2BPHhlbmM6RW5jcnlwdGVkS2V5IElkPSJfYjZmNmU2YWZjMzYyNGI3NmM1N2JmOWZhODA5YzAzNmMiIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6RW5jcnlwdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3JzYS1vYWVwLW1nZjFwIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiLz48L3hlbmM6RW5jcnlwdGlvbk1ldGhvZD48ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE%2BPGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDc0RDQ0FobWdBd0lCQWdJSkFPN0J3ZGpEWmNVV01BMEdDU3FHU0liM0RRRUJCUVVBTUVVeE
N6QUpCZ05WQkFZVEFrTkJNUmt3CkZ3WURWUVFJRXhCQ2NtbDBhWE5vSUVOdmJIVnRZbWxoTVJzd0dRWURWUVFLRXhKd2VYUm9iMjR0YzI5amFXRnNMV0YxZEdnd0hoY04KTVRVd05UQTRNRGMxT0RRMldoY05NalV3TlRBM01EYzFPRFEyV2pCRk1Rc3dDUVlEVlFRR0V3SkRRVEVaTUJjR0ExVUVDQk1RUW5KcApkR2x6YUNCRGIyeDFiV0pwWVRFYk1Ca0dBMVVFQ2hNU2NIbDBhRzl1TFhOdlkybGhiQzFoZFhSb01JR2ZNQTBHQ1NxR1NJYjNEUUVCCkFRVUFBNEdOQURDQmlRS0JnUUNxM2cxQ2wrM3VSNXZDbk40SGJnalRnK20zbkhodGVFTXliKyt5Y1pZcmUyYnhVZnNzaEVSNngzM2wKMjN0SGNrUll3bTdNZEJicnAzTHJWb2lPQ2RQYmxUbWwxSWhFUFRDd0tNaEJLdnZXcVR2Z2ZjU1NuUnpBV2tMbFFZU3VzYXl5Wks0bgo5cWNZa1Y1TUZuaTFyYmp4K01yNWFPRW1iNXUzM2FtTUtMd1NUd0lEQVFBQm80R25NSUdrTUIwR0ExVWREZ1FXQkJSUmlCUjZ6UzY2CmZLVm9rcDB5SkhiZ3YzUlltakIxQmdOVkhTTUViakJzZ0JSUmlCUjZ6UzY2ZktWb2twMHlKSGJndjNSWW1xRkpwRWN3UlRFTE1Ba0cKQTFVRUJoTUNRMEV4R1RBWEJnTlZCQWdURUVKeWFYUnBjMmdnUTI5c2RXMWlhV0V4R3pBWkJnTlZCQW9URW5CNWRHaHZiaTF6YjJOcApZV3d0WVhWMGFJSUpBTzdCd2RqRFpjVVdNQXdHQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUp3c01VM1lTCmF5YlZqdUo4VVMwZlVobFBPbE00MFFGQ0dMNHZCM1RFYmI
yNE1xOEhyalV3clUwSkZQR2xzOWEyT1l6TjJCM2UzNU5vck11eHMrZ3IKR3RyMnlQNkx2dVgrblY2QTkzd2I0b29HSG9HZkM3VkxseXhTU25zOTM3U1M1UjFwelE0Z1d6Wm1hMktHV0tJQ1dwaDV6UTBBUlZoTAo2Mzk2N21HTG1vST08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BTElQdkVNVUVGeXhrVHowQ2N4QVA5TjV4Y3NYT2V4aVV4cXBvR2VIeVFMV0R5RVBBUDVnZ1daL3NLZ1ViL2xWSk92bCtuQXhSdVhXUlc5dGxSWWx3R2orRVhIOWhIbmdEY1BWMDNqSUJMQnFJbElBL1RmMGw4cVliOHFKRy9ZM0RTS2RQNkwvUURtYXBtTXpFM29YOEJxMW5Ea3YrUWh4cmQwMGVGK2ZMYVQ0PTwveGVuYzpDaXBoZXJWYWx1ZT48L3hlbmM6Q2lwaGVyRGF0YT48L3hlbmM6RW5jcnlwdGVkS2V5PjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BRVpUWDhHTkM0My9yWStTUVlBMXRudHlUTTVVNkN2dUNCaktsVEVlekZPRjBZZHhCWUdFQVVjYU8xNVNKOXBMemJ1L1h0WGxzTkVMZTdKdEx4RUpwYUxubWFENnIranNWczdLaTBLNHRTMGNBUERDWHV2R1FoMmFOVjVQOGJ3N1JWUGhLOGQwYlJ1RklGR09FOHMwTTZYOUpxWDN4
S0MvL1lSbVVoeDlybnU3ZWlwMGh5ZitPaUZiVGR2SDY2NTB2LzQ3aVdKcDNZeFlUV0QyMHBNbVRJMUpwWUEwYjByWVFQRkR0RU93d0JxYktxanRJc3ZYVFJzeXJhQkxvbnFOeHN5dHpEWHEra0JsMXp3WGUvSE5QcUVQblczdnNxaFhZcDVGM3dkWThkKzNCOTRMZlpOdUd4a0p3VDNzdVR0OGY5VHRBSlI4VytBUmtzT2M4eDBVaVNsVG5BNHFHOTBLMTR5dkVoVHcvd2drZjFXV01RT3dpZDNpakFYbUV4MU5MbVZvYUxYb3p4VExkTjN6YnJ6VEJIRXc3R2J3ZEdrdU5pMlhZOW16YUgwaWtGRm51VUxjMHUwc0pycEdGdzlaK0VlUk44RzNVUVZ5MjhtS2g3ZFBwWU5KbzhyajIxZFFaK2JaeUtTUHZablU3REkyakdJRE5US1g2ZkVyVWFINGlOTzN4cUU2Vk90L2d4T3BMNE5VNUhLV0Q0bG93VzcwdUJjVEVQRmhwaThpYUovdTB6YzUvTEhvdVBjMzByc1RLZFc5cmJLL2NWaHNQUHErZzA5WHZpZ0QweTJvN2tOc1pVL25tRXFiSzBKOTBrazhCR3I5cXRSczY4bUJnSURtUHVwUkhwWjM4eXNnU2VZN3V0VlVaSG5tQ0dzTzZ2NDJ6OTVOK05Pb3RCTEVZbFd1ZEdzYnowQWc4VkRDSlY5ak95QW95MDZyL1AyUHBsOFhjdmJza2d2T1BMMWdDNnVYbVJJS1lmOEw4UDJCNXVjN0haK0dtUHNOWXRLS2VKRDFFUHovdCt2NlBIbXNVb3dsSDhSd3FMRHdtMUF4dlNLQTR3UXBlQ0dQd3A5YXRYS0lWMS84NUZzRWMzajVzNjd6VlRybThrVEpydXV2MDZEdFVRZDNMOFdwTkV4cWhQait6RUp6U3RxSG04ckhNMVhNQUVxdVozc0xycTVqLzFSNlpqS0dOdFJCb
jhwOE5ERGtrWm0vWTV5TXlJNXJJS3U5bnA3bXdaaEVpeWVHeHdxblV3VVMvUzVDRjNnMHVidnd4eVVnalVvd1ZvTkNqYktBbkdtT2VCSW5abkh0eGdIVUhVOUVlTFdyd2pRc3JtUmpJV0R2RkZQa3l6SzJDL20yaitubmNxc2E1OGRLVXZxcGR1VTRJYnNPQng3UGpXdXRBNmY5bXd6YWxyRU1NK0lGR3VPdk9HMC93eUdzQjZLREV6bldjUC83NkQ4angzaHZFSlAzN3REbFgreGM4Qno5TXdKdkd6VG4xbTdCb2xoR0lzSXlCTys1ZXpXa3RDWVVIUURGVE9wbXA0MDlOWHp6ZUNTUGY1U2NDWG5YYjRPd01ULy9VM1JFUnRRbGMrNmU2WG1JRjhoRkJVc0taUUJsS2ppSDkwZHlzYWlsNmN2V3UyQW55Q3QxbWxXcHFLc0MzU2RTRVZDTG1qRjlUQUFUMEtFSGdZQjg3RjZtZUpTTysvOXkyZkRuYVVvUUlUVzdubnVuSCtkT3dWSGZMU0wyL2N5YTltNlQzR29TSVNMbGJPMVRzalhKclVkZW55OTcvM2tkNmhFQlphdGY1U3NETFQ3SjNsQUVJNDROeXJ0NkIxQWdod2JNdkpqd1JNTXRNdUJLc3ltUytKVzc4UFNEWXQ4MG9waDJQTTc1N0tBNCtUMTAvYnZaQkE5Vk1OdVpqNVV3NXRWMnFIS3dwS0t6ZVVETUFiQlBRaGpYcXlQZzFKa09rd2RQMUpnOHRITjJTelBZQTlmT1htV0pBZGJDS2tMb0F4ZTV6cDZBUzYzS3FXMmFmSUt6SHJ3RTJmS1VtamppeURvMnNuMkJHbWtBaTRzbnpiVzc2SUQvSVgwd044aDBaQ2VRc29vKzdtb1RCMEJxSnBkS1MycXlsUktoc3BSTC9henVQdmxaK1pwckJxdXpJdEZkNFVLMkpzQkp6VXcwZkpxcTV1bk9PZENzVWM3SU
U3QTNmZ1NmZ3NBd1R3WFZJMEVoME5ySWZpMkFKV1Z2VFpEMys2eFZ3dS96WWhuVjc0VXkvMFE4Mi8yQWtpSGpFRjNJVGNLWHdTNTB6bWtLakxjZDJqa2h5TUFYMWRoQ0wwZElFMUJoN0RNamVvNC9YbjBqSlpPL3Rrbi9xZmYzc3RNb1BYVG9KTnBIU1RjR2ZheGtaMzJYNCt3Q0xPc0VBRWxlMVZSY0kwUkZyOFhHTSsxWU9BTjBodFdGcFMxaG9kSi9OczJqL1FnUVNEemNpQ1FZeUFDd3lFRWZDZjZybnR0VmJyTlJQZWlmSHhBM3B2UnZ5ZGRhNDE5cXl0ZXI0akJ3cmw3ZUpuVnJ2VEprR2VhU2FRbDdXWk5SQXBscXRnNnZPYmpiMHZDRWlFaFhKbmNzQUhxcXp5QTRGeWFUVGQ2R0FySU9adUNxRWVoWk51T01lOVlrMVpya0VkR3pIalJESWk3Q1BKQk12NEZ4ZHI3bnJvN0I1WEhKb0ZMNE1DSUtOWWU2aWZiTUtYOU5uN1FWdnphUmY2UXlaSW1BWENQZndvU1BkN2x6NXl3UDJLSUIyaGhFMWt5eVZ5YVc5T0praWpUY3dvUnZrSXhIU0RqMXFqeGxueXh0QzhVZ1pNWmlwcGgzQXJpcjRiekIzUDhIbGIzejZ0OW51KzZMemNiN2ZObVo0UHluaU50Vk9OQ0lHbEh4dTBSY3hQK3cwUXNsM1BtTzJLaHBpc2RIanhvSUJ1YVY1NXdoTlFFNmdNNFBrT0xINDc4Rzg4bUxkd2s2RFpkWVl4L2d6RWE3b3ZIL0pReFp2TzRLdFVTNmZjZHJxV2thTFg1cEhkNkdneFBGZ2NFc2Nad1ZqM2hCS0xFQmE5L0dodERINEhzRnNRbmpPZnNDQkNzN0tjRitmTi9oSUdUeHFqTVlKVHJRYmNtdWF5dk9xR3RQMDFPcXltR24rVm5FSVkzKytQcm95SFN3K0Q0b0JIVG1
maFNXRmJLZCtuTlVFS3BhRVIxNkdCU256WktQRVRVSmdRWEw5QWJRQ3RXVjFHb0UzRWNnMDZYaVd2aHFHakpGNldtdEU4dHY4Q25rZmxMNm91TDRvNldpbmx2WnNEdkZrS0R6TDkwUTNsWC9NanBtRTFpWU9uYzdISXdEVGwraFRRcHdsYXJiTDVUNGNkZTg1akNwYU0xU3p1TStiQU5zMHlXVDA0ZXJUVFc2cnhlbXFDTHAra202TVVMTlZOcE1CazBiQjJpRU82UlRtc3VpRlhDUU1xdU5xZjdkWXUwTFFCZzQ0MkJzU1pBV1ZrWEVZblduOURLdTRSby8veEFsb2h5VHozWlZmSkhuWVBSdDloSUErRHVUL3c4T2ZzTURIWnlCelUvL0JEa1NiNkxjMHdraVA3QlhIdjBoNVdud2dNWUxlZDBPalR5UWI2aGxpVnQ5b0FjaDRFVy9EZUlBdkpaQ1BYVm1pUFFYTGVsOVJIRko2bXFiYVo0TCtaZG1ONmQwcFZNZ1FveXhmQTR3dEwwYVpiNnFZYkhibjJMd2VBQVZwL3M2TzVlMVExdnZpZDRTWHo0a2l3RW1LSStIeXZEQ1pnekpQQVN5Z1gvWDJFWEZ0NGV3SjVmUFQyVXZmWnhQWlpqMFZGSFpyUFQwWVd2VE16bjUva3hoT09oM2drVGdDSmNwNWVsZnp4cEFPNFl1a0NoNHJXdVNndDRqVUJyaWNYbFdWdWo5U3JSZVhUalNHTktLK202NWovUDllNHRHT0RkMk9BbjNKTVQ3Q3FuaDhreTZpZjVjbmpVMmU3UDhTZnBONGwxWEFiZEZEcGk5bVJYamEyTzR1RWFHNGNvNW4xcWNDT3ZNMWYyblFBY1ZGNUFoSXhueS96TWhmU2l2RXdOQ0Zyd2tBWDRyQVE0WldUNldFakFyUG5jb1Y4Z1VRclhxQVA4NDJmK1lNWWI5RHFncmFicEg1a3ZuMnQzcWRldGJHODJ0
QWlTamhPcUxNYW9iU2F4cXdWa1lUOHRTMW9rUUt2MWZoZ2t6elpEOE5IQnVQQzdNVHdXS0VCS2tDRUUzRWRFMXhNQURLd1B1M3NSaGpSaExXZyszZ2srejJtdlU4cTBhTlc0Y3hObUdoekx4eEY0Q3NFNStMQ1cwOWFpUVJOM1VvWmg1aktBZzBiMlh3WHBLS3pycUVTY1BYdnI0L1dWUTMyMm5qRWRvQVdXR0t2WnBKMlRlREo0eDdiT21LVElFc2RHWU1UZzFVaEU2eFFQcnhqS3dWeGFJNVJyaVE4a0xpaGgwa0t0WHQvYTVsSDhzUjVwR0ZISGZ3dlNVb3liQTB1eUVDNnNRVitPbTVReUZmRmpqZHFCOGNpOGxQS1hLTHFCTHJ6bjNmUkh3TmQwbzFiRTg0aGllTkx5UlhZVmhrRCtFNEpGaVd3ZWt3U3VWM3BjQk9ybnRVU3RoWmx6M3hIUURUVGNJNWliOFJyQ2swZEZ6YTgvQmw3VUdtWlUwSXZ2UmdvVXF2TXNHT2dMY3pGWmRpZnJ5aGNiUTY4a2ZzZ3lCMHppdC9MN1BSV3V4RkdYdDFoTVZSVUZ3WXBJS04zVkI3cXVKZlgwamZsU1JaRndMaXdlK3VhYndmTVZ6c2doajUvOXZNNzcwK0JaMGtJcE45NzBTMG5BbHl6R0h0aW1nTUl1RXFhbUt5QTNTQlI1aHZIYmRyNENnTHFUbXIzbFFnWmpnSkNvN1FXYUJWTXdCR0RpdzVOVVhUUnBycWc4U3h2eDlnNWZwbXMrL0o2QjFEelNTM3ZRZzgxdHFRU1ZDWVJpc0Y3M2VqZlFuZk4zcUszd3RJRDkxQnRISmFvMEFaUUdKVFpKOXVsZ0kzV3hzdWR4ejB0VHVpNlJlSWpmSWsxekZRdFpwRExGMnB3NGpTQVdQTlJqNDBYdVIrRzFUVlI3OVFiME9FYkw4RDFoTU5zWmo3MTZNbUhSOTlKaUxNdm1FWHV5a
1V4VGhGYjRMTzZVbW1kU3UwTlBpMXQ2NmNkYURpQWhMaVBFTGdUNkZsenA2T2FGSGNSNjRncEtyemtTNDJONEhJeFpNa2R6M0FsYkRhK2pOWHZPR1l3UWl5K0xNNENZWGtrTWtHR3ZTWis5R2xWQ0l5RXBJaXIzbEQ3bmdzZGk4emxGWDYvekNaczlQSUtwZFZlSGJGZi9GS20wV3AreHI0Ykd0R0RrVHR2Nk1Manh2YU8zanFHaUFWeERKVWFkTVBlS2VHSm5uempTdnpKbGdOVHV3c3grRnF5L2dPMkwxMGowWmhDWi92dE9NelVjNjl3cGhKZm9FNzU3V3lOeFJOcThJc0Y1Tkg5Y0x0b3UvbUNxOTc3YnZPSkRrSURCN3lKWEJ6YUhVQkJuSXJra1Qyemg3bGJmUm5SREJUSFZraVZMazVESUxqeC9XL1BSZEZpUUM2SzRmZGx4Y29JbzlMcnM4ZFVWZkt2TTNNYnJ6c1hGT3ZtVVh0K3NsZldvd3UyTC9ndG9mRFhvTUJZZnlEcWIvWlRaRWZ0MC83blliRm1relBEUlZacU5SR0F3YWZVNTU1UjB2SWtNbGR2VjdKUzhNT1BNYWlXQVBpelNLRG4yRzNvcys1MzRFQytaOGZnWmFPVWpZL0xLME9vME9RMmhvNUV6MGNMYWpwUjFINk9FNEhvUm1ydjQzZkFjdGpYc0hYdi81RXg3emdrWk1NZXZhTFNEdjZtcjFGcDk4QXR4L296VTFGVDBoMDUxcVcwR0g2VWpRRXk5aExSZDBBMnFkUTRMZXpReDNvbDFTblhsamt2MG4zTXFlaFozOC94bzZhdHFDdkJtQkc3amlUdXd6YnlVUngzRm1TM0NCNllOYnFON3hPYVRZRnlkOEZDL01nY0xGQmMwS3F4MXllQ2VUd1hucldQb0dvdllVQlYxYjA1cWtIa1d5V0RUaCsveXJFNzF0RjNxbUQvd3F6cUJyNE04NERtWW
VuQkdFOWxtb3FIZEMyWnRpK09KVFZKcmlHZWxQQ3RjZnZRaUlQcHdDZ3BFNmg1ekZhRndLajRuZGtBUkRpTC95L1EwWTZxNU5rM1g5RURlTmdjY1pIcFdmOUpKQ3M2a29wdXRtYjdDczIrbVJYdER1S09DaGY5UVUyN3Bmb1NJaklYK3NGdHY1c0hhSms2aHBZMlpzUUhzaTBYbFowc3FMTnQ5ayszdTVnYnBSU1JCczlHaC9BaVY0dkNyYTRkOTh5U0dCdzRSR1FhSStpQ29RaG9YK3lxc3VrYkx6bXJUU3FXMVRXaXJReUlHZ1Q5VnFERE1mUzAxeGdQSlNFSTlIWlp6TGlFVXVGMm1CMi81Y2dqaEFUaWQrdGV1UVB4aldhN2NSc2t5YUhuTENjQURVUU9ESUFPVjJDWXROcnAwY29ZL091S3ZzaXlJT0lacVJ5dE1PMGVNZ1ZJWTBzWmdxeVEycXlubUx0NDBmWmd3SFVyV245Zm9TYTNtMkVRTy9uOS8yU2NuelJWdVZpVnNjM0tCSElQL3AzNlJlSWowTGlNcCtPQ0p3SHlLVW1UeDRBU1V0dXVhWktlRHl1QjlxcXJuUEFNWUVCeElsTGFvdXMzV1pHakIrcW9ub3QvNmk1UE40bUZjbHFDcUxhMGJHbks4ZnJxYy9yd2tuVGV0YUE0c2tXTEw1L21qNEd5MitFQkh3a0x3UXd2K0FKdmZTOXYvNDl1LzY0N1ZFYW15UzdZQ2ZEUHNBQUREQ1FFcWJNQ1h2Ui8xVmEwWi9YUWhoNlkrZUt0MEVpRDdpNmRZODJtQkFoNEJMRmRVV3VGZHVrdUVwaGZ2WXB3N2loVjNxTjB1NFM1NTRXU0dUa0ZsdlpYNG1hbkF4a1g2ekQxS0NWaEFMdEJnSDgzdkhxam9uc0lwOFMydHgwZ0tiYzEreHVaRVppVWlNVVlVdTByQVFsRFcrZHJoN3lVRHZqekFHSnBmTk01eThaMW4
5em93VzZ5YW5VZWFBNjhSZDd5TUxobFd0NVh6bGhBTVZDZmZYZ0pFelR1YzJEbENVOXNMLzVTVkRaV2N4R1E5aFM1cnJtK2VyQ1Jxd2FJQk1DNUtza0RCZHdOWmh2Q0FCdEpqS2Vla1FUSjd5MFp4SGNhbGVCaU1rbkYwZVRDZzFvUEhPUVZLQ3V3NE94cHRZUS9xS1V0TEFIWFZ2OTlLMGRWcWZDMmpVQWlHQmVYa0t3aGRYTGtJYlZxU0EyZmxraXBBeEhYNnByUEExQjF3eTVab3hPUFg4RVExOW92eXpBbFg1dHU0OXEwWC9PSExFN1o5T1cxenltRXR6ZFpyNXJZbWtFcVdtcHVSNU5jeHFwTWlZam93dUNXZWhubzIyeG5JM09IQ0xDZkFKaHRrcklhL1hPc0tZRFpCRzFJMGJsN2taR2R5cEtUQlhYdXl6WE5WUlU5L005ejhaVytwdG1oZ2NOUzBJS2VaaSs5bFl4cWRlS3lnbldTTTV3czdSYUpmNlRRZTNSaWJZUjFvNkhwRzB2VHpiTEtQZTZnRjJGODdiWlBJei9mcTNLWnZiM3UrSnhZcCtJVjBtQi9VN29YelhRRk1RK3VmWllpNzUxbkx6WlVxRE1ybU53TFJPVUFNUk8rVnJtblkwSVB1cFBVMXc0b0hBb1dnVGRnTk5pNk1uTFQ4V0pmUlhjT0pKMk1lbUc2K2ZNeHNZUU52UVJwa1RGY05vaFV6Y3ZjcHJ3NUV3WEVZQTJzbzczL2MvY3RIRGcreU05YlF4REppUlltRnFydkhYb29hS1JyekxnUjZLVWdoM3ltaWxaQ0lSSm9KbTE3aEtHM1pxTTE0Lzl5OUc5OE9BZjNkVTlqMDk3aUNlaEc3a2VxYXRJQ2hFWmJqbmQ4Y00rS3djN2FtVWp2ekQzQmNvMHl3MDJxT054OWF3OGhSblZiWDZhdkRJbGhySHZ6SU44MzFvUjljRHBwMG1DUEJXZFVD
QlNqVGJ1RkZqRC90WElSbGxlT2JraFFKSUdSNlE2U1MxcXkzT29WT1VheFl6THY0U2s3dndrQUMwUitGREVIeVFZbFVhbVVkTWcyUmdwRUdhSVd1V3IxaGNnRm10QmREV2g3ZFBuWTF0U3VKOC95MXp4NkRvN2ZJYmNFenBBK2E0ODNtRG5vemdld3VmaFdqVCsvUS85WlEreFQ5UWJBT1pQSXhHV3VhSXVrVk8zSWxvZDhJM1NGZFJCTHY5ZXBDNzFLeXpSdVlpMktkOHJ5NVNINit1WnMxUHlZUlpRakdDK3Q4VzRtSE82Z1lFRWVXSkJ1UWhnSHdmV2xhZXlWb3hac0NBQVZKRUllT3hPZDZtNW45OHRCUDdHTmgxT1M0eDRCS2FVN1A0UVQzNVVIZW5meE84WWFQUThmbXlobUJhSVJVZklBTVN2ZTJZRFp5SWNNTTkrN0tNSVVabzJ0eXRvYzdCOGVvZzBNaUkrVkpFdFg0c29FRjFSWkhQZVV3NWlCTjI4OTh2MmVTcGNnVUJhWHFzOUN5VlZtTVJQMEtLUDJ1REt4MUdJcUhjS0ZCOXVQVWRkQS9vT3dNa0tVUWsraFZVVDVPbEVMdjd1a0FBUEE0eE4rZkczVmYxeUVKV0FiVGx5dWtGcThjNXBTRkY1cXVHbUgwVmVpQzVvVEFka1VES3Z6WGhWWUs5c3BRYjNVZ1Z0Qld6N1ZScnlOUVVST3BIZU5xeDlhZHA4YWREWCtRSHJUKytYblN4VVI3SVdGanlNTkZJRWlMWmkxdks1UVVrZlRDUU9qdjh2SHdiUi9MRHF3Z3M5bXdsT3pPY0RLdVBVK0dTb2lnVFdRejRWN0N2SHRaVDI3WUdKVG44RFFFM3IzdjB4aWxvODJ2U3VXSDg0WEU3VEJsTUpFb2R5eDNDRngwVUVkc3VhRHBPSEV3UjZYNlUyU0xseERYSXVZeEhlNXh2NjI4bXU0bDRMSnBYUjhkYmljT
EZKQW55Q0FVeDJLb2dDamt1cmU4bXNUZktDbG8wamFlN1hNR05PSk15b0ZYbVlHZUh2eGhNUGMzTEtYLy9VY1p0c3p3dFJrQmNFdURXQysvQWNWZVBOSHVOWWI5MEpIcnRucGg1ZDlhL1lpTkpzY1N3QTFwUVZrdW1TQWtPQWdLdWRzcnl3c0N3Zkg1anNydVpHUTJDd1hKRXQzUU4wU2NLUlVnT1NCQ3FYa1BqZDVSVzJuOFZpamt4anovbWptakhCNmk0eHM5NEU2Nzk5STAyaldYNVd3UDZhTFRaTGt5TjhxNDUxT0RmeUZVZEY5WWsyZXQ5VUpsV1NzRFJMSWVCd0ZyQkEyZTdyRWsybWFLVUNCRW5PUWM2bUhVMXQvZ3gzK1VXVVFXbkpMZVUxbWUvbkFEdy96UGUwd3d0Vm9BaERZdDBoR1hQblJydjFoUHRGS01CeWtqckg3a0J5U0R3WDlQMi9XZkNkQlE5K1J4cHRsR2hvRmdpMUs0NVlOeEpEd05wTmd5MDV2WXUzVUtrMkpRYVNGUzcwK0Y1NzluRE5RenZpK0pPRlRsdDFmWDJGNXk5NEV2NHZobWRQSmRVOFVVRjU2Ymx0emxKREVFdmsySlFrOTM0aHpwTXJGZ1d3ZHUxUkxxSEhCN2h2T2hnaHNqV0ZGY01zNjZaRUtWcVhKUytxWWNVMHk0akwySVQrNlF2N2pvQ3BWbUdzUWtGY1FyblhxOUJiOTdaUS96UCtwaldmWTU0UmNRVlMydUU1YURObVVyVkdLK3E0d0xRcUhuRVViT2puSHFFeGlacUtxOVdRaUtUK2c3QS96bVlIQ2k0YzFTejRNVWhHb0t6U2l4aXoxYUNJUEJXdy9vczR2cUVqbXgzOGx6YnV0OWNWbElzeGNkTUpUTERRK3ZOZ0YyY1ZRaVcxRTQ0d3lWcnI3TUFaOE9KRVpFSzlEZWt5MzJQUkFuSkRUVXVqdGFscmJ0T2VOczhyS0
9uTjcvNFRqUEwvZmRlbEI4bjA4WXdSNXdmbU42VGpGWUhRSDFjbUZmK1AvNUxVMTI4Q1pEYjNQUStxMlFJazV3aE40eGwvcy9lb29pallmeWtDcm5aSEhHWkluTGhoU2pWbk5ISWdTL203VWV0NlhBTDdvZUl5UFRLeHVnbDJzRWtUQzNnZ0tjTnFZR0E5U3ZlYVlaQ00vWHNQRUtQbWs3QmlRNmprWFBKaE1yREd4Vkc0SW9aSDgrYjBrUWJYR2l0Mkw0L3hZdHh1bTVzcFNPSjdsTDltVFpRNnBxM2JOaTEwZU1mZ0ZWaDc3NU5JRlc0SEp3U1FtaTU0bk11blZTQjhxdjZKc0w3SGlsZ2N0ZHFSNThTTjVad1lCa2dOR1hzYjA1QXJWemVXbHh1Y21BSHNPT3dyczFnMzh6bTRZN2ZPZmducmFhV1kxanZZOFlEODZQZThkZzR4cE5paTg3UnNDZk5WK2NKVmMraktFdnpuZVY1Zzd0RmlxZCtsZHp4STlKemdSS2t0WUV6RUpRSVU5M2UvclJaN1lrVkZtNVV1cjVhMWYzcG83T0VtYkJUc2MrQ1FaOGNnYmIvbUphRXJoa3NyL3JURjBNcjNxeDl5SlJWSEJ6YWNWd0dScEFRaURPdnJkWU4xQXBVOTRyR1lrVFVzdWs1YjE1Wll2QVZxRlRzVlVMaS9HY29mbEljMm01Z2RFTFZOblRmdXY1Zlk5S1NlWHFoUU80S0pOYVZmbHAwQ0VKYWFFZFNLUXJJNXRaT2w1RkE4VXZlNmxTWVd5TVk0REl4a1RiT1JoWHVBdzR6b1RTMjgrN3d2TXhydVBkZnlKbUJCTkhQdCtEYmdKNHovcHJZWUhpTmFMTXNZamtQZE44ajNKZDczQXJFZk92Um52MzYxSVVVMFg1RDc1dlRSdlpkbzMzWERzanRlOU4weUo3K2lIQnF1a1FJY2pIVW9ic2RQN0hOajBVYWNSMHIvTmRlVTl
GNFBNc1VLY2t6Tk4rZGhyMVI2d1J2R1VZb1pDRWJaWlJMWEt4QnA3SElUNEVQUktHakIvdW1xTFhhMXl6RWx2QW1WQUJhMDFZN3dGdk4wM2Ywb25FbUhTM2w1d1paRmV6cjVibnN5T01XVGxhMU5kaW1ZNXNVeE15VFliZmc4dzB2cXNEc28zWFAxYndLdzZ3M3VIRGQ1UHBSWnVDSnR0eWk0ZzJGeWI0Ymg1UU42ZkdORTI2ekRGN1Y4QmJwZXJLNkFKQ0xTWm5kaDZMMTlPUTBram4xUGpEMGk4c1BZcGFXOWxVeVJkZElPKzRWQS9LemxPUzJ4M2s5VUtUdElsTTBUSVdtZXFIS0dYUVpocGpvVGI2VlNKN203cjZaaVlQMnVsQVVvZmVWL0o2eCtzckxEQXkyQ2ZFNnFrREZ1OU9NWDBBSXVnN3loQUtOMDRyT3hVNk5tcGtjOUZ4bXUvVS9vR3hHdmIzeFVFTDYwdE1sSE9EaWtqY1I5RDJrKzRwbEc1WnV0d0FIY2kwRU02WHRrVEhQOU5QMlRTR1VFN1E5SGYvU0VEc2V0a25hZXhvWmhDczJLWDFMeU5JS0U0N2pkMkR3MTUreDRRVXV0VUFTbzU5Q1lHMVFBeW9BVVhrV3dtbXkzTGdTUWp5T3ZLV25qaE8veWpPd0FyWGd0NFBrSVVnZDQ1N05ReFpMbU41K0J4NVJoQ0FHdkUxYmxOZjlMek9keGJiaG5VZ2Z1RDM5MXVSRkhjS2RYREY3ZmVqb3gveThtaWZJcTRWVzQyajBHQnFOQUtkK0prMnJCMW9hOTRiT2hxcVVzanhqWnlRaGRXTzhNblR6T2tOaGVpZXU2blYxcW5yZ3JHU2huWTNJMlczb29GNFNnczRjZ3drZ2h2dHpFa0xUbU5OUm83RTdudVRuMkxJcmlGSnlvTmZQdUp0aWN0S0JtNzRGZytkWVBTMlIzTzNmOWxBZWxiVWZjbzZGNU9EL3hk
S1VuRTh0V3FOMExVcDlWQUptWVZYZFVDaGJ4MjM4MWtDaStLNDJoRzUydFNQYU1hb1dTb0xQY2Zrb24rc1pYdjdEdEtwZi9HTzdhcUMza1pzRGpva29haHJGZGJWSlNTZWhrNGp5K3RzRHplQnJKSjBrMVZrUnJHN1NoVHZjTmd1cjVucVRUTEE5dlJMQmJNTTlhNlI1NEZ0Z1pQOWFKMU1aMEdCcUVpMnF6Ui8yd2tYQlhwcFhZdi9TcU1RV1dhbTVsSHBMVktxaDN4ZHRjNFdmck9mYldsbU1PNXA5Z0JUSFp1YUcxVGFkZXFRVVpKQmZBS01ENFdSR0NsMDFaeDRTVzE0YzZrdnFKdXExL080N215L3RsVHlLWndpYlBkQTNRMVVGd0I3R2Z4anEwaDN2ckxFbUNrS3Vsc0VBUkN6UnZNVjJSVnBVbFpUV240Y1Boc0hjcTNROElHSUYyKy9nOENFSU4vMU8xcVMvMkpXcXlDNmtIb0w4Y2R2R0VHbmkxSTNDTk1JcXhxaHhJL1V0R3REc2VwYmwrSHI0elh4MzZna3BCbXBoT2xkTFVYTHAzVEtibVVZRWJSWHcvZmRmeFQ3WDdZUFhHQ0hHVG1uTzk4WkxDOTA2Zmkvekd2b04rNlpzbCs3MkpWMGxJWEo0V3dZdWxFUmZHbkFDWGNoa0Yzei9ITWR3elcwTUFFaXptQmwvREo2ZUoyU01PSG1Uc25YbElGRDRlcFRrYnFBQ0dpZ2I1UExFdHdQRVRjYkNRckM5YUtTU1FnSTdEZXd1aWlxM2J0Y0RUWkIzeEI5WWxlbmhpU0FXNjIwcmwzc2ZjY3d3eGFSOHBDV2Rzd0x3dmFxcDhjM01PV3RCc2xPcmVTSkNEcWgvdzBYbm1WMFJVWFpNM2JvUmkwVXhsaHVUeDFlM1NTd09pbTlOczNYV3NoTmI4Lzc3VkhnUWhRVFlSUU1NRllYaWRmMElCKzBtSUpocWNoQTlUe
UY3dGRjSDhrUUJUSHNEWS96bFpqK3EwNlFMd0JkbTkxc3IyK3VzZmxlaXB3WUMrcmdiNHROVnA3VU5rYkVqTnR6ZWZsTi9VRTlkbHZtT2x6V1dtZkh2NGVkUGkzMmJmeUNRS1d6SGJVVEV3NU0yVFpsZnpNaTFWUjVsaDBxQ1lqaDNITUlmL2MwcHBKd2I1b1lFTnBBenlxbnlmdmlTV3lBYzc2L1l1VWwvb2FVaysrYzBZc2d1TGo5ZGFQdVVvemhoZ3VjSytQRGlNckI0ODU1Mk83VWg0aHRwNmZ3S2dJa1JCTVFIUTd6MmV5WXovV1AwQm9ZZVhjOGc3aUprclhFNzA1bFo1bXhGU0poT3E1WlNleVJSb21pUm41K3VRemM5ZFdWQjBYb2JURXdOc0VRM2FIZ25JY29BczY2UGplUT09PC94ZW5jOkNpcGhlclZhbHVlPjwveGVuYzpDaXBoZXJEYXRhPjwveGVuYzpFbmNyeXB0ZWREYXRhPjwvc2FtbDI6RW5jcnlwdGVkQXNzZXJ0aW9uPjwvc2FtbDJwOlJlc3BvbnNlPg==
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/backends/oauth.py
new/social-core-4.5.1/social_core/tests/backends/oauth.py
--- old/social-core-4.5.0/social_core/tests/backends/oauth.py 2023-10-31
13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/tests/backends/oauth.py 2023-11-29
09:52:23.000000000 +0100
@@ -1,7 +1,7 @@
from urllib.parse import urlparse
import requests
-from httpretty import HTTPretty
+from httpretty import HTTPretty, latest_requests
from ...utils import parse_qs, url_add_parameters
from ..models import User
@@ -121,3 +121,57 @@
social = user.social[0]
social.refresh_token(strategy=self.strategy,
**self.refresh_token_arguments())
return user, social
+
+
+class OAuth2PkcePlainTest(OAuth2Test):
+ def extra_settings(self):
+ settings = super().extra_settings()
+ settings.update(
+ {f"SOCIAL_AUTH_{self.name}_PKCE_CODE_CHALLENGE_METHOD": "plain"}
+ )
+ return settings
+
+ def do_login(self):
+ user = super().do_login()
+
+ requests = latest_requests()
+ auth_request = [
+ r for r in requests if self.backend.authorization_url() in r.url
+ ][0]
+ code_challenge = auth_request.querystring.get("code_challenge")[0]
+ code_challenge_method =
auth_request.querystring.get("code_challenge_method")[0]
+ self.assertIsNotNone(code_challenge)
+ self.assertEqual(code_challenge_method, "plain")
+
+ auth_complete = [
+ r for r in requests if self.backend.access_token_url() in r.url
+ ][0]
+ code_verifier = auth_complete.parsed_body.get("code_verifier")[0]
+ self.assertEqual(code_challenge, code_verifier)
+
+ return user
+
+
+class OAuth2PkceS256Test(OAuth2Test):
+ def do_login(self):
+ # use default value of PKCE_CODE_CHALLENGE_METHOD (s256)
+ user = super().do_login()
+
+ requests = latest_requests()
+ auth_request = [
+ r for r in requests if self.backend.authorization_url() in r.url
+ ][0]
+ code_challenge = auth_request.querystring.get("code_challenge")[0]
+ code_challenge_method =
auth_request.querystring.get("code_challenge_method")[0]
+ self.assertIsNotNone(code_challenge)
+ self.assertEqual(code_challenge_method, "s256")
+
+ auth_complete = [
+ r for r in requests if self.backend.access_token_url() in r.url
+ ][0]
+ code_verifier = auth_complete.parsed_body.get("code_verifier")[0]
+ self.assertEqual(
+ self.backend.generate_code_challenge(code_verifier, "s256"),
code_challenge
+ )
+
+ return user
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/backends/test_bitbucket_datacenter.py
new/social-core-4.5.1/social_core/tests/backends/test_bitbucket_datacenter.py
---
old/social-core-4.5.0/social_core/tests/backends/test_bitbucket_datacenter.py
1970-01-01 01:00:00.000000000 +0100
+++
new/social-core-4.5.1/social_core/tests/backends/test_bitbucket_datacenter.py
2023-11-29 09:52:23.000000000 +0100
@@ -0,0 +1,151 @@
+import json
+
+from httpretty import HTTPretty
+
+from .oauth import OAuth2PkcePlainTest, OAuth2PkceS256Test
+
+
+class BitbucketDataCenterOAuth2Mixin:
+ backend_path =
"social_core.backends.bitbucket_datacenter.BitbucketDataCenterOAuth2"
+ application_properties_url = (
+
"https://bachmanity.atlassian.net/rest/api/latest/application-properties"
+ )
+ application_properties_headers = {"x-ausername": "erlich-bachman"}
+ application_properties_body = json.dumps(
+ {
+ "version": "8.15.0",
+ "buildNumber": "8015000",
+ "buildDate": "1697764661289",
+ "displayName": "Bitbucket",
+ }
+ )
+ user_data_url = (
+ "https://bachmanity.atlassian.net/rest/api/latest/users/erlich-bachman"
+ )
+ user_data_body = json.dumps(
+ {
+ "name": "erlich-bachman",
+ "emailAddress": "[email protected]",
+ "active": True,
+ "displayName": "Erlich Bachman",
+ "id": 1,
+ "slug": "erlich-bachman",
+ "type": "NORMAL",
+ "links": {
+ "self": [
+ {"href":
"https://bachmanity.atlassian.net/users/erlich-bachman"}
+ ]
+ },
+ "avatarUrl":
"http://www.gravatar.com/avatar/af7d968fe79ea45271e3100391824b79.jpg?s=48&d=mm",
+ }
+ )
+ access_token_body = json.dumps(
+ {
+ "scope": "PUBLIC_REPOS",
+ "access_token": "dummy_access_token",
+ "token_type": "bearer",
+ "expires_in": 3600,
+ "refresh_token": "dummy_refresh_token",
+ }
+ )
+ refresh_token_body = json.dumps(
+ {
+ "scope": "PUBLIC_REPOS",
+ "access_token": "dummy_access_token_refreshed",
+ "token_type": "bearer",
+ "expires_in": 3600,
+ "refresh_token": "dummy_refresh_token_refreshed",
+ }
+ )
+ expected_username = "erlich-bachman"
+
+ def extra_settings(self):
+ settings = super().extra_settings()
+ settings.update(
+ {f"SOCIAL_AUTH_{self.name}_URL":
"https://bachmanity.atlassian.net"}
+ )
+ return settings
+
+ def auth_handlers(self, start_url):
+ target_url = super().auth_handlers(start_url)
+ HTTPretty.register_uri(
+ HTTPretty.GET,
+ self.application_properties_url,
+ body=self.application_properties_body,
+ adding_headers=self.application_properties_headers,
+ content_type="text/json",
+ )
+ return target_url
+
+ def test_login(self):
+ user = self.do_login()
+
+ self.assertEqual(len(user.social), 1)
+
+ social = user.social[0]
+ self.assertEqual(social.uid, 1)
+ self.assertEqual(social.extra_data["first_name"], "Erlich")
+ self.assertEqual(social.extra_data["last_name"], "Bachman")
+ self.assertEqual(social.extra_data["email"], "[email protected]")
+ self.assertEqual(social.extra_data["name"], "erlich-bachman")
+ self.assertEqual(social.extra_data["username"], "erlich-bachman")
+ self.assertEqual(social.extra_data["display_name"], "Erlich Bachman")
+ self.assertEqual(social.extra_data["type"], "NORMAL")
+ self.assertEqual(social.extra_data["active"], True)
+ self.assertEqual(
+ social.extra_data["url"],
+ "https://bachmanity.atlassian.net/users/erlich-bachman",
+ )
+ self.assertEqual(
+ social.extra_data["avatar_url"],
+
"http://www.gravatar.com/avatar/af7d968fe79ea45271e3100391824b79.jpg?s=48&d=mm",
+ )
+ self.assertEqual(social.extra_data["scope"], "PUBLIC_REPOS")
+ self.assertEqual(social.extra_data["access_token"],
"dummy_access_token")
+ self.assertEqual(social.extra_data["token_type"], "bearer")
+ self.assertEqual(social.extra_data["expires"], 3600)
+ self.assertEqual(social.extra_data["refresh_token"],
"dummy_refresh_token")
+
+ def test_refresh_token(self):
+ _, social = self.do_refresh_token()
+
+ self.assertEqual(social.uid, 1)
+ self.assertEqual(social.extra_data["first_name"], "Erlich")
+ self.assertEqual(social.extra_data["last_name"], "Bachman")
+ self.assertEqual(social.extra_data["email"], "[email protected]")
+ self.assertEqual(social.extra_data["name"], "erlich-bachman")
+ self.assertEqual(social.extra_data["username"], "erlich-bachman")
+ self.assertEqual(social.extra_data["display_name"], "Erlich Bachman")
+ self.assertEqual(social.extra_data["type"], "NORMAL")
+ self.assertEqual(social.extra_data["active"], True)
+ self.assertEqual(
+ social.extra_data["url"],
+ "https://bachmanity.atlassian.net/users/erlich-bachman",
+ )
+ self.assertEqual(
+ social.extra_data["avatar_url"],
+
"http://www.gravatar.com/avatar/af7d968fe79ea45271e3100391824b79.jpg?s=48&d=mm",
+ )
+ self.assertEqual(social.extra_data["scope"], "PUBLIC_REPOS")
+ self.assertEqual(
+ social.extra_data["access_token"], "dummy_access_token_refreshed"
+ )
+ self.assertEqual(social.extra_data["token_type"], "bearer")
+ self.assertEqual(social.extra_data["expires"], 3600)
+ self.assertEqual(
+ social.extra_data["refresh_token"], "dummy_refresh_token_refreshed"
+ )
+
+
+class BitbucketDataCenterOAuth2TestPkcePlain(
+ BitbucketDataCenterOAuth2Mixin,
+ OAuth2PkcePlainTest,
+):
+ pass
+
+
+class BitbucketDataCenterOAuth2TestPkceS256(
+ BitbucketDataCenterOAuth2Mixin,
+ OAuth2PkceS256Test,
+):
+ pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/backends/test_discogs.py
new/social-core-4.5.1/social_core/tests/backends/test_discogs.py
--- old/social-core-4.5.0/social_core/tests/backends/test_discogs.py
1970-01-01 01:00:00.000000000 +0100
+++ new/social-core-4.5.1/social_core/tests/backends/test_discogs.py
2023-11-29 09:52:23.000000000 +0100
@@ -0,0 +1,94 @@
+import json
+from urllib.parse import urlencode
+
+from httpretty import HTTPretty
+
+from .oauth import OAuth1Test
+
+
+class DiscsogsOAuth1Test(OAuth1Test):
+ _test_token = "lalala123boink"
+ backend_path = "social_core.backends.discogs.DiscogsOAuth1"
+ expected_username = "rodneyfool"
+ raw_complete_url = (
+
f"/complete/{0}/?oauth_verifier=wimblewomblefartfart&oauth_token={_test_token}"
+ )
+
+ access_token_body = json.dumps(
+ {"access_token": _test_token, "token_type": "bearer"}
+ )
+ request_token_body = urlencode(
+ {
+ "oauth_token": _test_token,
+ "oauth_token_secret": "xyz789",
+ "oauth_callback_confirmed": "true",
+ }
+ )
+
+ user_data_body = json.dumps(
+ {
+ "profile": "I am a software developer for
Discogs.\r\n\r\n[img=http://i.imgur.com/IAk3Ukk.gif]",
+ "wantlist_url": "https://api.discogs.com/users/rodneyfool/wants",
+ "rank": 149,
+ "num_pending": 61,
+ "id": 1578108,
+ "num_for_sale": 0,
+ "home_page": "",
+ "location": "I live in the good ol' Pacific NW",
+ "collection_folders_url":
"https://api.discogs.com/users/rodneyfool/collection/folders",
+ "username": expected_username,
+ "collection_fields_url":
"https://api.discogs.com/users/rodneyfool/collection/fields",
+ "releases_contributed": 5,
+ "registered": "2012-08-15T21:13:36-07:00",
+ "rating_avg": 3.47,
+ "num_collection": 78,
+ "releases_rated": 116,
+ "num_lists": 0,
+ "name": "Rodney",
+ "num_wantlist": 160,
+ "inventory_url":
"https://api.discogs.com/users/rodneyfool/inventory",
+ "avatar_url":
"http://www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=52&r=pg&d=mm",
+ "banner_url": (
+
"https://img.discogs.com/dhuJe-pRJmod7hN3cdVi2PugEh4=/1600x400/"
+
"filters:strip_icc():format(jpeg)/discogs-banners/B-1578108-user-1436314164-9231.jpg.jpg"
+ ),
+ "uri": "https://www.discogs.com/user/rodneyfool",
+ "resource_url": "https://api.discogs.com/users/rodneyfool",
+ "buyer_rating": 100.00,
+ "buyer_rating_stars": 5,
+ "buyer_num_ratings": 144,
+ "seller_rating": 100.00,
+ "seller_rating_stars": 5,
+ "seller_num_ratings": 21,
+ "curr_abbr": "USD",
+ }
+ )
+
+ def _mock(self):
+ HTTPretty.register_uri(
+ HTTPretty.GET,
+ uri="https://api.discogs.com/oauth/identity",
+ status=200,
+ body=json.dumps(
+ {
+ "id": 1,
+ "username": self.expected_username,
+ "resource_url":
f"https://api.discogs.com/users/{self.expected_username}",
+ "consumer_name": "SocialCore Discogs Test",
+ }
+ ),
+ )
+ HTTPretty.register_uri(
+ HTTPretty.GET,
+ f"https://api.discogs.com/users/{self.expected_username}",
+ status=200,
+ body=self.user_data_body,
+ )
+
+ def test_login(self):
+ self._mock()
+ self.do_login()
+
+ def test_partial_pipeline(self):
+ self._mock()
+ self.do_partial_pipeline()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/backends/test_saml.py
new/social-core-4.5.1/social_core/tests/backends/test_saml.py
--- old/social-core-4.5.0/social_core/tests/backends/test_saml.py
2023-10-31 13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/tests/backends/test_saml.py
2023-11-29 09:52:23.000000000 +0100
@@ -32,6 +32,7 @@
class SAMLTest(BaseBackendTest):
backend_path = "social_core.backends.saml.SAMLAuth"
expected_username = "myself"
+ response_fixture = "saml_response.txt"
def extra_settings(self):
name = path.join(DATA_DIR, "saml_config.json")
@@ -58,7 +59,7 @@
# we will eventually get a redirect back, with SAML assertion
# data in the query string. A pre-recorded correct response
# is kept in this .txt file:
- name = path.join(DATA_DIR, "saml_response.txt")
+ name = path.join(DATA_DIR, self.response_fixture)
with open(name) as response_file:
response_url = response_file.read()
HTTPretty.register_uri(
@@ -91,14 +92,55 @@
self.assertEqual(len(errors), 0)
self.assertEqual(xml.decode()[0], "<")
- def test_login(self):
- """Test that we can authenticate with a SAML IdP (TestShib)"""
- # pretend we've started with a URL like /login/saml/?idp=testshib:
+ def test_login_with_next_url(self):
+ """
+ Test that we login and then redirect to the "next" URL.
+ """
+ # pretend we've started with a URL like
/login/saml/?idp=testshib&next=/foo/bar
+ self.strategy.set_request_data(
+ {"idp": "testshib", "next": "/foo/bar"}, self.backend
+ )
+ self.do_login()
+ # The core `do_complete` action assumes the "next" URL is stored in
session state or the request data.
+ self.assertEqual(self.strategy.session_get("next"), "/foo/bar")
+
+ def test_login_no_next_url(self):
+ """
+ Test that we handle "next" being omitted from the request data and
RelayState.
+ """
+ self.response_fixture = "saml_response_no_next_url.txt"
+
+ # pretend we've started with a URL like /login/saml/?idp=testshib
+ self.strategy.set_request_data({"idp": "testshib"}, self.backend)
+ self.do_login()
+ self.assertEqual(self.strategy.session_get("next"), None)
+
+ def test_login_with_legacy_relay_state(self):
+ """
+ Test that we handle legacy RelayState (i.e. just the IDP name, not a
JSON object).
+
+ This is the form that RelayState had in prior versions of this
library. It should be supported for backwards
+ compatibility.
+ """
+ self.response_fixture = "saml_response_legacy.txt"
+
self.strategy.set_request_data({"idp": "testshib"}, self.backend)
self.do_login()
- def test_login_no_idp(self):
- """Logging in without an idp param should raise AuthMissingParameter"""
+ def test_login_no_idp_in_initial_request(self):
+ """
+ Logging in without an idp param should raise AuthMissingParameter
+ """
+ with self.assertRaises(AuthMissingParameter):
+ self.do_start()
+
+ def test_login_no_idp_in_saml_response(self):
+ """
+ The RelayState should always contain a JSON object with an "idp" key,
or be just the IDP name as a string.
+ This tests that an exception is raised if it is a JSON object, but is
missing the "idp" key.
+ """
+ self.response_fixture = "saml_response_no_idp_name.txt"
+
with self.assertRaises(AuthMissingParameter):
self.do_start()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/social-core-4.5.0/social_core/tests/backends/test_twitter_oauth2.py
new/social-core-4.5.1/social_core/tests/backends/test_twitter_oauth2.py
--- old/social-core-4.5.0/social_core/tests/backends/test_twitter_oauth2.py
2023-10-31 13:44:09.000000000 +0100
+++ new/social-core-4.5.1/social_core/tests/backends/test_twitter_oauth2.py
2023-11-29 09:52:23.000000000 +0100
@@ -1,13 +1,11 @@
import json
-import httpretty
-
from social_core.exceptions import AuthException
-from .oauth import OAuth2Test
+from .oauth import OAuth2PkcePlainTest, OAuth2PkceS256Test, OAuth2Test
-class TwitterOAuth2Test(OAuth2Test):
+class TwitterOAuth2Mixin:
backend_path = "social_core.backends.twitter_oauth2.TwitterOAuth2"
user_data_url = "https://api.twitter.com/2/users/me"
access_token_body = json.dumps(
@@ -172,58 +170,21 @@
self.assertIsNone(social.extra_data.get("public_metrics"))
-class TwitterOAuth2TestPkcePlain(TwitterOAuth2Test):
- def test_login(self):
- self.strategy.set_settings(
- {"SOCIAL_AUTH_TWITTER_OAUTH2_PKCE_CODE_CHALLENGE_METHOD": "plain"}
- )
-
- self.do_login()
-
- requests = httpretty.latest_requests()
- auth_request = [
- r for r in requests if "https://twitter.com/i/oauth2/authorize" in
r.url
- ][0]
- code_challenge = auth_request.querystring.get("code_challenge")[0]
- code_challenge_method =
auth_request.querystring.get("code_challenge_method")[0]
- self.assertIsNotNone(code_challenge)
- self.assertEqual(code_challenge_method, "plain")
-
- auth_complete = [
- r for r in requests if "https://api.twitter.com/2/oauth2/token" in
r.url
- ][0]
- code_verifier = auth_complete.parsed_body.get("code_verifier")[0]
- self.assertEqual(code_challenge, code_verifier)
-
+class TwitterOAuth2TestPkcePlain(TwitterOAuth2Mixin, OAuth2PkcePlainTest):
+ pass
-class TwitterOAuth2TestPkceS256(TwitterOAuth2Test):
- def test_login(self):
- # use default value of PKCE_CODE_CHALLENGE_METHOD (s256)
- self.do_login()
- requests = httpretty.latest_requests()
- auth_request = [
- r for r in requests if "https://twitter.com/i/oauth2/authorize" in
r.url
- ][0]
- code_challenge = auth_request.querystring.get("code_challenge")[0]
- code_challenge_method =
auth_request.querystring.get("code_challenge_method")[0]
- self.assertIsNotNone(code_challenge)
- self.assertEqual(code_challenge_method, "s256")
-
- auth_complete = [
- r for r in requests if "https://api.twitter.com/2/oauth2/toke" in
r.url
- ][0]
- code_verifier = auth_complete.parsed_body.get("code_verifier")[0]
- self.assertEqual(
- self.backend.generate_code_challenge(code_verifier, "s256"),
code_challenge
- )
+class TwitterOAuth2TestPkceS256(TwitterOAuth2Mixin, OAuth2PkceS256Test):
+ pass
-class TwitterOAuth2TestInvalidCodeChallengeMethod(TwitterOAuth2Test):
+class TwitterOAuth2TestInvalidCodeChallengeMethod(
+ TwitterOAuth2Mixin, OAuth2PkcePlainTest
+):
def test_login__error(self):
self.strategy.set_settings(
{
- "SOCIAL_AUTH_TWITTER_OAUTH2_PKCE_CODE_CHALLENGE_METHOD":
"invalidmethodname"
+ f"SOCIAL_AUTH_{self.name}_PKCE_CODE_CHALLENGE_METHOD":
"invalidmethodname",
}
)