We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
403 clicking "fix credit card" in email when not logged in
My credit card expired and I got the email reminding me to fix payment info. I clicked the "fix credit card" button in the email and was taken to a 403 Forbidden page. Would expect to be taken to login form when I'm not already logged in. Thanks!


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gratipay/utils/__init__.py`
Content:
```
1 # encoding: utf8
2 
3 from __future__ import absolute_import, division, print_function, unicode_literals
4 
5 from base64 import urlsafe_b64encode, urlsafe_b64decode
6 from datetime import datetime, timedelta
7 
8 from aspen import Response, json
9 from aspen.utils import to_rfc822, utcnow
10 from dependency_injection import resolve_dependencies
11 from postgres.cursors import SimpleCursorBase
12 
13 import gratipay
14 
15 
16 BEGINNING_OF_EPOCH = to_rfc822(datetime(1970, 1, 1)).encode('ascii')
17 
18 # Difference between current time and credit card expiring date when
19 # card is considered as expiring
20 EXPIRING_DELTA = timedelta(days = 30)
21 
22 
23 def dict_to_querystring(mapping):
24     if not mapping:
25         return u''
26 
27     arguments = []
28     for key, values in mapping.iteritems():
29         for val in values:
30             arguments.append(u'='.join([key, val]))
31 
32     return u'?' + u'&'.join(arguments)
33 
34 
35 def use_tildes_for_participants(website, request):
36     if request.path.raw.startswith('/~/'):
37         to = '/~' + request.path.raw[3:]
38         if request.qs.raw:
39             to += '?' + request.qs.raw
40         website.redirect(to)
41     elif request.path.raw.startswith('/~'):
42         request.path.__init__('/~/' + request.path.raw[2:])
43 
44 
45 def canonicalize(redirect, path, base, canonical, given, arguments=None):
46     if given != canonical:
47         assert canonical.lower() == given.lower()  # sanity check
48         remainder = path[len(base + given):]
49 
50         if arguments is not None:
51             arguments = dict_to_querystring(arguments)
52 
53         newpath = base + canonical + remainder + arguments or ''
54         redirect(newpath)
55 
56 
57 def get_participant(state, restrict=True, resolve_unclaimed=True):
58     """Given a Request, raise Response or return Participant.
59 
60     If restrict is True then we'll restrict access to owners and admins.
61 
62     """
63     redirect = state['website'].redirect
64     request = state['request']
65     user = state['user']
66     slug = request.line.uri.path['username']
67     qs = request.line.uri.querystring
68     _ = state['_']
69 
70     if restrict:
71         if user.ANON:
72             raise Response(403, _("You need to log in to access this page."))
73 
74     from gratipay.models.participant import Participant  # avoid circular import
75     participant = Participant.from_username(slug)
76 
77     if participant is None:
78         raise Response(404)
79 
80     canonicalize(redirect, request.line.uri.path.raw, '/~/', participant.username, slug, qs)
81 
82     if participant.is_closed:
83         if user.ADMIN:
84             return participant
85         raise Response(410)
86 
87     if participant.claimed_time is None and resolve_unclaimed:
88         to = participant.resolve_unclaimed()
89         if to:
90             # This is a stub account (someone on another platform who hasn't
91             # actually registered with Gratipay yet)
92             redirect(to)
93         else:
94             # This is an archived account (result of take_over)
95             if user.ADMIN:
96                 return participant
97             raise Response(404)
98 
99     if restrict:
100         if participant != user.participant:
101             if not user.ADMIN:
102                 raise Response(403, _("You are not authorized to access this page."))
103 
104     return participant
105 
106 
107 def get_team(state):
108     """Given a Request, raise Response or return Team.
109     """
110     redirect = state['website'].redirect
111     request = state['request']
112     user = state['user']
113     slug = request.line.uri.path['team']
114     qs = request.line.uri.querystring
115 
116     from gratipay.models.team import Team  # avoid circular import
117     team = Team.from_slug(slug)
118 
119     if team is None:
120         # Try to redirect to a Participant.
121         from gratipay.models.participant import Participant # avoid circular import
122         participant = Participant.from_username(slug)
123         if participant is not None:
124             qs = '?' + request.qs.raw if request.qs.raw else ''
125             redirect('/~' + request.path.raw[1:] + qs)
126         raise Response(404)
127 
128     canonicalize(redirect, request.line.uri.path.raw, '/', team.slug, slug, qs)
129 
130     if team.is_closed and not user.ADMIN:
131         raise Response(410)
132 
133     return team
134 
135 
136 def encode_for_querystring(s):
137     """Given a unicode, return a unicode that's safe for transport across a querystring.
138     """
139     if not isinstance(s, unicode):
140         raise TypeError('unicode required')
141     return urlsafe_b64encode(s.encode('utf8')).replace(b'=', b'~').decode('ascii')
142 
143 
144 def decode_from_querystring(s, **kw):
145     """Given a unicode computed by encode_for_querystring, return the inverse.
146 
147     We raise Response(400) if the input value can't be decoded (i.e., it's not
148     ASCII, not padded properly, or not decodable as UTF-8 once Base64-decoded).
149 
150     """
151     if not isinstance(s, unicode):
152         raise TypeError('unicode required')
153     try:
154         return urlsafe_b64decode(s.encode('ascii').replace(b'~', b'=')).decode('utf8')
155     except:
156         if 'default' in kw:
157             # Enable callers to handle errors without using try/except.
158             return kw['default']
159         raise Response(400, "invalid input")
160 
161 
162 def update_cta(website):
163     nusers = website.db.one("""
164         SELECT nusers FROM paydays
165         ORDER BY ts_end DESC LIMIT 1
166     """, default=0)
167     nreceiving_from = website.db.one("""
168         SELECT nreceiving_from
169           FROM teams
170          WHERE slug = 'Gratipay'
171     """, default=0)
172     website.support_current = cur = int(round(nreceiving_from / nusers * 100)) if nusers else 0
173     if cur < 10:    goal = 20
174     elif cur < 15:  goal = 30
175     elif cur < 25:  goal = 40
176     elif cur < 35:  goal = 50
177     elif cur < 45:  goal = 60
178     elif cur < 55:  goal = 70
179     elif cur < 65:  goal = 80
180     elif cur > 70:  goal = None
181     website.support_goal = goal
182 
183 
184 def _execute(this, sql, params=[]):
185     print(sql.strip(), params)
186     super(SimpleCursorBase, this).execute(sql, params)
187 
188 def log_cursor(f):
189     "Prints sql and params to stdout. Works globaly so watch for threaded use."
190     def wrapper(*a, **kw):
191         try:
192             SimpleCursorBase.execute = _execute
193             ret = f(*a, **kw)
194         finally:
195             del SimpleCursorBase.execute
196         return ret
197     return wrapper
198 
199 
200 def format_money(money):
201     format = '%.2f' if money < 1000 else '%.0f'
202     return format % money
203 
204 
205 def excerpt_intro(text, length=175, append=u'…'):
206     if not text:
207         return ''
208     if len(text) > length:
209         return text[:length] + append
210     return text
211 
212 
213 def is_card_expiring(expiration_year, expiration_month):
214     now = datetime.utcnow()
215     expiring_date = datetime(expiration_year, expiration_month, 1)
216     delta = expiring_date - now
217     return delta < EXPIRING_DELTA
218 
219 
220 def set_cookie(cookies, key, value, expires=None, httponly=True, path=b'/'):
221     cookies[key] = value
222     cookie = cookies[key]
223     if expires:
224         if isinstance(expires, timedelta):
225             expires += utcnow()
226         if isinstance(expires, datetime):
227             expires = to_rfc822(expires).encode('ascii')
228         cookie[b'expires'] = expires
229     if httponly:
230         cookie[b'httponly'] = True
231     if path:
232         cookie[b'path'] = path
233     if gratipay.use_secure_cookies:
234         cookie[b'secure'] = True
235 
236 
237 def erase_cookie(cookies, key, **kw):
238     set_cookie(cookies, key, '', BEGINNING_OF_EPOCH, **kw)
239 
240 
241 def filter_profile_nav(user, participant, pages):
242     out = []
243     for foo, bar, show_them, show_others in pages:
244         if (user.participant == participant and show_them) \
245         or (user.participant != participant and show_others) \
246         or user.ADMIN:
247             out.append((foo, bar, show_them, show_others))
248     return out
249 
250 
251 def to_javascript(obj):
252     """For when you want to inject an object into a <script> tag.
253     """
254     return json.dumps(obj).replace('</', '<\\/')
255 
256 
257 class LazyResponse(Response):
258 
259     def __init__(self, code, lazy_body, **kw):
260         Response.__init__(self, code, '', **kw)
261         self.lazy_body = lazy_body
262 
263     def render_body(self, state):
264         f = self.lazy_body
265         self.body = f(*resolve_dependencies(f, state).as_args)
266
```
--- 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/gratipay/utils/__init__.py b/gratipay/utils/__init__.py
--- a/gratipay/utils/__init__.py
+++ b/gratipay/utils/__init__.py
@@ -69,7 +69,7 @@
 
     if restrict:
         if user.ANON:
-            raise Response(403, _("You need to log in to access this page."))
+            raise Response(401, _("You need to log in to access this page."))
 
     from gratipay.models.participant import Participant  # avoid circular import
     participant = Participant.from_username(slug)

{"golden_diff": "diff --git a/gratipay/utils/__init__.py b/gratipay/utils/__init__.py\n--- a/gratipay/utils/__init__.py\n+++ b/gratipay/utils/__init__.py\n@@ -69,7 +69,7 @@\n \n     if restrict:\n         if user.ANON:\n-            raise Response(403, _(\"You need to log in to access this page.\"))\n+            raise Response(401, _(\"You need to log in to access this page.\"))\n \n     from gratipay.models.participant import Participant  # avoid circular import\n     participant = Participant.from_username(slug)\n", "issue": "403 clicking \"fix credit card\" in email when not logged in\nMy credit card expired and I got the email reminding me to fix payment info. I clicked the \"fix credit card\" button in the email and was taken to a 403 Forbidden page. Would expect to be taken to login form when I'm not already logged in. Thanks!\n\n", "before_files": [{"content": "# encoding: utf8\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nfrom base64 import urlsafe_b64encode, urlsafe_b64decode\nfrom datetime import datetime, timedelta\n\nfrom aspen import Response, json\nfrom aspen.utils import to_rfc822, utcnow\nfrom dependency_injection import resolve_dependencies\nfrom postgres.cursors import SimpleCursorBase\n\nimport gratipay\n\n\nBEGINNING_OF_EPOCH = to_rfc822(datetime(1970, 1, 1)).encode('ascii')\n\n# Difference between current time and credit card expiring date when\n# card is considered as expiring\nEXPIRING_DELTA = timedelta(days = 30)\n\n\ndef dict_to_querystring(mapping):\n    if not mapping:\n        return u''\n\n    arguments = []\n    for key, values in mapping.iteritems():\n        for val in values:\n            arguments.append(u'='.join([key, val]))\n\n    return u'?' + u'&'.join(arguments)\n\n\ndef use_tildes_for_participants(website, request):\n    if request.path.raw.startswith('/~/'):\n        to = '/~' + request.path.raw[3:]\n        if request.qs.raw:\n            to += '?' + request.qs.raw\n        website.redirect(to)\n    elif request.path.raw.startswith('/~'):\n        request.path.__init__('/~/' + request.path.raw[2:])\n\n\ndef canonicalize(redirect, path, base, canonical, given, arguments=None):\n    if given != canonical:\n        assert canonical.lower() == given.lower()  # sanity check\n        remainder = path[len(base + given):]\n\n        if arguments is not None:\n            arguments = dict_to_querystring(arguments)\n\n        newpath = base + canonical + remainder + arguments or ''\n        redirect(newpath)\n\n\ndef get_participant(state, restrict=True, resolve_unclaimed=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    redirect = state['website'].redirect\n    request = state['request']\n    user = state['user']\n    slug = request.line.uri.path['username']\n    qs = request.line.uri.querystring\n    _ = state['_']\n\n    if restrict:\n        if user.ANON:\n            raise Response(403, _(\"You need to log in to access this page.\"))\n\n    from gratipay.models.participant import Participant  # avoid circular import\n    participant = Participant.from_username(slug)\n\n    if participant is None:\n        raise Response(404)\n\n    canonicalize(redirect, request.line.uri.path.raw, '/~/', participant.username, slug, qs)\n\n    if participant.is_closed:\n        if user.ADMIN:\n            return participant\n        raise Response(410)\n\n    if participant.claimed_time is None and resolve_unclaimed:\n        to = participant.resolve_unclaimed()\n        if to:\n            # This is a stub account (someone on another platform who hasn't\n            # actually registered with Gratipay yet)\n            redirect(to)\n        else:\n            # This is an archived account (result of take_over)\n            if user.ADMIN:\n                return participant\n            raise Response(404)\n\n    if restrict:\n        if participant != user.participant:\n            if not user.ADMIN:\n                raise Response(403, _(\"You are not authorized to access this page.\"))\n\n    return participant\n\n\ndef get_team(state):\n    \"\"\"Given a Request, raise Response or return Team.\n    \"\"\"\n    redirect = state['website'].redirect\n    request = state['request']\n    user = state['user']\n    slug = request.line.uri.path['team']\n    qs = request.line.uri.querystring\n\n    from gratipay.models.team import Team  # avoid circular import\n    team = Team.from_slug(slug)\n\n    if team is None:\n        # Try to redirect to a Participant.\n        from gratipay.models.participant import Participant # avoid circular import\n        participant = Participant.from_username(slug)\n        if participant is not None:\n            qs = '?' + request.qs.raw if request.qs.raw else ''\n            redirect('/~' + request.path.raw[1:] + qs)\n        raise Response(404)\n\n    canonicalize(redirect, request.line.uri.path.raw, '/', team.slug, slug, qs)\n\n    if team.is_closed and not user.ADMIN:\n        raise Response(410)\n\n    return team\n\n\ndef encode_for_querystring(s):\n    \"\"\"Given a unicode, return a unicode that's safe for transport across a querystring.\n    \"\"\"\n    if not isinstance(s, unicode):\n        raise TypeError('unicode required')\n    return urlsafe_b64encode(s.encode('utf8')).replace(b'=', b'~').decode('ascii')\n\n\ndef decode_from_querystring(s, **kw):\n    \"\"\"Given a unicode computed by encode_for_querystring, return the inverse.\n\n    We raise Response(400) if the input value can't be decoded (i.e., it's not\n    ASCII, not padded properly, or not decodable as UTF-8 once Base64-decoded).\n\n    \"\"\"\n    if not isinstance(s, unicode):\n        raise TypeError('unicode required')\n    try:\n        return urlsafe_b64decode(s.encode('ascii').replace(b'~', b'=')).decode('utf8')\n    except:\n        if 'default' in kw:\n            # Enable callers to handle errors without using try/except.\n            return kw['default']\n        raise Response(400, \"invalid input\")\n\n\ndef update_cta(website):\n    nusers = website.db.one(\"\"\"\n        SELECT nusers FROM paydays\n        ORDER BY ts_end DESC LIMIT 1\n    \"\"\", default=0)\n    nreceiving_from = website.db.one(\"\"\"\n        SELECT nreceiving_from\n          FROM teams\n         WHERE slug = 'Gratipay'\n    \"\"\", default=0)\n    website.support_current = cur = int(round(nreceiving_from / nusers * 100)) if nusers else 0\n    if cur < 10:    goal = 20\n    elif cur < 15:  goal = 30\n    elif cur < 25:  goal = 40\n    elif cur < 35:  goal = 50\n    elif cur < 45:  goal = 60\n    elif cur < 55:  goal = 70\n    elif cur < 65:  goal = 80\n    elif cur > 70:  goal = None\n    website.support_goal = goal\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 format_money(money):\n    format = '%.2f' if money < 1000 else '%.0f'\n    return format % money\n\n\ndef excerpt_intro(text, length=175, append=u'\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_expiring(expiration_year, expiration_month):\n    now = datetime.utcnow()\n    expiring_date = datetime(expiration_year, expiration_month, 1)\n    delta = expiring_date - now\n    return delta < EXPIRING_DELTA\n\n\ndef set_cookie(cookies, key, value, expires=None, httponly=True, path=b'/'):\n    cookies[key] = 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).encode('ascii')\n        cookie[b'expires'] = expires\n    if httponly:\n        cookie[b'httponly'] = True\n    if path:\n        cookie[b'path'] = path\n    if gratipay.use_secure_cookies:\n        cookie[b'secure'] = True\n\n\ndef erase_cookie(cookies, key, **kw):\n    set_cookie(cookies, key, '', BEGINNING_OF_EPOCH, **kw)\n\n\ndef filter_profile_nav(user, participant, pages):\n    out = []\n    for foo, bar, show_them, show_others in pages:\n        if (user.participant == participant and show_them) \\\n        or (user.participant != participant and show_others) \\\n        or user.ADMIN:\n            out.append((foo, bar, show_them, show_others))\n    return out\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\nclass LazyResponse(Response):\n\n    def __init__(self, code, lazy_body, **kw):\n        Response.__init__(self, code, '', **kw)\n        self.lazy_body = lazy_body\n\n    def render_body(self, state):\n        f = self.lazy_body\n        self.body = f(*resolve_dependencies(f, state).as_args)\n", "path": "gratipay/utils/__init__.py"}], "after_files": [{"content": "# encoding: utf8\n\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nfrom base64 import urlsafe_b64encode, urlsafe_b64decode\nfrom datetime import datetime, timedelta\n\nfrom aspen import Response, json\nfrom aspen.utils import to_rfc822, utcnow\nfrom dependency_injection import resolve_dependencies\nfrom postgres.cursors import SimpleCursorBase\n\nimport gratipay\n\n\nBEGINNING_OF_EPOCH = to_rfc822(datetime(1970, 1, 1)).encode('ascii')\n\n# Difference between current time and credit card expiring date when\n# card is considered as expiring\nEXPIRING_DELTA = timedelta(days = 30)\n\n\ndef dict_to_querystring(mapping):\n    if not mapping:\n        return u''\n\n    arguments = []\n    for key, values in mapping.iteritems():\n        for val in values:\n            arguments.append(u'='.join([key, val]))\n\n    return u'?' + u'&'.join(arguments)\n\n\ndef use_tildes_for_participants(website, request):\n    if request.path.raw.startswith('/~/'):\n        to = '/~' + request.path.raw[3:]\n        if request.qs.raw:\n            to += '?' + request.qs.raw\n        website.redirect(to)\n    elif request.path.raw.startswith('/~'):\n        request.path.__init__('/~/' + request.path.raw[2:])\n\n\ndef canonicalize(redirect, path, base, canonical, given, arguments=None):\n    if given != canonical:\n        assert canonical.lower() == given.lower()  # sanity check\n        remainder = path[len(base + given):]\n\n        if arguments is not None:\n            arguments = dict_to_querystring(arguments)\n\n        newpath = base + canonical + remainder + arguments or ''\n        redirect(newpath)\n\n\ndef get_participant(state, restrict=True, resolve_unclaimed=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    redirect = state['website'].redirect\n    request = state['request']\n    user = state['user']\n    slug = request.line.uri.path['username']\n    qs = request.line.uri.querystring\n    _ = state['_']\n\n    if restrict:\n        if user.ANON:\n            raise Response(401, _(\"You need to log in to access this page.\"))\n\n    from gratipay.models.participant import Participant  # avoid circular import\n    participant = Participant.from_username(slug)\n\n    if participant is None:\n        raise Response(404)\n\n    canonicalize(redirect, request.line.uri.path.raw, '/~/', participant.username, slug, qs)\n\n    if participant.is_closed:\n        if user.ADMIN:\n            return participant\n        raise Response(410)\n\n    if participant.claimed_time is None and resolve_unclaimed:\n        to = participant.resolve_unclaimed()\n        if to:\n            # This is a stub account (someone on another platform who hasn't\n            # actually registered with Gratipay yet)\n            redirect(to)\n        else:\n            # This is an archived account (result of take_over)\n            if user.ADMIN:\n                return participant\n            raise Response(404)\n\n    if restrict:\n        if participant != user.participant:\n            if not user.ADMIN:\n                raise Response(403, _(\"You are not authorized to access this page.\"))\n\n    return participant\n\n\ndef get_team(state):\n    \"\"\"Given a Request, raise Response or return Team.\n    \"\"\"\n    redirect = state['website'].redirect\n    request = state['request']\n    user = state['user']\n    slug = request.line.uri.path['team']\n    qs = request.line.uri.querystring\n\n    from gratipay.models.team import Team  # avoid circular import\n    team = Team.from_slug(slug)\n\n    if team is None:\n        # Try to redirect to a Participant.\n        from gratipay.models.participant import Participant # avoid circular import\n        participant = Participant.from_username(slug)\n        if participant is not None:\n            qs = '?' + request.qs.raw if request.qs.raw else ''\n            redirect('/~' + request.path.raw[1:] + qs)\n        raise Response(404)\n\n    canonicalize(redirect, request.line.uri.path.raw, '/', team.slug, slug, qs)\n\n    if team.is_closed and not user.ADMIN:\n        raise Response(410)\n\n    return team\n\n\ndef encode_for_querystring(s):\n    \"\"\"Given a unicode, return a unicode that's safe for transport across a querystring.\n    \"\"\"\n    if not isinstance(s, unicode):\n        raise TypeError('unicode required')\n    return urlsafe_b64encode(s.encode('utf8')).replace(b'=', b'~').decode('ascii')\n\n\ndef decode_from_querystring(s, **kw):\n    \"\"\"Given a unicode computed by encode_for_querystring, return the inverse.\n\n    We raise Response(400) if the input value can't be decoded (i.e., it's not\n    ASCII, not padded properly, or not decodable as UTF-8 once Base64-decoded).\n\n    \"\"\"\n    if not isinstance(s, unicode):\n        raise TypeError('unicode required')\n    try:\n        return urlsafe_b64decode(s.encode('ascii').replace(b'~', b'=')).decode('utf8')\n    except:\n        if 'default' in kw:\n            # Enable callers to handle errors without using try/except.\n            return kw['default']\n        raise Response(400, \"invalid input\")\n\n\ndef update_cta(website):\n    nusers = website.db.one(\"\"\"\n        SELECT nusers FROM paydays\n        ORDER BY ts_end DESC LIMIT 1\n    \"\"\", default=0)\n    nreceiving_from = website.db.one(\"\"\"\n        SELECT nreceiving_from\n          FROM teams\n         WHERE slug = 'Gratipay'\n    \"\"\", default=0)\n    website.support_current = cur = int(round(nreceiving_from / nusers * 100)) if nusers else 0\n    if cur < 10:    goal = 20\n    elif cur < 15:  goal = 30\n    elif cur < 25:  goal = 40\n    elif cur < 35:  goal = 50\n    elif cur < 45:  goal = 60\n    elif cur < 55:  goal = 70\n    elif cur < 65:  goal = 80\n    elif cur > 70:  goal = None\n    website.support_goal = goal\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 format_money(money):\n    format = '%.2f' if money < 1000 else '%.0f'\n    return format % money\n\n\ndef excerpt_intro(text, length=175, append=u'\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_expiring(expiration_year, expiration_month):\n    now = datetime.utcnow()\n    expiring_date = datetime(expiration_year, expiration_month, 1)\n    delta = expiring_date - now\n    return delta < EXPIRING_DELTA\n\n\ndef set_cookie(cookies, key, value, expires=None, httponly=True, path=b'/'):\n    cookies[key] = 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).encode('ascii')\n        cookie[b'expires'] = expires\n    if httponly:\n        cookie[b'httponly'] = True\n    if path:\n        cookie[b'path'] = path\n    if gratipay.use_secure_cookies:\n        cookie[b'secure'] = True\n\n\ndef erase_cookie(cookies, key, **kw):\n    set_cookie(cookies, key, '', BEGINNING_OF_EPOCH, **kw)\n\n\ndef filter_profile_nav(user, participant, pages):\n    out = []\n    for foo, bar, show_them, show_others in pages:\n        if (user.participant == participant and show_them) \\\n        or (user.participant != participant and show_others) \\\n        or user.ADMIN:\n            out.append((foo, bar, show_them, show_others))\n    return out\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\nclass LazyResponse(Response):\n\n    def __init__(self, code, lazy_body, **kw):\n        Response.__init__(self, code, '', **kw)\n        self.lazy_body = lazy_body\n\n    def render_body(self, state):\n        f = self.lazy_body\n        self.body = f(*resolve_dependencies(f, state).as_args)\n", "path": "gratipay/utils/__init__.py"}]}