Hello community,

here is the log from the commit of package python-social-auth-core for 
openSUSE:Factory checked in at 2019-06-03 18:57:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-social-auth-core (Old)
 and      /work/SRC/openSUSE:Factory/.python-social-auth-core.new.5148 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-social-auth-core"

Mon Jun  3 18:57:53 2019 rev:7 rq:707119 version:3.2.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-social-auth-core/python-social-auth-core.changes
  2019-05-06 13:21:40.240574315 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-social-auth-core.new.5148/python-social-auth-core.changes
        2019-06-03 18:57:56.288371710 +0200
@@ -1,0 +2,8 @@
+Mon Jun  3 10:08:47 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 3.2.0:
+  * Cognito backend
+  * OpenStack (openstackid and openstackid-dev) backends
+  * Many fixes to all existing Backends to match up upstream projects
+
+-------------------------------------------------------------------

Old:
----
  social-auth-core-3.1.0.tar.gz

New:
----
  social-auth-core-3.2.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-social-auth-core.spec ++++++
--- /var/tmp/diff_new_pack.zbP2Tg/_old  2019-06-03 18:57:57.420371289 +0200
+++ /var/tmp/diff_new_pack.zbP2Tg/_new  2019-06-03 18:57:57.420371289 +0200
@@ -19,7 +19,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-social-auth-core
-Version:        3.1.0
+Version:        3.2.0
 Release:        0
 Summary:        Python Social Auth Core
 License:        BSD-3-Clause

++++++ social-auth-core-3.1.0.tar.gz -> social-auth-core-3.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-auth-core-3.1.0/CHANGELOG.md 
new/social-auth-core-3.2.0/CHANGELOG.md
--- old/social-auth-core-3.1.0/CHANGELOG.md     2019-02-20 14:58:25.000000000 
+0100
+++ new/social-auth-core-3.2.0/CHANGELOG.md     2019-05-30 07:07:03.000000000 
+0200
@@ -7,6 +7,29 @@
 
 ## 
[Unreleased](https://github.com/python-social-auth/social-core/commits/master)
 
+## 
[3.2.0](https://github.com/python-social-auth/social-core/releases/tag/3.2.0) - 
2019-05-30
+
+### Added
+- Cognito backend
+- OpenStack (openstackid and openstackid-dev) backends
+
+### Changed
+- Updated Linkedin backend to v2 API
+- Facebook: Update to use the latest Graph API v3.2
+- Send User-Agent header on GitHub backend
+- Remove profile scope and verification at hash on Elixir backend
+- Mark description as Markdown for PyPI
+- Use `hmac.compare_digest` for constant time comparision
+- Replace deprecated Google+ API usage in GoogleOpenIdConnect
+- Defined scope separator for Strava backend
+- Ensure `saml_config.json` is included by addint it to `MANIFEST.in`
+- Include `email_verified` as part of user details on Auth0 backend
+- Include Shopify `version` parameter on Shopify session setup
+- Define `SOCIAL_AUTH_SHOPIFY_API_VERSION` setting to override default API 
version
+- Check user `id` attribute existence before using it
+- Pull `last_name` from `family_name` in Cognito backend
+- Ignore key errors on Naver backend for missing attributes
+
 ## 
[3.1.0](https://github.com/python-social-auth/social-core/releases/tag/3.1.0) - 
2019-02-20
 
 ### Added
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-auth-core-3.1.0/MANIFEST.in 
new/social-auth-core-3.2.0/MANIFEST.in
--- old/social-auth-core-3.1.0/MANIFEST.in      2018-08-20 15:44:10.000000000 
+0200
+++ new/social-auth-core-3.2.0/MANIFEST.in      2019-04-21 15:29:41.000000000 
+0200
@@ -1,7 +1,7 @@
 global-include *.py
 
 include *.txt CHANGELOG.md LICENSE README.md social_core/tests/testkey.pem
-recursive-include social_core/tests *.txt
+recursive-include social_core/tests *.txt *.json
 
 graft examples
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-auth-core-3.1.0/PKG-INFO 
new/social-auth-core-3.2.0/PKG-INFO
--- old/social-auth-core-3.1.0/PKG-INFO 2019-02-20 14:59:01.000000000 +0100
+++ new/social-auth-core-3.2.0/PKG-INFO 2019-05-30 07:09:54.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: social-auth-core
-Version: 3.1.0
+Version: 3.2.0
 Summary: Python social authentication made simple.
 Home-page: https://github.com/python-social-auth/social-core
 Author: Matias Aguirre
@@ -60,9 +60,10 @@
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
+Description-Content-Type: text/markdown
 Provides-Extra: openidconnect
-Provides-Extra: saml
 Provides-Extra: allpy2
 Provides-Extra: azuread
-Provides-Extra: allpy3
 Provides-Extra: all
+Provides-Extra: saml
+Provides-Extra: allpy3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-auth-core-3.1.0/setup.py 
new/social-auth-core-3.2.0/setup.py
--- old/social-auth-core-3.1.0/setup.py 2019-02-18 16:56:13.000000000 +0100
+++ new/social-auth-core-3.2.0/setup.py 2019-04-07 15:28:25.000000000 +0200
@@ -82,6 +82,7 @@
         'social_core.tests.backends.data'
     ],
     long_description=long_description() or LONG_DESCRIPTION,
+    long_description_content_type="text/markdown",
     install_requires=requirements,
     extras_require={
         'openidconnect': [requirements_openidconnect],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_auth_core.egg-info/PKG-INFO 
new/social-auth-core-3.2.0/social_auth_core.egg-info/PKG-INFO
--- old/social-auth-core-3.1.0/social_auth_core.egg-info/PKG-INFO       
2019-02-20 14:59:00.000000000 +0100
+++ new/social-auth-core-3.2.0/social_auth_core.egg-info/PKG-INFO       
2019-05-30 07:09:53.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: social-auth-core
-Version: 3.1.0
+Version: 3.2.0
 Summary: Python social authentication made simple.
 Home-page: https://github.com/python-social-auth/social-core
 Author: Matias Aguirre
@@ -60,9 +60,10 @@
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
+Description-Content-Type: text/markdown
 Provides-Extra: openidconnect
-Provides-Extra: saml
 Provides-Extra: allpy2
 Provides-Extra: azuread
-Provides-Extra: allpy3
 Provides-Extra: all
+Provides-Extra: saml
+Provides-Extra: allpy3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_auth_core.egg-info/SOURCES.txt 
new/social-auth-core-3.2.0/social_auth_core.egg-info/SOURCES.txt
--- old/social-auth-core-3.1.0/social_auth_core.egg-info/SOURCES.txt    
2019-02-20 14:59:01.000000000 +0100
+++ new/social-auth-core-3.2.0/social_auth_core.egg-info/SOURCES.txt    
2019-05-30 07:09:54.000000000 +0200
@@ -49,6 +49,7 @@
 social_core/backends/classlink.py
 social_core/backends/clef.py
 social_core/backends/coding.py
+social_core/backends/cognito.py
 social_core/backends/coinbase.py
 social_core/backends/coursera.py
 social_core/backends/dailymotion.py
@@ -121,6 +122,8 @@
 social_core/backends/open_id.py
 social_core/backends/open_id_connect.py
 social_core/backends/openshift.py
+social_core/backends/openstack.py
+social_core/backends/openstackdev.py
 social_core/backends/openstreetmap.py
 social_core/backends/orbi.py
 social_core/backends/orcid.py
@@ -233,6 +236,7 @@
 social_core/tests/backends/test_broken.py
 social_core/tests/backends/test_chatwork.py
 social_core/tests/backends/test_clef.py
+social_core/tests/backends/test_cognito.py
 social_core/tests/backends/test_coinbase.py
 social_core/tests/backends/test_coursera.py
 social_core/tests/backends/test_dailymotion.py
@@ -314,4 +318,5 @@
 social_core/tests/backends/test_yammer.py
 social_core/tests/backends/test_yandex.py
 social_core/tests/backends/test_zotero.py
+social_core/tests/backends/data/saml_config.json
 social_core/tests/backends/data/saml_response.txt
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-auth-core-3.1.0/social_core/__init__.py 
new/social-auth-core-3.2.0/social_core/__init__.py
--- old/social-auth-core-3.1.0/social_core/__init__.py  2019-02-20 
14:57:46.000000000 +0100
+++ new/social-auth-core-3.2.0/social_core/__init__.py  2019-05-30 
07:06:39.000000000 +0200
@@ -1 +1 @@
-__version__ = '3.1.0'
+__version__ = '3.2.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-auth-core-3.1.0/social_core/backends/auth0.py 
new/social-auth-core-3.2.0/social_core/backends/auth0.py
--- old/social-auth-core-3.1.0/social_core/backends/auth0.py    2019-02-18 
16:45:39.000000000 +0100
+++ new/social-auth-core-3.2.0/social_core/backends/auth0.py    2019-04-21 
15:34:42.000000000 +0200
@@ -45,6 +45,7 @@
         fullname, first_name, last_name = self.get_user_names(payload['name'])
         return {'username': payload['nickname'],
                 'email': payload['email'],
+                'email_verified': payload.get('email_verified', False),
                 'fullname': fullname,
                 'first_name': first_name,
                 'last_name': last_name,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/backends/cognito.py 
new/social-auth-core-3.2.0/social_core/backends/cognito.py
--- old/social-auth-core-3.1.0/social_core/backends/cognito.py  1970-01-01 
01:00:00.000000000 +0100
+++ new/social-auth-core-3.2.0/social_core/backends/cognito.py  2019-05-30 
06:45:47.000000000 +0200
@@ -0,0 +1,51 @@
+from social_core.backends.oauth import BaseOAuth2
+
+
+class CognitoOAuth2(BaseOAuth2):
+    name = 'cognito'
+    ID_KEY = 'username'
+    DEFAULT_SCOPE = ['openid', 'profile', 'email']
+    ACCESS_TOKEN_METHOD = 'POST'
+    REDIRECT_STATE = False
+
+    def user_pool_domain(self):
+        return self.setting('POOL_DOMAIN')
+
+    def authorization_url(self):
+        return '{}/login'.format(self.user_pool_domain())
+
+    def access_token_url(self):
+        return '{}/oauth2/token'.format(self.user_pool_domain())
+
+    def user_data_url(self):
+        return '{}/oauth2/userInfo'.format(self.user_pool_domain())
+
+    def get_user_details(self, response):
+        """Return user details from their cognito pool account"""
+        first_name = response.get('given_name') or ''
+        last_name = response.get('family_name') or ''
+        fullname, first_name, last_name = self.get_user_names(
+            first_name=first_name,
+            last_name=last_name,
+        )
+        return {'username': response.get('username') or response.get('email'),
+                'email': response.get('email'),
+                'fullname': fullname,
+                'first_name': first_name,
+                'last_name': last_name}
+
+    def user_data(self, access_token, *args, **kwargs):
+        """Grab user profile information from cognito."""
+        response = self.get_json(
+            url=self.user_data_url(),
+            headers={'Authorization': 'Bearer {}'.format(access_token)},
+        )
+
+        user_data = {
+            'given_name': response.get('given_name'),
+            'family_name': response.get('family_name'),
+            'username': response.get('username'),
+            'email': response.get('email'),
+        }
+
+        return user_data
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/backends/elixir.py 
new/social-auth-core-3.2.0/social_core/backends/elixir.py
--- old/social-auth-core-3.1.0/social_core/backends/elixir.py   2018-10-28 
20:22:07.000000000 +0100
+++ new/social-auth-core-3.2.0/social_core/backends/elixir.py   2019-04-07 
15:28:25.000000000 +0200
@@ -15,6 +15,11 @@
         ('id_token', 'id_token', True),
         ('other_tokens', 'other_tokens', True),
     ]
+    # In order to get any scopes, you have to register your service with
+    # ELIXIR, see documentation at
+    # https://www.elixir-europe.org/services/compute/aai
+    DEFAULT_SCOPE = ['openid', 'email']
+    JWT_DECODE_OPTIONS = {'verify_at_hash': False}
 
     def get_user_details(self, response):
         username_key = self.setting('USERNAME_KEY', default=self.USERNAME_KEY)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/backends/facebook.py 
new/social-auth-core-3.2.0/social_core/backends/facebook.py
--- old/social-auth-core-3.1.0/social_core/backends/facebook.py 2018-08-30 
16:55:12.000000000 +0200
+++ new/social-auth-core-3.2.0/social_core/backends/facebook.py 2019-04-10 
14:14:40.000000000 +0200
@@ -14,7 +14,7 @@
                          AuthMissingParameter
 
 
-API_VERSION = 2.9
+API_VERSION = 3.2
 
 
 class FacebookOAuth2(BaseOAuth2):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/backends/github.py 
new/social-auth-core-3.2.0/social_core/backends/github.py
--- old/social-auth-core-3.1.0/social_core/backends/github.py   2018-08-20 
15:44:10.000000000 +0200
+++ new/social-auth-core-3.2.0/social_core/backends/github.py   2019-04-07 
15:28:25.000000000 +0200
@@ -20,6 +20,7 @@
     SCOPE_SEPARATOR = ','
     REDIRECT_STATE = False
     STATE_PARAMETER = True
+    SEND_USER_AGENT = True
     EXTRA_DATA = [
         ('id', 'id'),
         ('expires', 'expires'),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/backends/google_openidconnect.py 
new/social-auth-core-3.2.0/social_core/backends/google_openidconnect.py
--- old/social-auth-core-3.1.0/social_core/backends/google_openidconnect.py     
2018-08-20 15:44:10.000000000 +0200
+++ new/social-auth-core-3.2.0/social_core/backends/google_openidconnect.py     
2019-04-07 15:28:25.000000000 +0200
@@ -16,6 +16,6 @@
     def user_data(self, access_token, *args, **kwargs):
         """Return user data from Google API"""
         return self.get_json(
-            'https://www.googleapis.com/plus/v1/people/me/openIdConnect',
+            'https://openidconnect.googleapis.com/v1/userinfo',
             params={'access_token': access_token, 'alt': 'json'}
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/backends/linkedin.py 
new/social-auth-core-3.2.0/social_core/backends/linkedin.py
--- old/social-auth-core-3.1.0/social_core/backends/linkedin.py 2018-08-20 
15:44:10.000000000 +0200
+++ new/social-auth-core-3.2.0/social_core/backends/linkedin.py 2019-04-07 
14:33:19.000000000 +0200
@@ -2,94 +2,108 @@
 LinkedIn OAuth1 and OAuth2 backend, docs at:
     https://python-social-auth.readthedocs.io/en/latest/backends/linkedin.html
 """
-from .oauth import BaseOAuth1, BaseOAuth2
+from social_core.exceptions import AuthCanceled
+from .oauth import BaseOAuth2
 
 
-class BaseLinkedinAuth(object):
-    EXTRA_DATA = [('id', 'id'),
-                  ('expires_in', 'expires'),
-                  ('first-name', 'first_name', True),
-                  ('last-name', 'last_name', True),
-                  ('firstName', 'first_name', True),
-                  ('lastName', 'last_name', True)]
-    USER_DETAILS = 'https://api.linkedin.com/v1/people/~:({0})'
-
-    def get_user_details(self, response):
-        """Return user details from Linkedin account"""
-        fullname, first_name, last_name = self.get_user_names(
-            first_name=response['firstName'],
-            last_name=response['lastName']
-        )
-        email = response.get('emailAddress', '')
-        return {'username': first_name + last_name,
-                'fullname': fullname,
-                'first_name': first_name,
-                'last_name': last_name,
-                'email': email}
+class LinkedinOAuth2(BaseOAuth2):
+    name = 'linkedin-oauth2'
+    AUTHORIZATION_URL = \
+        'https://www.linkedin.com/oauth/v2/authorization'
+    ACCESS_TOKEN_URL = 'https://www.linkedin.com/oauth/v2/accessToken'
+    USER_DETAILS_URL = \
+        'https://api.linkedin.com/v2/me?projection=({projection})'
+    USER_EMAILS_URL = 'https://api.linkedin.com/v2/emailAddress' \
+                      '?q=members&projection=(elements*(handle~))'
+    ACCESS_TOKEN_METHOD = 'POST'
+    REDIRECT_STATE = False
+    DEFAULT_SCOPE = ['r_liteprofile']
+    EXTRA_DATA = [
+        ('id', 'id'),
+        ('expires_in', 'expires'),
+        ('firstName', 'first_name'),
+        ('lastName', 'last_name')
+    ]
 
     def user_details_url(self):
         # use set() since LinkedIn fails when values are duplicated
-        fields_selectors = list(set(['first-name', 'id', 'last-name'] +
-                                self.setting('FIELD_SELECTORS', [])))
+        fields_selectors = list(set(['id', 'firstName', 'lastName'] +
+                                    self.setting('FIELD_SELECTORS', [])))
         # user sort to ease the tests URL mocking
         fields_selectors.sort()
         fields_selectors = ','.join(fields_selectors)
-        return self.USER_DETAILS.format(fields_selectors)
+        return self.USER_DETAILS_URL.format(projection=fields_selectors)
 
-    def user_data_headers(self):
-        lang = self.setting('FORCE_PROFILE_LANGUAGE')
-        if lang:
-            return {
-                'Accept-Language': lang if lang is not True
-                                        else self.strategy.get_language()
-            }
-
-
-class LinkedinOAuth(BaseLinkedinAuth, BaseOAuth1):
-    """Linkedin OAuth authentication backend"""
-    name = 'linkedin'
-    SCOPE_SEPARATOR = '+'
-    AUTHORIZATION_URL = 'https://www.linkedin.com/uas/oauth/authenticate'
-    REQUEST_TOKEN_URL = 'https://api.linkedin.com/uas/oauth/requestToken'
-    ACCESS_TOKEN_URL = 'https://api.linkedin.com/uas/oauth/accessToken'
+    def user_emails_url(self):
+        return self.USER_EMAILS_URL
 
     def user_data(self, access_token, *args, **kwargs):
-        """Return user data provided"""
-        return self.get_json(
+        response = self.get_json(
             self.user_details_url(),
-            params={'format': 'json'},
-            auth=self.oauth_auth(access_token),
-            headers=self.user_data_headers()
+            headers=self.user_data_headers(access_token)
         )
 
-    def unauthorized_token(self):
-        """Makes first request to oauth. Returns an unauthorized Token."""
-        scope = self.get_scope() or ''
-        if scope:
-            scope = '?scope=' + self.SCOPE_SEPARATOR.join(scope)
-        return self.request(self.REQUEST_TOKEN_URL + scope,
-                            params=self.request_token_extra_arguments(),
-                            auth=self.oauth_auth()).text
+        if 'emailAddress' in set(self.setting('FIELD_SELECTORS', [])):
+            emails = self.email_data(access_token, *args, **kwargs)
+            if emails:
+                response['emailAddress'] = emails[0]
+
+        return response
+
+    def email_data(self, access_token, *args, **kwargs):
+        response = self.get_json(
+            self.user_emails_url(),
+            headers=self.user_data_headers(access_token)
+        )
+        email_addresses = []
+        for element in response.get('elements', []):
+            email_address = element.get('handle~', {}).get('emailAddress')
+            email_addresses.append(email_address)
+        return list(filter(None, email_addresses))
 
+    def get_user_details(self, response):
+        """Return user details from Linkedin account"""
 
-class LinkedinOAuth2(BaseLinkedinAuth, BaseOAuth2):
-    name = 'linkedin-oauth2'
-    SCOPE_SEPARATOR = ' '
-    AUTHORIZATION_URL = 'https://www.linkedin.com/uas/oauth2/authorization'
-    ACCESS_TOKEN_URL = 'https://www.linkedin.com/uas/oauth2/accessToken'
-    ACCESS_TOKEN_METHOD = 'POST'
-    REDIRECT_STATE = False
+        def get_localized_name(name):
+            """
+            FirstName & Last Name object
+            {
+                  "localized":{
+                     "en_US":"Smith"
+                  },
+                  "preferredLocale":{
+                     "country":"US",
+                     "language":"en"
+                  }
+            }
+            :return the localizedName from the lastName object
+            """
+            locale = "{}_{}".format(
+                name["preferredLocale"]["language"],
+                name["preferredLocale"]["country"]
+            )
+            return name['localized'].get(locale, '')
 
-    def user_data(self, access_token, *args, **kwargs):
-        headers = self.user_data_headers() or {}
-        headers['Authorization'] = 'Bearer {access_token}'.format(
-            access_token=access_token
-        )
-        return self.get_json(
-            self.user_details_url(),
-            params={'format': 'json'},
-            headers=headers
+        fullname, first_name, last_name = self.get_user_names(
+            first_name=get_localized_name(response['firstName']),
+            last_name=get_localized_name(response['lastName'])
         )
+        email = response.get('emailAddress', '')
+        return {'username': first_name + last_name,
+                'fullname': fullname,
+                'first_name': first_name,
+                'last_name': last_name,
+                'email': email}
+
+    def user_data_headers(self, access_token):
+        headers = {}
+        lang = self.setting('FORCE_PROFILE_LANGUAGE')
+        if lang:
+            headers['Accept-Language'] = lang if lang is not True \
+                else self.strategy.get_language()
+        headers['Authorization'] = 'Bearer {access_token}'.format(
+            access_token=access_token)
+        return headers
 
     def request_access_token(self, *args, **kwargs):
         # LinkedIn expects a POST request with querystring parameters, despite
@@ -99,18 +113,17 @@
             *args, **kwargs
         )
 
+    def process_error(self, data):
+        super(LinkedinOAuth2, self).process_error(data)
+        if data.get('serviceErrorCode'):
+            raise AuthCanceled(self, data.get('message') or data.get('status'))
+
 
 class LinkedinMobileOAuth2(LinkedinOAuth2):
     name = 'linkedin-mobile-oauth2'
 
-    def user_data(self, access_token, *args, **kwargs):
-        headers = self.user_data_headers()
-        if not headers:
-            headers = {}
-        headers['Authorization'] = 'Bearer ' + access_token
+    def user_data_headers(self, access_token):
+        headers = super(LinkedinMobileOAuth2, self).user_data_headers(
+            access_token)
         headers['x-li-src'] = 'msdk'
-        return self.get_json(
-            self.user_details_url(),
-            params={'format': 'json'},
-            headers=headers
-        )
+        return headers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-auth-core-3.1.0/social_core/backends/naver.py 
new/social-auth-core-3.2.0/social_core/backends/naver.py
--- old/social-auth-core-3.1.0/social_core/backends/naver.py    2018-08-20 
15:44:10.000000000 +0200
+++ new/social-auth-core-3.2.0/social_core/backends/naver.py    2019-05-30 
06:50:11.000000000 +0200
@@ -57,4 +57,8 @@
         }
 
     def _dom_value(self, dom, key):
-        return dom.getElementsByTagName(key)[0].childNodes[0].data
+        try:
+            # Fixed Missing Key Getting Error
+            return dom.getElementsByTagName(key)[0].childNodes[0].data
+        except IndexError:
+            return ''
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/backends/openstack.py 
new/social-auth-core-3.2.0/social_core/backends/openstack.py
--- old/social-auth-core-3.1.0/social_core/backends/openstack.py        
1970-01-01 01:00:00.000000000 +0100
+++ new/social-auth-core-3.2.0/social_core/backends/openstack.py        
2019-05-30 06:58:33.000000000 +0200
@@ -0,0 +1,47 @@
+"""
+OpenStack OpenId backend
+"""
+from six.moves.urllib_parse import urlsplit
+from openid.extensions import ax
+
+from .open_id import OpenIdAuth
+
+
+class OpenStackOpenId(OpenIdAuth):
+    name = 'openstack'
+    URL = 'openstackid.org'
+
+    def get_user_details(self, response):
+        """Generate username from identity url"""
+        values = super(OpenStackDevOpenId, self).get_user_details(response)
+        values['username'] = values.get('username') or \
+            urlsplit(response.identity_url).path.strip('/')
+        values['nickname'] = values.get('nickname', '')
+        return values
+
+    def setup_request(self, params=None):
+        """Fetch email, firstname, lastname from openid"""
+        request = self.openid_request(params)
+
+        # TODO: use sreg instead ax request to fetch nickname as username
+        fetch_request = ax.FetchRequest()
+        fetch_request.add(ax.AttrInfo(
+            'http://axschema.org/contact/email',
+            alias='email',
+            required=True
+        ))
+
+        fetch_request.add(ax.AttrInfo(
+            'http://axschema.org/namePerson/first',
+            alias='firstname',
+            required=True
+        ))
+
+        fetch_request.add(ax.AttrInfo(
+            'http://axschema.org/namePerson/last',
+            alias='lastname',
+            required=True
+        ))
+
+        request.addExtension(fetch_request)
+        return request
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/backends/openstackdev.py 
new/social-auth-core-3.2.0/social_core/backends/openstackdev.py
--- old/social-auth-core-3.1.0/social_core/backends/openstackdev.py     
1970-01-01 01:00:00.000000000 +0100
+++ new/social-auth-core-3.2.0/social_core/backends/openstackdev.py     
2019-05-30 06:58:33.000000000 +0200
@@ -0,0 +1,47 @@
+"""
+OpenStack OpenId backend
+"""
+from six.moves.urllib_parse import urlsplit
+from openid.extensions import ax
+
+from .open_id import OpenIdAuth
+
+
+class OpenStackDevOpenId(OpenIdAuth):
+    name = 'openstackdev'
+    URL = 'openstackid-dev.openstack.org'
+
+    def get_user_details(self, response):
+        """Generate username from identity url"""
+        values = super(OpenStackDevOpenId, self).get_user_details(response)
+        values['username'] = values.get('username') or \
+            urlsplit(response.identity_url).path.strip('/')
+        values['nickname'] = values.get('nickname', '')
+        return values
+
+    def setup_request(self, params=None):
+        """Fetch email, firstname, lastname from openid"""
+        request = self.openid_request(params)
+
+        # TODO: use sreg instead ax request to fetch nickname as username
+        fetch_request = ax.FetchRequest()
+        fetch_request.add(ax.AttrInfo(
+            'http://axschema.org/contact/email',
+            alias='email',
+            required=True
+        ))
+
+        fetch_request.add(ax.AttrInfo(
+            'http://axschema.org/namePerson/first',
+            alias='firstname',
+            required=True
+        ))
+
+        fetch_request.add(ax.AttrInfo(
+            'http://axschema.org/namePerson/last',
+            alias='lastname',
+            required=True
+        ))
+
+        request.addExtension(fetch_request)
+        return request
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/backends/shopify.py 
new/social-auth-core-3.2.0/social_core/backends/shopify.py
--- old/social-auth-core-3.1.0/social_core/backends/shopify.py  2018-08-20 
15:44:10.000000000 +0200
+++ new/social-auth-core-3.2.0/social_core/backends/shopify.py  2019-04-22 
17:26:10.000000000 +0200
@@ -22,7 +22,11 @@
     REDIRECT_STATE = False
 
     @property
-    def shopifyAPI(self):
+    def shopify_api_version(self):
+        return self.setting('API_VERSION', '2019-04')
+
+    @property
+    def shopify_api(self):
         if not hasattr(self, '_shopify_api'):
             fp, pathname, description = imp.find_module('shopify')
             self._shopify_api = imp.load_module('shopify', fp, pathname,
@@ -42,7 +46,8 @@
         extra_data field"""
         data = super(ShopifyOAuth2, self).extra_data(user, uid, response,
                                                      details, *args, **kwargs)
-        session = self.shopifyAPI.Session(self.data.get('shop').strip())
+        session = self.shopify_api.Session(self.data.get('shop').strip(),
+                                           version=self.shopify_api_version)
         # Get, and store the permanent token
         token = session.request_token(data['access_token'])
         data['access_token'] = token
@@ -50,12 +55,13 @@
 
     def auth_url(self):
         key, secret = self.get_key_and_secret()
-        self.shopifyAPI.Session.setup(api_key=key, secret=secret)
+        self.shopify_api.Session.setup(api_key=key, secret=secret)
         scope = self.get_scope()
         state = self.state_token()
         self.strategy.session_set(self.name + '_state', state)
         redirect_uri = self.get_redirect_uri(state)
-        session = self.shopifyAPI.Session(self.data.get('shop').strip())
+        session = self.shopify_api.Session(self.data.get('shop').strip(),
+                                           version=self.shopify_api_version)
         return session.create_permission_url(
             scope=scope,
             redirect_uri=redirect_uri
@@ -69,10 +75,12 @@
         key, secret = self.get_key_and_secret()
         try:
             shop_url = self.data.get('shop')
-            self.shopifyAPI.Session.setup(api_key=key, secret=secret)
-            shopify_session = self.shopifyAPI.Session(shop_url, self.data)
+            self.shopify_api.Session.setup(api_key=key, secret=secret)
+            shopify_session = self.shopify_api.Session(
+                shop_url, version=self.shopify_api_version, token=self.data
+            )
             access_token = shopify_session.token
-        except self.shopifyAPI.ValidationException:
+        except self.shopify_api.ValidationException:
             raise AuthCanceled(self)
         else:
             if not access_token:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/backends/strava.py 
new/social-auth-core-3.2.0/social_core/backends/strava.py
--- old/social-auth-core-3.1.0/social_core/backends/strava.py   2018-08-20 
15:44:10.000000000 +0200
+++ new/social-auth-core-3.2.0/social_core/backends/strava.py   2019-04-21 
15:17:43.000000000 +0200
@@ -16,6 +16,7 @@
     # Check issue #259 for details.
     REDIRECT_STATE = False
     REVOKE_TOKEN_URL = 'https://www.strava.com/oauth/deauthorize'
+    SCOPE_SEPARATOR = ','
 
     def get_user_id(self, details, response):
         return response['athlete']['id']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-auth-core-3.1.0/social_core/pipeline/utils.py 
new/social-auth-core-3.2.0/social_core/pipeline/utils.py
--- old/social-auth-core-3.1.0/social_core/pipeline/utils.py    2018-08-20 
15:44:10.000000000 +0200
+++ new/social-auth-core-3.2.0/social_core/pipeline/utils.py    2019-05-30 
06:41:39.000000000 +0200
@@ -23,7 +23,7 @@
         'uid': kwargs.get('uid'),
         'is_new': kwargs.get('is_new') or False,
         'new_association': kwargs.get('new_association') or False,
-        'user': user and user.id or None,
+        'user': hasattr(user, 'id') and user.id or None,
         'social': social and {
             'provider': social.provider,
             'uid': social.uid
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/tests/backends/data/saml_config.json 
new/social-auth-core-3.2.0/social_core/tests/backends/data/saml_config.json
--- old/social-auth-core-3.1.0/social_core/tests/backends/data/saml_config.json 
1970-01-01 01:00:00.000000000 +0100
+++ new/social-auth-core-3.2.0/social_core/tests/backends/data/saml_config.json 
2018-08-20 15:44:10.000000000 +0200
@@ -0,0 +1,23 @@
+{
+    "SOCIAL_AUTH_SAML_SP_ENTITY_ID": 
"https://github.com/omab/python-social-auth/saml-test";,
+    "SOCIAL_AUTH_SAML_SP_PUBLIC_CERT": 
"MIICsDCCAhmgAwIBAgIJAO7BwdjDZcUWMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNBMRkwFwYDVQQIExBCcml0aXNoIENvbHVtYmlhMRswGQYDVQQKExJweXRob24tc29jaWFsLWF1dGgwHhcNMTUwNTA4MDc1ODQ2WhcNMjUwNTA3MDc1ODQ2WjBFMQswCQYDVQQGEwJDQTEZMBcGA1UECBMQQnJpdGlzaCBDb2x1bWJpYTEbMBkGA1UEChMScHl0aG9uLXNvY2lhbC1hdXRoMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq3g1Cl+3uR5vCnN4HbgjTg+m3nHhteEMyb++ycZYre2bxUfsshER6x33l23tHckRYwm7MdBbrp3LrVoiOCdPblTml1IhEPTCwKMhBKvvWqTvgfcSSnRzAWkLlQYSusayyZK4n9qcYkV5MFni1rbjx+Mr5aOEmb5u33amMKLwSTwIDAQABo4GnMIGkMB0GA1UdDgQWBBRRiBR6zS66fKVokp0yJHbgv3RYmjB1BgNVHSMEbjBsgBRRiBR6zS66fKVokp0yJHbgv3RYmqFJpEcwRTELMAkGA1UEBhMCQ0ExGTAXBgNVBAgTEEJyaXRpc2ggQ29sdW1iaWExGzAZBgNVBAoTEnB5dGhvbi1zb2NpYWwtYXV0aIIJAO7BwdjDZcUWMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAJwsMU3YSaybVjuJ8US0fUhlPOlM40QFCGL4vB3TEbb24Mq8HrjUwrU0JFPGls9a2OYzN2B3e35NorMuxs+grGtr2yP6LvuX+nV6A93wb4ooGHoGfC7VLlyxSSns937SS5R1pzQ4gWzZma2KGWKICWph5zQ0ARVhL63967mGLmoI=",
+    "SOCIAL_AUTH_SAML_SP_PRIVATE_KEY": 
"MIICXgIBAAKBgQCq3g1Cl+3uR5vCnN4HbgjTg+m3nHhteEMyb++ycZYre2bxUfsshER6x33l23tHckRYwm7MdBbrp3LrVoiOCdPblTml1IhEPTCwKMhBKvvWqTvgfcSSnRzAWkLlQYSusayyZK4n9qcYkV5MFni1rbjx+Mr5aOEmb5u33amMKLwSTwIDAQABAoGBAIHAg6NJSiYC/NYpVzWfKlasuoNy78R5adXYSNZiCR5V5FNm5OzmODZgXUt6g0A7FomshIT/txQWoV7y5FmwPs8n13JY3Hdt4tJ6MHw2feLo710+OEp9VBQus3JsB2F8ONYrGvs00hPPL7h5av/rzTdE8F67YM1mSgeg7xEF6BghAkEA12OOqSzp2MLTNY7PqOaLDzy4aAMVNN3Ntv2jBN0jq7s1b5ilQ2PGkLwdtkicq/VZcRyUqVbZbMwz05II3nqx3wJBAMsVhRQ5sdFCRBzEbSAm2YEJaFh5u6QT3+zWHMFpPJRnaBAWz3RXKEnleJ+DS2Xz1Jm6ZrmLdZiwMx/8dK5rDZECQQC7GTdWi7ZC3dIcpwaKIGHRhZxmda8ZMkc9Wwwd8H7I8aFUZFPCu0xEc7SXoHHACit8zyfwBYpvMN8gPK3JnOkfAkEAsUSpk0wBMT38one7IZOHzCDgGkq4RbKrhdon45Pus0PIDDM9BrqFimtpbSN4DxhVfZK91DwtfAhhuAvv9cewYQJAPMhpAqv3PBGYmtRDUlWXJQv2JRJJkrvbbqgBed2OX5RRgj5V3SR6PBhLbcTZ+q+1tdPkMFzZo5U6MN5m/6oXvQ==",
+    "SOCIAL_AUTH_SAML_ORG_INFO": {
+        "en-US": {"name": "psa", "displayname": "PSA", "url": 
"https://github.com/omab/python-social-auth/"}
+    },
+    "SOCIAL_AUTH_SAML_TECHNICAL_CONTACT":
+        {"givenName": "Tech Gal", "emailAddress": "[email protected]"},
+    "SOCIAL_AUTH_SAML_SUPPORT_CONTACT":
+        {"givenName": "Support Guy", "emailAddress": "[email protected]"},
+    "SOCIAL_AUTH_SAML_ENABLED_IDPS": {
+        "testshib": {
+            "entity_id": "https://idp.testshib.org/idp/shibboleth";,
+            "url": "https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO";,
+            "x509cert": 
"MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEVMBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYDVQQKEwhUZXN0U2hpYjEZMBcGA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcxCzAJBgNVBAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gxETAPBgNVBAoTCFRlc3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7CyVTDClcpu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe3OQ01Ow3yT4I+Wdg1tsTpSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aTNPFmDixzUjoYzbGDrtAyCqA8f9CN2txIfJnpHE6q6CmKcoLADS4UrNPlhHSzd614kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB5/9nb0yh/ojRuJGmgMWHgWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HEMIHBMB0GA1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ869nh83KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTETMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNoaWIxGTAXBgNVBAMTEGlkcC50ZXN0c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5MFfSVk98t3CT9jHZoYxd8QMRLI4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpkOAvZZUosVkUo93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAjGeka8nz8JjwxpUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr8K/qhmFT2nIQi538n6rVYLeWj8Bbnl+ev0peYzxFyF5sQA=="
+        },
+        "other": {
+            "entity_id": "https://unused.saml.example.com";,
+            "url": "https://unused.saml.example.com/SAML2/Redirect/SSO";
+        }
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/tests/backends/test_cognito.py 
new/social-auth-core-3.2.0/social_core/tests/backends/test_cognito.py
--- old/social-auth-core-3.1.0/social_core/tests/backends/test_cognito.py       
1970-01-01 01:00:00.000000000 +0100
+++ new/social-auth-core-3.2.0/social_core/tests/backends/test_cognito.py       
2019-04-21 15:24:23.000000000 +0200
@@ -0,0 +1,36 @@
+import json
+
+from .oauth import OAuth2Test
+
+
+class CognitoAuth2Test(OAuth2Test):
+    backend_path = 'social_core.backends.cognito.CognitoOAuth2'
+    pool_domain = 'https://social_core.auth.eu-west-1.amazoncognito.com'
+    expected_username = 'cognito.account.ABCDE1234'
+    access_token_body = json.dumps({
+        'access_token': 'foobar',
+        'token_type': 'bearer'
+    })
+    user_data_body = json.dumps({
+        'given_name': 'John',
+        'family_name': 'Doe',
+        'username': 'cognito.account.ABCDE1234',
+        'email': '[email protected]',
+    })
+
+    @property
+    def user_data_url(self):
+        return self.backend.user_data_url()
+
+    def extra_settings(self):
+        settings = super(CognitoAuth2Test, self).extra_settings()
+        settings.update({
+            'SOCIAL_AUTH_' + self.name + '_POOL_DOMAIN': self.pool_domain,
+        })
+        return settings
+
+    def test_login(self):
+        self.do_login()
+
+    def test_partial_pipeline(self):
+        self.do_partial_pipeline()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/social-auth-core-3.1.0/social_core/tests/backends/test_linkedin.py 
new/social-auth-core-3.2.0/social_core/tests/backends/test_linkedin.py
--- old/social-auth-core-3.1.0/social_core/tests/backends/test_linkedin.py      
2018-08-20 15:44:10.000000000 +0200
+++ new/social-auth-core-3.2.0/social_core/tests/backends/test_linkedin.py      
2019-04-07 14:33:19.000000000 +0200
@@ -1,23 +1,40 @@
 import json
 
-from six.moves.urllib_parse import urlencode
-
-
-from .oauth import OAuth1Test, OAuth2Test
+from .oauth import OAuth2Test
 
 
 class BaseLinkedinTest(object):
-    user_data_url = 'https://api.linkedin.com/v1/people/~:' \
-                        '(first-name,id,last-name)'
+    user_data_url = 'https://api.linkedin.com/v2/me' \
+                    '?projection=(firstName,id,lastName)'
     expected_username = 'FooBar'
     access_token_body = json.dumps({
         'access_token': 'foobar',
         'token_type': 'bearer'
     })
+
+    # Reference:
+    # https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self
+    # 
-serve/sign-in-with-linkedin?context=linkedin/consumer/context#api-request
     user_data_body = json.dumps({
-        'lastName': 'Bar',
-        'id': '1010101010',
-        'firstName': 'Foo'
+        "id": '1010101010',
+        "firstName": {
+            "localized": {
+                "en_US": "Foo"
+            },
+            "preferredLocale": {
+                "country": "US",
+                "language": "en"
+            }
+        },
+        "lastName": {
+            "localized": {
+                "en_US": "Bar"
+            },
+            "preferredLocale": {
+                "country": "US",
+                "language": "en"
+            }
+        }
     })
 
     def test_login(self):
@@ -27,15 +44,6 @@
         self.do_partial_pipeline()
 
 
-class LinkedinOAuth1Test(BaseLinkedinTest, OAuth1Test):
-    backend_path = 'social_core.backends.linkedin.LinkedinOAuth'
-    request_token_body = urlencode({
-        'oauth_token_secret': 'foobar-secret',
-        'oauth_token': 'foobar',
-        'oauth_callback_confirmed': 'true'
-    })
-
-
 class LinkedinOAuth2Test(BaseLinkedinTest, OAuth2Test):
     backend_path = 'social_core.backends.linkedin.LinkedinOAuth2'
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/social-auth-core-3.1.0/social_core/utils.py 
new/social-auth-core-3.2.0/social_core/utils.py
--- old/social-auth-core-3.1.0/social_core/utils.py     2018-08-20 
15:44:10.000000000 +0200
+++ new/social-auth-core-3.2.0/social_core/utils.py     2019-04-07 
15:28:25.000000000 +0200
@@ -4,6 +4,7 @@
 import unicodedata
 import collections
 import functools
+import hmac
 import logging
 
 import six
@@ -218,21 +219,12 @@
 
 
 def constant_time_compare(val1, val2):
-    """
-    Returns True if the two strings are equal, False otherwise.
-    The time taken is independent of the number of characters that match.
-    This code was borrowed from Django 1.5.4-final
-    """
-    if len(val1) != len(val2):
-        return False
-    result = 0
-    if six.PY3 and isinstance(val1, bytes) and isinstance(val2, bytes):
-        for x, y in zip(val1, val2):
-            result |= x ^ y
-    else:
-        for x, y in zip(val1, val2):
-            result |= ord(x) ^ ord(y)
-    return result == 0
+    """Compare two values and prevent timing attacks for cryptographic use."""
+    if isinstance(val1, six.text_type):
+        val1 = val1.encode('utf-8')
+    if isinstance(val2, six.text_type):
+        val2 = val2.encode('utf-8')
+    return hmac.compare_digest(val1, val2)
 
 
 def is_url(value):


Reply via email to