We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Logging in has become more difficult
In #421 I optimized the sign-in template for new users, putting the sign-up form on top. This results in the sign-in page (<https://liberapay.com/sign-in>) impeding users that are simply trying to log in.

The solution is simple: use two separate templates.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `liberapay/utils/__init__.py`
Content:
```
1 # encoding: utf8
2 
3 from __future__ import absolute_import, division, print_function, unicode_literals
4 
5 from base64 import b64decode, b64encode
6 from binascii import hexlify, unhexlify
7 from datetime import date, datetime, timedelta
8 import errno
9 import fnmatch
10 import os
11 import pickle
12 import re
13 
14 from six import PY3
15 from six.moves.urllib.parse import quote as urlquote
16 
17 from pando import Response, json
18 from pando.utils import to_rfc822, utcnow
19 from markupsafe import Markup
20 from postgres.cursors import SimpleCursorBase
21 
22 from liberapay.exceptions import AccountSuspended, AuthRequired, LoginRequired
23 from liberapay.models.community import Community
24 from liberapay.utils.i18n import Money
25 from liberapay.website import website
26 
27 
28 BEGINNING_OF_EPOCH = to_rfc822(datetime(1970, 1, 1)).encode('ascii')
29 
30 
31 def get_participant(state, restrict=True, redirect_stub=True, allow_member=False,
32                     block_suspended_user=False, redirect_canon=True):
33     """Given a Request, raise Response or return Participant.
34 
35     If restrict is True then we'll restrict access to owners and admins.
36 
37     """
38     request = state['request']
39     response = state['response']
40     user = state['user']
41     slug = request.line.uri.path['username']
42     _ = state['_']
43 
44     if restrict and user.ANON:
45         raise LoginRequired
46 
47     if slug.startswith('~'):
48         thing = 'id'
49         value = slug[1:]
50         participant = user if user and str(user.id) == value else None
51     else:
52         thing = 'lower(username)'
53         value = slug.lower()
54         participant = user if user and user.username.lower() == value else None
55 
56     if participant is None:
57         from liberapay.models.participant import Participant  # avoid circular import
58         participant = Participant._from_thing(thing, value) if value else None
59         if participant is None or participant.kind == 'community':
60             raise response.error(404)
61 
62     if redirect_canon and request.method in ('GET', 'HEAD'):
63         if slug != participant.username:
64             canon = '/' + participant.username + request.line.uri[len(slug)+1:]
65             raise response.redirect(canon)
66 
67     status = participant.status
68     if status == 'closed':
69         if user.is_admin:
70             return participant
71         response.html_template = 'templates/account-closed.html'
72         raise response.error(410)
73     elif status == 'stub':
74         if redirect_stub:
75             to = participant.resolve_stub()
76             assert to
77             raise response.redirect(to)
78 
79     if restrict:
80         if participant != user:
81             if allow_member and participant.kind == 'group' and user.member_of(participant):
82                 pass
83             elif not user.is_admin:
84                 raise response.error(403, _("You are not authorized to access this page."))
85 
86     if block_suspended_user and participant.is_suspended and participant == user:
87         raise AccountSuspended()
88 
89     return participant
90 
91 
92 def get_community(state, restrict=False):
93     request, response = state['request'], state['response']
94     user = state['user']
95     name = request.path['name']
96 
97     c = Community.from_name(name)
98     if request.method in ('GET', 'HEAD'):
99         if not c:
100             response.redirect('/for/new?name=' + urlquote(name))
101         if c.name != name:
102             response.redirect('/for/' + c.name + request.line.uri[5+len(name):])
103     elif not c:
104         raise response.error(404)
105     elif user.ANON:
106         raise AuthRequired
107 
108     if restrict:
109         if user.ANON:
110             raise LoginRequired
111         if user.id != c.creator and not user.is_admin:
112             _ = state['_']
113             raise response.error(403, _("You are not authorized to access this page."))
114 
115     return c
116 
117 
118 def b64decode_s(s, **kw):
119     def error():
120         if 'default' in kw:
121             return kw['default']
122         raise Response(400, "invalid base64 input")
123 
124     try:
125         s = s.encode('ascii') if hasattr(s, 'encode') else s
126     except UnicodeError:
127         return error()
128 
129     udecode = lambda a: a.decode('utf8')
130     if s[:1] == b'.':
131         udecode = lambda a: a
132         s = s[1:]
133     s = s.replace(b'~', b'=')
134     try:
135         return udecode(b64decode(s, '-_'))
136     except Exception:
137         try:
138             # For retrocompatibility
139             return udecode(b64decode(s))
140         except Exception:
141             pass
142         return error()
143 
144 
145 def b64encode_s(s):
146     prefix = b''
147     if not isinstance(s, bytes):
148         s = s.encode('utf8')
149     else:
150         # Check whether the string is binary or already utf8
151         try:
152             s.decode('utf8')
153         except UnicodeError:
154             prefix = b'.'
155     r = prefix + b64encode(s, b'-_').replace(b'=', b'~')
156     return r.decode('ascii') if PY3 else r
157 
158 
159 def update_global_stats(website):
160     website.gnusers = website.db.one("""
161         SELECT count(*)
162           FROM participants
163          WHERE status = 'active'
164            AND kind <> 'community';
165     """)
166     transfer_volume = website.db.one("""
167         SELECT coalesce(sum(amount), 0)
168           FROM current_tips
169          WHERE is_funded
170     """)
171     website.gmonthly_volume = Money(transfer_volume * 52 / 12, 'EUR')
172 
173 
174 def _execute(this, sql, params=[]):
175     print(sql.strip(), params)
176     super(SimpleCursorBase, this).execute(sql, params)
177 
178 def log_cursor(f):
179     "Prints sql and params to stdout. Works globaly so watch for threaded use."
180     def wrapper(*a, **kw):
181         try:
182             SimpleCursorBase.execute = _execute
183             ret = f(*a, **kw)
184         finally:
185             del SimpleCursorBase.execute
186         return ret
187     return wrapper
188 
189 
190 def excerpt_intro(text, length=175, append='…'):
191     if not text:
192         return ''
193     if len(text) > length:
194         return text[:length] + append
195     return text
196 
197 
198 def is_card_expired(exp_year, exp_month):
199     today = date.today()
200     cur_year, cur_month = today.year, today.month
201     return exp_year < cur_year or exp_year == cur_year and exp_month < cur_month
202 
203 
204 def ensure_str(s):
205     if isinstance(s, str):
206         return s
207     return s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii')
208 
209 
210 def set_cookie(cookies, key, value, expires=None, httponly=True, path='/'):
211     key = ensure_str(key)
212     cookies[key] = ensure_str(value)
213     cookie = cookies[key]
214     if expires:
215         if isinstance(expires, timedelta):
216             expires += utcnow()
217         if isinstance(expires, datetime):
218             expires = to_rfc822(expires)
219         cookie[str('expires')] = ensure_str(expires)
220     if httponly:
221         cookie[str('httponly')] = True
222     if path:
223         cookie[str('path')] = ensure_str(path)
224     if website.canonical_domain:
225         cookie[str('domain')] = ensure_str(website.canonical_domain)
226     if website.canonical_scheme == 'https':
227         cookie[str('secure')] = True
228 
229 
230 def erase_cookie(cookies, key, **kw):
231     set_cookie(cookies, key, '', BEGINNING_OF_EPOCH, **kw)
232 
233 
234 def to_javascript(obj):
235     """For when you want to inject an object into a <script> tag.
236     """
237     return json.dumps(obj).replace('</', '<\\/')
238 
239 
240 svg_attrs_re = re.compile(r'\s+(?:height|width|x|y|xmlns)=(["\']).*?\1')
241 
242 def include_svg(svg, height, width, x=None, y=None):
243     """For when you want to include an SVG in an HTML page or in another SVG.
244     """
245     assert svg.startswith('<svg')
246     i = svg.find('>')
247     assert i != -1
248     d = locals()
249     attrs = svg_attrs_re.sub('', svg[4:i])
250     for a in ('height', 'width', 'x', 'y'):
251         v = d[a]
252         if v is None:
253             continue
254         attrs += ' %s="%s"' % (a, v)
255     return Markup(svg[:4] + attrs + svg[i:])
256 
257 
258 def group_by(iterable, key):
259     r = {}
260     for obj in iterable:
261         try:
262             k = obj[key]
263         except KeyError:
264             continue
265         r.setdefault(k, []).append(obj)
266     return r
267 
268 
269 def find_files(directory, pattern):
270     for root, dirs, files in os.walk(directory):
271         for filename in fnmatch.filter(files, pattern):
272             yield os.path.join(root, filename)
273 
274 
275 def serialize(context):
276     for k, v in context.items():
277         if str(type(v)) == "<class 'psycopg2.extras.Record'>":
278             context[k] = v._asdict()
279     return b'\\x' + hexlify(pickle.dumps(context, 2))
280 
281 
282 def deserialize(context):
283     if isinstance(context, memoryview) and context[:2].tobytes() == b'\\x':
284         context = unhexlify(context[2:])
285     return pickle.loads(context)
286 
287 
288 def pid_exists(pid):
289     """Check whether pid exists in the current process table. UNIX only.
290 
291     Source: http://stackoverflow.com/a/6940314/2729778
292     """
293     if not pid > 0:
294         raise ValueError("bad PID %s" % pid)
295     try:
296         os.kill(pid, 0)
297     except OSError as err:
298         if err.errno == errno.ESRCH:
299             # ESRCH == No such process
300             return False
301         elif err.errno == errno.EPERM:
302             # EPERM clearly means there's a process to deny access to
303             return True
304         else:
305             # According to "man 2 kill" possible error values are
306             # (EINVAL, EPERM, ESRCH)
307             raise
308     else:
309         return True
310
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/liberapay/utils/__init__.py b/liberapay/utils/__init__.py
--- a/liberapay/utils/__init__.py
+++ b/liberapay/utils/__init__.py
@@ -68,6 +68,7 @@
     if status == 'closed':
         if user.is_admin:
             return participant
+        state['closed_account'] = participant
         response.html_template = 'templates/account-closed.html'
         raise response.error(410)
     elif status == 'stub':

{"golden_diff": "diff --git a/liberapay/utils/__init__.py b/liberapay/utils/__init__.py\n--- a/liberapay/utils/__init__.py\n+++ b/liberapay/utils/__init__.py\n@@ -68,6 +68,7 @@\n     if status == 'closed':\n         if user.is_admin:\n             return participant\n+        state['closed_account'] = participant\n         response.html_template = 'templates/account-closed.html'\n         raise response.error(410)\n     elif status == 'stub':\n", "issue": "Logging in has become more difficult\nIn #421 I optimized the sign-in template for new users, putting the sign-up form on top. This results in the sign-in page (<https://liberapay.com/sign-in>) impeding users that are simply trying to log in.\r\n\r\nThe solution is simple: use two separate templates.\n", "before_files": [{"content": "# encoding: utf8\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nfrom base64 import b64decode, b64encode\nfrom binascii import hexlify, unhexlify\nfrom datetime import date, datetime, timedelta\nimport errno\nimport fnmatch\nimport os\nimport pickle\nimport re\n\nfrom six import PY3\nfrom six.moves.urllib.parse import quote as urlquote\n\nfrom pando import Response, json\nfrom pando.utils import to_rfc822, utcnow\nfrom markupsafe import Markup\nfrom postgres.cursors import SimpleCursorBase\n\nfrom liberapay.exceptions import AccountSuspended, AuthRequired, LoginRequired\nfrom liberapay.models.community import Community\nfrom liberapay.utils.i18n import Money\nfrom liberapay.website import website\n\n\nBEGINNING_OF_EPOCH = to_rfc822(datetime(1970, 1, 1)).encode('ascii')\n\n\ndef get_participant(state, restrict=True, redirect_stub=True, allow_member=False,\n                    block_suspended_user=False, redirect_canon=True):\n    \"\"\"Given a Request, raise Response or return Participant.\n\n    If restrict is True then we'll restrict access to owners and admins.\n\n    \"\"\"\n    request = state['request']\n    response = state['response']\n    user = state['user']\n    slug = request.line.uri.path['username']\n    _ = state['_']\n\n    if restrict and user.ANON:\n        raise LoginRequired\n\n    if slug.startswith('~'):\n        thing = 'id'\n        value = slug[1:]\n        participant = user if user and str(user.id) == value else None\n    else:\n        thing = 'lower(username)'\n        value = slug.lower()\n        participant = user if user and user.username.lower() == value else None\n\n    if participant is None:\n        from liberapay.models.participant import Participant  # avoid circular import\n        participant = Participant._from_thing(thing, value) if value else None\n        if participant is None or participant.kind == 'community':\n            raise response.error(404)\n\n    if redirect_canon and request.method in ('GET', 'HEAD'):\n        if slug != participant.username:\n            canon = '/' + participant.username + request.line.uri[len(slug)+1:]\n            raise response.redirect(canon)\n\n    status = participant.status\n    if status == 'closed':\n        if user.is_admin:\n            return participant\n        response.html_template = 'templates/account-closed.html'\n        raise response.error(410)\n    elif status == 'stub':\n        if redirect_stub:\n            to = participant.resolve_stub()\n            assert to\n            raise response.redirect(to)\n\n    if restrict:\n        if participant != user:\n            if allow_member and participant.kind == 'group' and user.member_of(participant):\n                pass\n            elif not user.is_admin:\n                raise response.error(403, _(\"You are not authorized to access this page.\"))\n\n    if block_suspended_user and participant.is_suspended and participant == user:\n        raise AccountSuspended()\n\n    return participant\n\n\ndef get_community(state, restrict=False):\n    request, response = state['request'], state['response']\n    user = state['user']\n    name = request.path['name']\n\n    c = Community.from_name(name)\n    if request.method in ('GET', 'HEAD'):\n        if not c:\n            response.redirect('/for/new?name=' + urlquote(name))\n        if c.name != name:\n            response.redirect('/for/' + c.name + request.line.uri[5+len(name):])\n    elif not c:\n        raise response.error(404)\n    elif user.ANON:\n        raise AuthRequired\n\n    if restrict:\n        if user.ANON:\n            raise LoginRequired\n        if user.id != c.creator and not user.is_admin:\n            _ = state['_']\n            raise response.error(403, _(\"You are not authorized to access this page.\"))\n\n    return c\n\n\ndef b64decode_s(s, **kw):\n    def error():\n        if 'default' in kw:\n            return kw['default']\n        raise Response(400, \"invalid base64 input\")\n\n    try:\n        s = s.encode('ascii') if hasattr(s, 'encode') else s\n    except UnicodeError:\n        return error()\n\n    udecode = lambda a: a.decode('utf8')\n    if s[:1] == b'.':\n        udecode = lambda a: a\n        s = s[1:]\n    s = s.replace(b'~', b'=')\n    try:\n        return udecode(b64decode(s, '-_'))\n    except Exception:\n        try:\n            # For retrocompatibility\n            return udecode(b64decode(s))\n        except Exception:\n            pass\n        return error()\n\n\ndef b64encode_s(s):\n    prefix = b''\n    if not isinstance(s, bytes):\n        s = s.encode('utf8')\n    else:\n        # Check whether the string is binary or already utf8\n        try:\n            s.decode('utf8')\n        except UnicodeError:\n            prefix = b'.'\n    r = prefix + b64encode(s, b'-_').replace(b'=', b'~')\n    return r.decode('ascii') if PY3 else r\n\n\ndef update_global_stats(website):\n    website.gnusers = website.db.one(\"\"\"\n        SELECT count(*)\n          FROM participants\n         WHERE status = 'active'\n           AND kind <> 'community';\n    \"\"\")\n    transfer_volume = website.db.one(\"\"\"\n        SELECT coalesce(sum(amount), 0)\n          FROM current_tips\n         WHERE is_funded\n    \"\"\")\n    website.gmonthly_volume = Money(transfer_volume * 52 / 12, 'EUR')\n\n\ndef _execute(this, sql, params=[]):\n    print(sql.strip(), params)\n    super(SimpleCursorBase, this).execute(sql, params)\n\ndef log_cursor(f):\n    \"Prints sql and params to stdout. Works globaly so watch for threaded use.\"\n    def wrapper(*a, **kw):\n        try:\n            SimpleCursorBase.execute = _execute\n            ret = f(*a, **kw)\n        finally:\n            del SimpleCursorBase.execute\n        return ret\n    return wrapper\n\n\ndef excerpt_intro(text, length=175, append='\u2026'):\n    if not text:\n        return ''\n    if len(text) > length:\n        return text[:length] + append\n    return text\n\n\ndef is_card_expired(exp_year, exp_month):\n    today = date.today()\n    cur_year, cur_month = today.year, today.month\n    return exp_year < cur_year or exp_year == cur_year and exp_month < cur_month\n\n\ndef ensure_str(s):\n    if isinstance(s, str):\n        return s\n    return s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii')\n\n\ndef set_cookie(cookies, key, value, expires=None, httponly=True, path='/'):\n    key = ensure_str(key)\n    cookies[key] = ensure_str(value)\n    cookie = cookies[key]\n    if expires:\n        if isinstance(expires, timedelta):\n            expires += utcnow()\n        if isinstance(expires, datetime):\n            expires = to_rfc822(expires)\n        cookie[str('expires')] = ensure_str(expires)\n    if httponly:\n        cookie[str('httponly')] = True\n    if path:\n        cookie[str('path')] = ensure_str(path)\n    if website.canonical_domain:\n        cookie[str('domain')] = ensure_str(website.canonical_domain)\n    if website.canonical_scheme == 'https':\n        cookie[str('secure')] = True\n\n\ndef erase_cookie(cookies, key, **kw):\n    set_cookie(cookies, key, '', BEGINNING_OF_EPOCH, **kw)\n\n\ndef to_javascript(obj):\n    \"\"\"For when you want to inject an object into a <script> tag.\n    \"\"\"\n    return json.dumps(obj).replace('</', '<\\\\/')\n\n\nsvg_attrs_re = re.compile(r'\\s+(?:height|width|x|y|xmlns)=([\"\\']).*?\\1')\n\ndef include_svg(svg, height, width, x=None, y=None):\n    \"\"\"For when you want to include an SVG in an HTML page or in another SVG.\n    \"\"\"\n    assert svg.startswith('<svg')\n    i = svg.find('>')\n    assert i != -1\n    d = locals()\n    attrs = svg_attrs_re.sub('', svg[4:i])\n    for a in ('height', 'width', 'x', 'y'):\n        v = d[a]\n        if v is None:\n            continue\n        attrs += ' %s=\"%s\"' % (a, v)\n    return Markup(svg[:4] + attrs + svg[i:])\n\n\ndef group_by(iterable, key):\n    r = {}\n    for obj in iterable:\n        try:\n            k = obj[key]\n        except KeyError:\n            continue\n        r.setdefault(k, []).append(obj)\n    return r\n\n\ndef find_files(directory, pattern):\n    for root, dirs, files in os.walk(directory):\n        for filename in fnmatch.filter(files, pattern):\n            yield os.path.join(root, filename)\n\n\ndef serialize(context):\n    for k, v in context.items():\n        if str(type(v)) == \"<class 'psycopg2.extras.Record'>\":\n            context[k] = v._asdict()\n    return b'\\\\x' + hexlify(pickle.dumps(context, 2))\n\n\ndef deserialize(context):\n    if isinstance(context, memoryview) and context[:2].tobytes() == b'\\\\x':\n        context = unhexlify(context[2:])\n    return pickle.loads(context)\n\n\ndef pid_exists(pid):\n    \"\"\"Check whether pid exists in the current process table. UNIX only.\n\n    Source: http://stackoverflow.com/a/6940314/2729778\n    \"\"\"\n    if not pid > 0:\n        raise ValueError(\"bad PID %s\" % pid)\n    try:\n        os.kill(pid, 0)\n    except OSError as err:\n        if err.errno == errno.ESRCH:\n            # ESRCH == No such process\n            return False\n        elif err.errno == errno.EPERM:\n            # EPERM clearly means there's a process to deny access to\n            return True\n        else:\n            # According to \"man 2 kill\" possible error values are\n            # (EINVAL, EPERM, ESRCH)\n            raise\n    else:\n        return True\n", "path": "liberapay/utils/__init__.py"}], "after_files": [{"content": "# encoding: utf8\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nfrom base64 import b64decode, b64encode\nfrom binascii import hexlify, unhexlify\nfrom datetime import date, datetime, timedelta\nimport errno\nimport fnmatch\nimport os\nimport pickle\nimport re\n\nfrom six import PY3\nfrom six.moves.urllib.parse import quote as urlquote\n\nfrom pando import Response, json\nfrom pando.utils import to_rfc822, utcnow\nfrom markupsafe import Markup\nfrom postgres.cursors import SimpleCursorBase\n\nfrom liberapay.exceptions import AccountSuspended, AuthRequired, LoginRequired\nfrom liberapay.models.community import Community\nfrom liberapay.utils.i18n import Money\nfrom liberapay.website import website\n\n\nBEGINNING_OF_EPOCH = to_rfc822(datetime(1970, 1, 1)).encode('ascii')\n\n\ndef get_participant(state, restrict=True, redirect_stub=True, allow_member=False,\n                    block_suspended_user=False, redirect_canon=True):\n    \"\"\"Given a Request, raise Response or return Participant.\n\n    If restrict is True then we'll restrict access to owners and admins.\n\n    \"\"\"\n    request = state['request']\n    response = state['response']\n    user = state['user']\n    slug = request.line.uri.path['username']\n    _ = state['_']\n\n    if restrict and user.ANON:\n        raise LoginRequired\n\n    if slug.startswith('~'):\n        thing = 'id'\n        value = slug[1:]\n        participant = user if user and str(user.id) == value else None\n    else:\n        thing = 'lower(username)'\n        value = slug.lower()\n        participant = user if user and user.username.lower() == value else None\n\n    if participant is None:\n        from liberapay.models.participant import Participant  # avoid circular import\n        participant = Participant._from_thing(thing, value) if value else None\n        if participant is None or participant.kind == 'community':\n            raise response.error(404)\n\n    if redirect_canon and request.method in ('GET', 'HEAD'):\n        if slug != participant.username:\n            canon = '/' + participant.username + request.line.uri[len(slug)+1:]\n            raise response.redirect(canon)\n\n    status = participant.status\n    if status == 'closed':\n        if user.is_admin:\n            return participant\n        state['closed_account'] = participant\n        response.html_template = 'templates/account-closed.html'\n        raise response.error(410)\n    elif status == 'stub':\n        if redirect_stub:\n            to = participant.resolve_stub()\n            assert to\n            raise response.redirect(to)\n\n    if restrict:\n        if participant != user:\n            if allow_member and participant.kind == 'group' and user.member_of(participant):\n                pass\n            elif not user.is_admin:\n                raise response.error(403, _(\"You are not authorized to access this page.\"))\n\n    if block_suspended_user and participant.is_suspended and participant == user:\n        raise AccountSuspended()\n\n    return participant\n\n\ndef get_community(state, restrict=False):\n    request, response = state['request'], state['response']\n    user = state['user']\n    name = request.path['name']\n\n    c = Community.from_name(name)\n    if request.method in ('GET', 'HEAD'):\n        if not c:\n            response.redirect('/for/new?name=' + urlquote(name))\n        if c.name != name:\n            response.redirect('/for/' + c.name + request.line.uri[5+len(name):])\n    elif not c:\n        raise response.error(404)\n    elif user.ANON:\n        raise AuthRequired\n\n    if restrict:\n        if user.ANON:\n            raise LoginRequired\n        if user.id != c.creator and not user.is_admin:\n            _ = state['_']\n            raise response.error(403, _(\"You are not authorized to access this page.\"))\n\n    return c\n\n\ndef b64decode_s(s, **kw):\n    def error():\n        if 'default' in kw:\n            return kw['default']\n        raise Response(400, \"invalid base64 input\")\n\n    try:\n        s = s.encode('ascii') if hasattr(s, 'encode') else s\n    except UnicodeError:\n        return error()\n\n    udecode = lambda a: a.decode('utf8')\n    if s[:1] == b'.':\n        udecode = lambda a: a\n        s = s[1:]\n    s = s.replace(b'~', b'=')\n    try:\n        return udecode(b64decode(s, '-_'))\n    except Exception:\n        try:\n            # For retrocompatibility\n            return udecode(b64decode(s))\n        except Exception:\n            pass\n        return error()\n\n\ndef b64encode_s(s):\n    prefix = b''\n    if not isinstance(s, bytes):\n        s = s.encode('utf8')\n    else:\n        # Check whether the string is binary or already utf8\n        try:\n            s.decode('utf8')\n        except UnicodeError:\n            prefix = b'.'\n    r = prefix + b64encode(s, b'-_').replace(b'=', b'~')\n    return r.decode('ascii') if PY3 else r\n\n\ndef update_global_stats(website):\n    website.gnusers = website.db.one(\"\"\"\n        SELECT count(*)\n          FROM participants\n         WHERE status = 'active'\n           AND kind <> 'community';\n    \"\"\")\n    transfer_volume = website.db.one(\"\"\"\n        SELECT coalesce(sum(amount), 0)\n          FROM current_tips\n         WHERE is_funded\n    \"\"\")\n    website.gmonthly_volume = Money(transfer_volume * 52 / 12, 'EUR')\n\n\ndef _execute(this, sql, params=[]):\n    print(sql.strip(), params)\n    super(SimpleCursorBase, this).execute(sql, params)\n\ndef log_cursor(f):\n    \"Prints sql and params to stdout. Works globaly so watch for threaded use.\"\n    def wrapper(*a, **kw):\n        try:\n            SimpleCursorBase.execute = _execute\n            ret = f(*a, **kw)\n        finally:\n            del SimpleCursorBase.execute\n        return ret\n    return wrapper\n\n\ndef excerpt_intro(text, length=175, append='\u2026'):\n    if not text:\n        return ''\n    if len(text) > length:\n        return text[:length] + append\n    return text\n\n\ndef is_card_expired(exp_year, exp_month):\n    today = date.today()\n    cur_year, cur_month = today.year, today.month\n    return exp_year < cur_year or exp_year == cur_year and exp_month < cur_month\n\n\ndef ensure_str(s):\n    if isinstance(s, str):\n        return s\n    return s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii')\n\n\ndef set_cookie(cookies, key, value, expires=None, httponly=True, path='/'):\n    key = ensure_str(key)\n    cookies[key] = ensure_str(value)\n    cookie = cookies[key]\n    if expires:\n        if isinstance(expires, timedelta):\n            expires += utcnow()\n        if isinstance(expires, datetime):\n            expires = to_rfc822(expires)\n        cookie[str('expires')] = ensure_str(expires)\n    if httponly:\n        cookie[str('httponly')] = True\n    if path:\n        cookie[str('path')] = ensure_str(path)\n    if website.canonical_domain:\n        cookie[str('domain')] = ensure_str(website.canonical_domain)\n    if website.canonical_scheme == 'https':\n        cookie[str('secure')] = True\n\n\ndef erase_cookie(cookies, key, **kw):\n    set_cookie(cookies, key, '', BEGINNING_OF_EPOCH, **kw)\n\n\ndef to_javascript(obj):\n    \"\"\"For when you want to inject an object into a <script> tag.\n    \"\"\"\n    return json.dumps(obj).replace('</', '<\\\\/')\n\n\nsvg_attrs_re = re.compile(r'\\s+(?:height|width|x|y|xmlns)=([\"\\']).*?\\1')\n\ndef include_svg(svg, height, width, x=None, y=None):\n    \"\"\"For when you want to include an SVG in an HTML page or in another SVG.\n    \"\"\"\n    assert svg.startswith('<svg')\n    i = svg.find('>')\n    assert i != -1\n    d = locals()\n    attrs = svg_attrs_re.sub('', svg[4:i])\n    for a in ('height', 'width', 'x', 'y'):\n        v = d[a]\n        if v is None:\n            continue\n        attrs += ' %s=\"%s\"' % (a, v)\n    return Markup(svg[:4] + attrs + svg[i:])\n\n\ndef group_by(iterable, key):\n    r = {}\n    for obj in iterable:\n        try:\n            k = obj[key]\n        except KeyError:\n            continue\n        r.setdefault(k, []).append(obj)\n    return r\n\n\ndef find_files(directory, pattern):\n    for root, dirs, files in os.walk(directory):\n        for filename in fnmatch.filter(files, pattern):\n            yield os.path.join(root, filename)\n\n\ndef serialize(context):\n    for k, v in context.items():\n        if str(type(v)) == \"<class 'psycopg2.extras.Record'>\":\n            context[k] = v._asdict()\n    return b'\\\\x' + hexlify(pickle.dumps(context, 2))\n\n\ndef deserialize(context):\n    if isinstance(context, memoryview) and context[:2].tobytes() == b'\\\\x':\n        context = unhexlify(context[2:])\n    return pickle.loads(context)\n\n\ndef pid_exists(pid):\n    \"\"\"Check whether pid exists in the current process table. UNIX only.\n\n    Source: http://stackoverflow.com/a/6940314/2729778\n    \"\"\"\n    if not pid > 0:\n        raise ValueError(\"bad PID %s\" % pid)\n    try:\n        os.kill(pid, 0)\n    except OSError as err:\n        if err.errno == errno.ESRCH:\n            # ESRCH == No such process\n            return False\n        elif err.errno == errno.EPERM:\n            # EPERM clearly means there's a process to deny access to\n            return True\n        else:\n            # According to \"man 2 kill\" possible error values are\n            # (EINVAL, EPERM, ESRCH)\n            raise\n    else:\n        return True\n", "path": "liberapay/utils/__init__.py"}]}