We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
The list of top individuals is incomplete
While looking at https://liberapay.com/explore/individuals I realized that ploum isn't listed. It's because he doesn't have a profile statement. The thinking was that without a statement there isn't much to see on a profile page, so there's little point in linking to it. However it also makes the list incomplete.
The list of top individuals is incomplete
While looking at https://liberapay.com/explore/individuals I realized that ploum isn't listed. It's because he doesn't have a profile statement. The thinking was that without a statement there isn't much to see on a profile page, so there's little point in linking to it. However it also makes the list incomplete.

--- 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/constants.py`
Content:
```
1 # coding: utf8
2 from __future__ import print_function, unicode_literals
3 
4 from collections import namedtuple, OrderedDict
5 from datetime import date, datetime, timedelta
6 from decimal import Decimal, ROUND_UP
7 import re
8 
9 from jinja2 import StrictUndefined
10 from pando.utils import utc
11 
12 
13 class CustomUndefined(StrictUndefined):
14     __bool__ = __nonzero__ = lambda self: False
15 
16     def __str__(self):
17         try:
18             self._fail_with_undefined_error()
19         except Exception as e:
20             self._tell_sentry(e, {})
21         return ''
22 
23     __unicode__ = __str__
24 
25 
26 def check_bits(bits):
27     assert len(set(bits)) == len(bits)  # no duplicates
28     assert not [b for b in bits if '{0:b}'.format(b).count('1') != 1]  # single bit
29 
30 
31 Event = namedtuple('Event', 'name bit title')
32 
33 Fees = namedtuple('Fees', ('var', 'fix'))
34 
35 StandardTip = namedtuple('StandardTip', 'label weekly monthly yearly')
36 
37 
38 _ = lambda a: a
39 
40 ASCII_ALLOWED_IN_USERNAME = set("0123456789"
41                                 "abcdefghijklmnopqrstuvwxyz"
42                                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
43                                 "-_.")
44 
45 AVATAR_QUERY = '?s=160&default=retro'
46 AVATAR_SOURCES = 'libravatar bitbucket facebook github google mastodon twitter'.split()
47 
48 BIRTHDAY = date(2015, 5, 22)
49 
50 D_CENT = Decimal('0.01')
51 D_INF = Decimal('inf')
52 D_UNIT = Decimal('1.00')
53 D_ZERO = Decimal('0.00')
54 
55 DONATION_LIMITS_WEEKLY = (Decimal('0.01'), Decimal('100.00'))
56 DONATION_LIMITS = {
57     'weekly': DONATION_LIMITS_WEEKLY,
58     'monthly': tuple((x * Decimal(52) / Decimal(12)).quantize(D_CENT, rounding=ROUND_UP)
59                      for x in DONATION_LIMITS_WEEKLY),
60     'yearly': tuple((x * Decimal(52)).quantize(D_CENT)
61                     for x in DONATION_LIMITS_WEEKLY),
62 }
63 DONATION_WEEKLY_MIN, DONATION_WEEKLY_MAX = DONATION_LIMITS_WEEKLY
64 
65 DOMAIN_RE = re.compile(r'''
66     ^
67     ([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+
68     [a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?
69     $
70 ''', re.VERBOSE)
71 
72 ELSEWHERE_ACTIONS = {'connect', 'lock', 'unlock'}
73 
74 EMAIL_VERIFICATION_TIMEOUT = timedelta(hours=24)
75 EMAIL_RE = re.compile(r'''
76     # This is the regexp used by MangoPay (as of February 2017).
77     # It rejects some valid but exotic addresses.
78     # https://en.wikipedia.org/wiki/Email_address
79     ^
80     [a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*
81     @
82     ([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?
83     $
84 ''', re.VERBOSE)
85 
86 EPOCH = datetime(1970, 1, 1, 0, 0, 0, 0, utc)
87 
88 EVENTS = [
89     Event('income', 1, _("When I receive money")),
90     Event('low_balance', 2, _("When there isn't enough money in my wallet to cover my donations")),
91     Event('withdrawal_created', 4, _("When a transfer to my bank account is initiated")),
92     Event('withdrawal_failed', 8, _("When a transfer to my bank account fails")),
93     Event('pledgee_joined', 16, _("When someone I pledge to joins Liberapay")),
94     Event('team_invite', 32, _("When someone invites me to join a team")),
95     Event('payin_bankwire_failed', 64, _("When a bank wire transfer to my Liberapay wallet fails")),
96     Event('payin_bankwire_succeeded', 128, _("When a bank wire transfer to my Liberapay wallet succeeds")),
97     Event('payin_bankwire_expired', 256, _("When a bank wire transfer to my Liberapay wallet expires")),
98     Event('payin_directdebit_failed', 512, _("When a direct debit from my bank account fails")),
99     Event('payin_directdebit_succeeded', 1024, _("When a direct debit from my bank account succeeds")),
100 ]
101 check_bits([e.bit for e in EVENTS])
102 EVENTS = OrderedDict((e.name, e) for e in EVENTS)
103 EVENTS_S = ' '.join(EVENTS.keys())
104 
105 # https://www.mangopay.com/pricing/
106 FEE_PAYIN_BANK_WIRE = Fees(Decimal('0.005'), Decimal(0))  # 0.5%
107 FEE_PAYIN_CARD = Fees(Decimal('0.018'), Decimal('0.18'))  # 1.8% + €0.18
108 FEE_PAYIN_DIRECT_DEBIT = Fees(Decimal(0), Decimal('0.80'))  # €0.80
109 FEE_PAYOUT = Fees(Decimal(0), Decimal(0))
110 FEE_PAYOUT_OUTSIDE_SEPA = Fees(Decimal(0), Decimal('2.5'))
111 FEE_PAYOUT_WARN = Decimal('0.03')  # warn user when fee exceeds 3%
112 FEE_VAT = Decimal('0.17')  # 17% (Luxembourg rate)
113 
114 INVOICE_DOC_MAX_SIZE = 5000000
115 INVOICE_DOCS_EXTS = ['pdf', 'jpeg', 'jpg', 'png']
116 INVOICE_DOCS_LIMIT = 10
117 
118 INVOICE_NATURES = {
119     'expense': _("Expense Report"),
120 }
121 
122 INVOICE_STATUSES = {
123     'pre': _("Draft"),
124     'new': _("Sent (awaiting approval)"),
125     'retracted': _("Retracted"),
126     'accepted': _("Accepted (awaiting payment)"),
127     'paid': _("Paid"),
128     'rejected': _("Rejected"),
129 }
130 
131 JINJA_ENV_COMMON = dict(
132     trim_blocks=True, lstrip_blocks=True,
133     line_statement_prefix='%',
134     # undefined=CustomUndefined,
135 )
136 
137 # https://docs.mangopay.com/api-references/kyc-rules/
138 KYC_DOC_MAX_SIZE = 7000000
139 KYC_DOC_MAX_SIZE_MB = int(KYC_DOC_MAX_SIZE / 1000000)
140 KYC_DOCS_EXTS = ['pdf', 'jpeg', 'jpg', 'gif', 'png']
141 KYC_DOCS_EXTS_STR = ', '.join(KYC_DOCS_EXTS)
142 KYC_INCOME_THRESHOLDS = (
143     (1, 18000),
144     (2, 30000),
145     (3, 50000),
146     (4, 80000),
147     (5, 120000),
148     (6, 120000),
149 )
150 KYC_PAYIN_YEARLY_THRESHOLD = Decimal('2500')
151 KYC_PAYOUT_YEARLY_THRESHOLD = Decimal('1000')
152 
153 LAUNCH_TIME = datetime(2016, 2, 3, 12, 50, 0, 0, utc)
154 
155 PARTICIPANT_KINDS = {
156     'individual': _("Individual"),
157     'organization': _("Organization"),
158     'group': _("Team"),
159 }
160 
161 PASSWORD_MIN_SIZE = 8
162 PASSWORD_MAX_SIZE = 150
163 
164 PAYIN_BANK_WIRE_MIN = Decimal('2.00')  # fee ≈ 0.99%
165 PAYIN_BANK_WIRE_TARGET = Decimal('5.00')  # fee ≈ 0.6%
166 PAYIN_CARD_MIN = Decimal("15.00")  # fee ≈ 3.5%
167 PAYIN_CARD_TARGET = Decimal("92.00")  # fee ≈ 2.33%
168 PAYIN_DIRECT_DEBIT_MIN = Decimal('25.00')  # fee ≈ 3.6%
169 PAYIN_DIRECT_DEBIT_TARGET = Decimal('99.00')  # fee ≈ 0.94%
170 
171 PERIOD_CONVERSION_RATES = {
172     'weekly': Decimal(1),
173     'monthly': Decimal(12) / Decimal(52),
174     'yearly': Decimal(1) / Decimal(52),
175 }
176 
177 POSTAL_ADDRESS_KEYS = (
178     'AddressLine1', 'AddressLine2', 'City', 'Region', 'PostalCode', 'Country'
179 )
180 
181 PRIVACY_FIELDS = OrderedDict([
182     ('hide_giving', _("Hide total giving from others.")),
183     ('hide_receiving', _("Hide total receiving from others.")),
184     ('hide_from_search', _("Hide myself from search results on Liberapay.")),
185     ('profile_noindex', _("Tell web search engines not to index my profile.")),
186     ('hide_from_lists', _("Prevent my profile from being listed on Liberapay.")),
187 ])
188 PRIVACY_FIELDS_S = ' '.join(PRIVACY_FIELDS.keys())
189 
190 PRIVILEGES = dict(admin=1, run_payday=2)
191 check_bits(list(PRIVILEGES.values()))
192 
193 QUARANTINE = timedelta(weeks=4)
194 
195 RATE_LIMITS = {
196     'add_email.source': (5, 60*60*24),  # 5 per day
197     'add_email.target': (2, 60*60*24),  # 2 per day
198     'change_username': (7, 60*60*24*7),  # 7 per week
199     'log-in.email': (10, 60*60*24),  # 10 per day
200     'log-in.email.not-verified': (2, 60*60*24),  # 2 per day
201     'log-in.email.verified': (10, 60*60*24),  # 10 per day
202     'log-in.password': (3, 60*60),  # 3 per hour
203     'sign-up.ip-addr': (5, 60*60),  # 5 per hour per IP address
204     'sign-up.ip-net': (15, 15*60),  # 15 per 15 minutes per IP network
205     'sign-up.ip-version': (15, 15*60),  # 15 per 15 minutes per IP version
206 }
207 
208 SEPA = set("""
209     AT BE BG CH CY CZ DE DK EE ES ES FI FR GB GI GR HR HU IE IS IT LI LT LU LV
210     MC MT NL NO PL PT RO SE SI SK
211 """.split())
212 
213 SESSION = str('session')  # bytes in python2, unicode in python3
214 SESSION_REFRESH = timedelta(hours=1)
215 SESSION_TIMEOUT = timedelta(hours=6)
216 
217 
218 def make_standard_tip(label, weekly):
219     return StandardTip(
220         label,
221         weekly,
222         weekly / PERIOD_CONVERSION_RATES['monthly'],
223         weekly / PERIOD_CONVERSION_RATES['yearly'],
224     )
225 
226 
227 STANDARD_TIPS = (
228     make_standard_tip(_("Symbolic"), Decimal('0.01')),
229     make_standard_tip(_("Small"), Decimal('0.25')),
230     make_standard_tip(_("Medium"), Decimal('1.00')),
231     make_standard_tip(_("Large"), Decimal('5.00')),
232     make_standard_tip(_("Maximum"), DONATION_WEEKLY_MAX),
233 )
234 
235 USERNAME_MAX_SIZE = 32
236 
237 del _
238
```
--- 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/constants.py b/liberapay/constants.py
--- a/liberapay/constants.py
+++ b/liberapay/constants.py
@@ -232,6 +232,8 @@
     make_standard_tip(_("Maximum"), DONATION_WEEKLY_MAX),
 )
 
+SUMMARY_MAX_SIZE = 100
+
 USERNAME_MAX_SIZE = 32
 
 del _

{"golden_diff": "diff --git a/liberapay/constants.py b/liberapay/constants.py\n--- a/liberapay/constants.py\n+++ b/liberapay/constants.py\n@@ -232,6 +232,8 @@\n     make_standard_tip(_(\"Maximum\"), DONATION_WEEKLY_MAX),\n )\n \n+SUMMARY_MAX_SIZE = 100\n+\n USERNAME_MAX_SIZE = 32\n \n del _\n", "issue": "The list of top individuals is incomplete\nWhile looking at https://liberapay.com/explore/individuals I realized that ploum isn't listed. It's because he doesn't have a profile statement. The thinking was that without a statement there isn't much to see on a profile page, so there's little point in linking to it. However it also makes the list incomplete.\nThe list of top individuals is incomplete\nWhile looking at https://liberapay.com/explore/individuals I realized that ploum isn't listed. It's because he doesn't have a profile statement. The thinking was that without a statement there isn't much to see on a profile page, so there's little point in linking to it. However it also makes the list incomplete.\n", "before_files": [{"content": "# coding: utf8\nfrom __future__ import print_function, unicode_literals\n\nfrom collections import namedtuple, OrderedDict\nfrom datetime import date, datetime, timedelta\nfrom decimal import Decimal, ROUND_UP\nimport re\n\nfrom jinja2 import StrictUndefined\nfrom pando.utils import utc\n\n\nclass CustomUndefined(StrictUndefined):\n    __bool__ = __nonzero__ = lambda self: False\n\n    def __str__(self):\n        try:\n            self._fail_with_undefined_error()\n        except Exception as e:\n            self._tell_sentry(e, {})\n        return ''\n\n    __unicode__ = __str__\n\n\ndef check_bits(bits):\n    assert len(set(bits)) == len(bits)  # no duplicates\n    assert not [b for b in bits if '{0:b}'.format(b).count('1') != 1]  # single bit\n\n\nEvent = namedtuple('Event', 'name bit title')\n\nFees = namedtuple('Fees', ('var', 'fix'))\n\nStandardTip = namedtuple('StandardTip', 'label weekly monthly yearly')\n\n\n_ = lambda a: a\n\nASCII_ALLOWED_IN_USERNAME = set(\"0123456789\"\n                                \"abcdefghijklmnopqrstuvwxyz\"\n                                \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n                                \"-_.\")\n\nAVATAR_QUERY = '?s=160&default=retro'\nAVATAR_SOURCES = 'libravatar bitbucket facebook github google mastodon twitter'.split()\n\nBIRTHDAY = date(2015, 5, 22)\n\nD_CENT = Decimal('0.01')\nD_INF = Decimal('inf')\nD_UNIT = Decimal('1.00')\nD_ZERO = Decimal('0.00')\n\nDONATION_LIMITS_WEEKLY = (Decimal('0.01'), Decimal('100.00'))\nDONATION_LIMITS = {\n    'weekly': DONATION_LIMITS_WEEKLY,\n    'monthly': tuple((x * Decimal(52) / Decimal(12)).quantize(D_CENT, rounding=ROUND_UP)\n                     for x in DONATION_LIMITS_WEEKLY),\n    'yearly': tuple((x * Decimal(52)).quantize(D_CENT)\n                    for x in DONATION_LIMITS_WEEKLY),\n}\nDONATION_WEEKLY_MIN, DONATION_WEEKLY_MAX = DONATION_LIMITS_WEEKLY\n\nDOMAIN_RE = re.compile(r'''\n    ^\n    ([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+\n    [a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\n    $\n''', re.VERBOSE)\n\nELSEWHERE_ACTIONS = {'connect', 'lock', 'unlock'}\n\nEMAIL_VERIFICATION_TIMEOUT = timedelta(hours=24)\nEMAIL_RE = re.compile(r'''\n    # This is the regexp used by MangoPay (as of February 2017).\n    # It rejects some valid but exotic addresses.\n    # https://en.wikipedia.org/wiki/Email_address\n    ^\n    [a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*\n    @\n    ([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\n    $\n''', re.VERBOSE)\n\nEPOCH = datetime(1970, 1, 1, 0, 0, 0, 0, utc)\n\nEVENTS = [\n    Event('income', 1, _(\"When I receive money\")),\n    Event('low_balance', 2, _(\"When there isn't enough money in my wallet to cover my donations\")),\n    Event('withdrawal_created', 4, _(\"When a transfer to my bank account is initiated\")),\n    Event('withdrawal_failed', 8, _(\"When a transfer to my bank account fails\")),\n    Event('pledgee_joined', 16, _(\"When someone I pledge to joins Liberapay\")),\n    Event('team_invite', 32, _(\"When someone invites me to join a team\")),\n    Event('payin_bankwire_failed', 64, _(\"When a bank wire transfer to my Liberapay wallet fails\")),\n    Event('payin_bankwire_succeeded', 128, _(\"When a bank wire transfer to my Liberapay wallet succeeds\")),\n    Event('payin_bankwire_expired', 256, _(\"When a bank wire transfer to my Liberapay wallet expires\")),\n    Event('payin_directdebit_failed', 512, _(\"When a direct debit from my bank account fails\")),\n    Event('payin_directdebit_succeeded', 1024, _(\"When a direct debit from my bank account succeeds\")),\n]\ncheck_bits([e.bit for e in EVENTS])\nEVENTS = OrderedDict((e.name, e) for e in EVENTS)\nEVENTS_S = ' '.join(EVENTS.keys())\n\n# https://www.mangopay.com/pricing/\nFEE_PAYIN_BANK_WIRE = Fees(Decimal('0.005'), Decimal(0))  # 0.5%\nFEE_PAYIN_CARD = Fees(Decimal('0.018'), Decimal('0.18'))  # 1.8% + \u20ac0.18\nFEE_PAYIN_DIRECT_DEBIT = Fees(Decimal(0), Decimal('0.80'))  # \u20ac0.80\nFEE_PAYOUT = Fees(Decimal(0), Decimal(0))\nFEE_PAYOUT_OUTSIDE_SEPA = Fees(Decimal(0), Decimal('2.5'))\nFEE_PAYOUT_WARN = Decimal('0.03')  # warn user when fee exceeds 3%\nFEE_VAT = Decimal('0.17')  # 17% (Luxembourg rate)\n\nINVOICE_DOC_MAX_SIZE = 5000000\nINVOICE_DOCS_EXTS = ['pdf', 'jpeg', 'jpg', 'png']\nINVOICE_DOCS_LIMIT = 10\n\nINVOICE_NATURES = {\n    'expense': _(\"Expense Report\"),\n}\n\nINVOICE_STATUSES = {\n    'pre': _(\"Draft\"),\n    'new': _(\"Sent (awaiting approval)\"),\n    'retracted': _(\"Retracted\"),\n    'accepted': _(\"Accepted (awaiting payment)\"),\n    'paid': _(\"Paid\"),\n    'rejected': _(\"Rejected\"),\n}\n\nJINJA_ENV_COMMON = dict(\n    trim_blocks=True, lstrip_blocks=True,\n    line_statement_prefix='%',\n    # undefined=CustomUndefined,\n)\n\n# https://docs.mangopay.com/api-references/kyc-rules/\nKYC_DOC_MAX_SIZE = 7000000\nKYC_DOC_MAX_SIZE_MB = int(KYC_DOC_MAX_SIZE / 1000000)\nKYC_DOCS_EXTS = ['pdf', 'jpeg', 'jpg', 'gif', 'png']\nKYC_DOCS_EXTS_STR = ', '.join(KYC_DOCS_EXTS)\nKYC_INCOME_THRESHOLDS = (\n    (1, 18000),\n    (2, 30000),\n    (3, 50000),\n    (4, 80000),\n    (5, 120000),\n    (6, 120000),\n)\nKYC_PAYIN_YEARLY_THRESHOLD = Decimal('2500')\nKYC_PAYOUT_YEARLY_THRESHOLD = Decimal('1000')\n\nLAUNCH_TIME = datetime(2016, 2, 3, 12, 50, 0, 0, utc)\n\nPARTICIPANT_KINDS = {\n    'individual': _(\"Individual\"),\n    'organization': _(\"Organization\"),\n    'group': _(\"Team\"),\n}\n\nPASSWORD_MIN_SIZE = 8\nPASSWORD_MAX_SIZE = 150\n\nPAYIN_BANK_WIRE_MIN = Decimal('2.00')  # fee \u2248 0.99%\nPAYIN_BANK_WIRE_TARGET = Decimal('5.00')  # fee \u2248 0.6%\nPAYIN_CARD_MIN = Decimal(\"15.00\")  # fee \u2248 3.5%\nPAYIN_CARD_TARGET = Decimal(\"92.00\")  # fee \u2248 2.33%\nPAYIN_DIRECT_DEBIT_MIN = Decimal('25.00')  # fee \u2248 3.6%\nPAYIN_DIRECT_DEBIT_TARGET = Decimal('99.00')  # fee \u2248 0.94%\n\nPERIOD_CONVERSION_RATES = {\n    'weekly': Decimal(1),\n    'monthly': Decimal(12) / Decimal(52),\n    'yearly': Decimal(1) / Decimal(52),\n}\n\nPOSTAL_ADDRESS_KEYS = (\n    'AddressLine1', 'AddressLine2', 'City', 'Region', 'PostalCode', 'Country'\n)\n\nPRIVACY_FIELDS = OrderedDict([\n    ('hide_giving', _(\"Hide total giving from others.\")),\n    ('hide_receiving', _(\"Hide total receiving from others.\")),\n    ('hide_from_search', _(\"Hide myself from search results on Liberapay.\")),\n    ('profile_noindex', _(\"Tell web search engines not to index my profile.\")),\n    ('hide_from_lists', _(\"Prevent my profile from being listed on Liberapay.\")),\n])\nPRIVACY_FIELDS_S = ' '.join(PRIVACY_FIELDS.keys())\n\nPRIVILEGES = dict(admin=1, run_payday=2)\ncheck_bits(list(PRIVILEGES.values()))\n\nQUARANTINE = timedelta(weeks=4)\n\nRATE_LIMITS = {\n    'add_email.source': (5, 60*60*24),  # 5 per day\n    'add_email.target': (2, 60*60*24),  # 2 per day\n    'change_username': (7, 60*60*24*7),  # 7 per week\n    'log-in.email': (10, 60*60*24),  # 10 per day\n    'log-in.email.not-verified': (2, 60*60*24),  # 2 per day\n    'log-in.email.verified': (10, 60*60*24),  # 10 per day\n    'log-in.password': (3, 60*60),  # 3 per hour\n    'sign-up.ip-addr': (5, 60*60),  # 5 per hour per IP address\n    'sign-up.ip-net': (15, 15*60),  # 15 per 15 minutes per IP network\n    'sign-up.ip-version': (15, 15*60),  # 15 per 15 minutes per IP version\n}\n\nSEPA = set(\"\"\"\n    AT BE BG CH CY CZ DE DK EE ES ES FI FR GB GI GR HR HU IE IS IT LI LT LU LV\n    MC MT NL NO PL PT RO SE SI SK\n\"\"\".split())\n\nSESSION = str('session')  # bytes in python2, unicode in python3\nSESSION_REFRESH = timedelta(hours=1)\nSESSION_TIMEOUT = timedelta(hours=6)\n\n\ndef make_standard_tip(label, weekly):\n    return StandardTip(\n        label,\n        weekly,\n        weekly / PERIOD_CONVERSION_RATES['monthly'],\n        weekly / PERIOD_CONVERSION_RATES['yearly'],\n    )\n\n\nSTANDARD_TIPS = (\n    make_standard_tip(_(\"Symbolic\"), Decimal('0.01')),\n    make_standard_tip(_(\"Small\"), Decimal('0.25')),\n    make_standard_tip(_(\"Medium\"), Decimal('1.00')),\n    make_standard_tip(_(\"Large\"), Decimal('5.00')),\n    make_standard_tip(_(\"Maximum\"), DONATION_WEEKLY_MAX),\n)\n\nUSERNAME_MAX_SIZE = 32\n\ndel _\n", "path": "liberapay/constants.py"}], "after_files": [{"content": "# coding: utf8\nfrom __future__ import print_function, unicode_literals\n\nfrom collections import namedtuple, OrderedDict\nfrom datetime import date, datetime, timedelta\nfrom decimal import Decimal, ROUND_UP\nimport re\n\nfrom jinja2 import StrictUndefined\nfrom pando.utils import utc\n\n\nclass CustomUndefined(StrictUndefined):\n    __bool__ = __nonzero__ = lambda self: False\n\n    def __str__(self):\n        try:\n            self._fail_with_undefined_error()\n        except Exception as e:\n            self._tell_sentry(e, {})\n        return ''\n\n    __unicode__ = __str__\n\n\ndef check_bits(bits):\n    assert len(set(bits)) == len(bits)  # no duplicates\n    assert not [b for b in bits if '{0:b}'.format(b).count('1') != 1]  # single bit\n\n\nEvent = namedtuple('Event', 'name bit title')\n\nFees = namedtuple('Fees', ('var', 'fix'))\n\nStandardTip = namedtuple('StandardTip', 'label weekly monthly yearly')\n\n\n_ = lambda a: a\n\nASCII_ALLOWED_IN_USERNAME = set(\"0123456789\"\n                                \"abcdefghijklmnopqrstuvwxyz\"\n                                \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n                                \"-_.\")\n\nAVATAR_QUERY = '?s=160&default=retro'\nAVATAR_SOURCES = 'libravatar bitbucket facebook github google mastodon twitter'.split()\n\nBIRTHDAY = date(2015, 5, 22)\n\nD_CENT = Decimal('0.01')\nD_INF = Decimal('inf')\nD_UNIT = Decimal('1.00')\nD_ZERO = Decimal('0.00')\n\nDONATION_LIMITS_WEEKLY = (Decimal('0.01'), Decimal('100.00'))\nDONATION_LIMITS = {\n    'weekly': DONATION_LIMITS_WEEKLY,\n    'monthly': tuple((x * Decimal(52) / Decimal(12)).quantize(D_CENT, rounding=ROUND_UP)\n                     for x in DONATION_LIMITS_WEEKLY),\n    'yearly': tuple((x * Decimal(52)).quantize(D_CENT)\n                    for x in DONATION_LIMITS_WEEKLY),\n}\nDONATION_WEEKLY_MIN, DONATION_WEEKLY_MAX = DONATION_LIMITS_WEEKLY\n\nDOMAIN_RE = re.compile(r'''\n    ^\n    ([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+\n    [a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\n    $\n''', re.VERBOSE)\n\nELSEWHERE_ACTIONS = {'connect', 'lock', 'unlock'}\n\nEMAIL_VERIFICATION_TIMEOUT = timedelta(hours=24)\nEMAIL_RE = re.compile(r'''\n    # This is the regexp used by MangoPay (as of February 2017).\n    # It rejects some valid but exotic addresses.\n    # https://en.wikipedia.org/wiki/Email_address\n    ^\n    [a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*\n    @\n    ([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\n    $\n''', re.VERBOSE)\n\nEPOCH = datetime(1970, 1, 1, 0, 0, 0, 0, utc)\n\nEVENTS = [\n    Event('income', 1, _(\"When I receive money\")),\n    Event('low_balance', 2, _(\"When there isn't enough money in my wallet to cover my donations\")),\n    Event('withdrawal_created', 4, _(\"When a transfer to my bank account is initiated\")),\n    Event('withdrawal_failed', 8, _(\"When a transfer to my bank account fails\")),\n    Event('pledgee_joined', 16, _(\"When someone I pledge to joins Liberapay\")),\n    Event('team_invite', 32, _(\"When someone invites me to join a team\")),\n    Event('payin_bankwire_failed', 64, _(\"When a bank wire transfer to my Liberapay wallet fails\")),\n    Event('payin_bankwire_succeeded', 128, _(\"When a bank wire transfer to my Liberapay wallet succeeds\")),\n    Event('payin_bankwire_expired', 256, _(\"When a bank wire transfer to my Liberapay wallet expires\")),\n    Event('payin_directdebit_failed', 512, _(\"When a direct debit from my bank account fails\")),\n    Event('payin_directdebit_succeeded', 1024, _(\"When a direct debit from my bank account succeeds\")),\n]\ncheck_bits([e.bit for e in EVENTS])\nEVENTS = OrderedDict((e.name, e) for e in EVENTS)\nEVENTS_S = ' '.join(EVENTS.keys())\n\n# https://www.mangopay.com/pricing/\nFEE_PAYIN_BANK_WIRE = Fees(Decimal('0.005'), Decimal(0))  # 0.5%\nFEE_PAYIN_CARD = Fees(Decimal('0.018'), Decimal('0.18'))  # 1.8% + \u20ac0.18\nFEE_PAYIN_DIRECT_DEBIT = Fees(Decimal(0), Decimal('0.80'))  # \u20ac0.80\nFEE_PAYOUT = Fees(Decimal(0), Decimal(0))\nFEE_PAYOUT_OUTSIDE_SEPA = Fees(Decimal(0), Decimal('2.5'))\nFEE_PAYOUT_WARN = Decimal('0.03')  # warn user when fee exceeds 3%\nFEE_VAT = Decimal('0.17')  # 17% (Luxembourg rate)\n\nINVOICE_DOC_MAX_SIZE = 5000000\nINVOICE_DOCS_EXTS = ['pdf', 'jpeg', 'jpg', 'png']\nINVOICE_DOCS_LIMIT = 10\n\nINVOICE_NATURES = {\n    'expense': _(\"Expense Report\"),\n}\n\nINVOICE_STATUSES = {\n    'pre': _(\"Draft\"),\n    'new': _(\"Sent (awaiting approval)\"),\n    'retracted': _(\"Retracted\"),\n    'accepted': _(\"Accepted (awaiting payment)\"),\n    'paid': _(\"Paid\"),\n    'rejected': _(\"Rejected\"),\n}\n\nJINJA_ENV_COMMON = dict(\n    trim_blocks=True, lstrip_blocks=True,\n    line_statement_prefix='%',\n    # undefined=CustomUndefined,\n)\n\n# https://docs.mangopay.com/api-references/kyc-rules/\nKYC_DOC_MAX_SIZE = 7000000\nKYC_DOC_MAX_SIZE_MB = int(KYC_DOC_MAX_SIZE / 1000000)\nKYC_DOCS_EXTS = ['pdf', 'jpeg', 'jpg', 'gif', 'png']\nKYC_DOCS_EXTS_STR = ', '.join(KYC_DOCS_EXTS)\nKYC_INCOME_THRESHOLDS = (\n    (1, 18000),\n    (2, 30000),\n    (3, 50000),\n    (4, 80000),\n    (5, 120000),\n    (6, 120000),\n)\nKYC_PAYIN_YEARLY_THRESHOLD = Decimal('2500')\nKYC_PAYOUT_YEARLY_THRESHOLD = Decimal('1000')\n\nLAUNCH_TIME = datetime(2016, 2, 3, 12, 50, 0, 0, utc)\n\nPARTICIPANT_KINDS = {\n    'individual': _(\"Individual\"),\n    'organization': _(\"Organization\"),\n    'group': _(\"Team\"),\n}\n\nPASSWORD_MIN_SIZE = 8\nPASSWORD_MAX_SIZE = 150\n\nPAYIN_BANK_WIRE_MIN = Decimal('2.00')  # fee \u2248 0.99%\nPAYIN_BANK_WIRE_TARGET = Decimal('5.00')  # fee \u2248 0.6%\nPAYIN_CARD_MIN = Decimal(\"15.00\")  # fee \u2248 3.5%\nPAYIN_CARD_TARGET = Decimal(\"92.00\")  # fee \u2248 2.33%\nPAYIN_DIRECT_DEBIT_MIN = Decimal('25.00')  # fee \u2248 3.6%\nPAYIN_DIRECT_DEBIT_TARGET = Decimal('99.00')  # fee \u2248 0.94%\n\nPERIOD_CONVERSION_RATES = {\n    'weekly': Decimal(1),\n    'monthly': Decimal(12) / Decimal(52),\n    'yearly': Decimal(1) / Decimal(52),\n}\n\nPOSTAL_ADDRESS_KEYS = (\n    'AddressLine1', 'AddressLine2', 'City', 'Region', 'PostalCode', 'Country'\n)\n\nPRIVACY_FIELDS = OrderedDict([\n    ('hide_giving', _(\"Hide total giving from others.\")),\n    ('hide_receiving', _(\"Hide total receiving from others.\")),\n    ('hide_from_search', _(\"Hide myself from search results on Liberapay.\")),\n    ('profile_noindex', _(\"Tell web search engines not to index my profile.\")),\n    ('hide_from_lists', _(\"Prevent my profile from being listed on Liberapay.\")),\n])\nPRIVACY_FIELDS_S = ' '.join(PRIVACY_FIELDS.keys())\n\nPRIVILEGES = dict(admin=1, run_payday=2)\ncheck_bits(list(PRIVILEGES.values()))\n\nQUARANTINE = timedelta(weeks=4)\n\nRATE_LIMITS = {\n    'add_email.source': (5, 60*60*24),  # 5 per day\n    'add_email.target': (2, 60*60*24),  # 2 per day\n    'change_username': (7, 60*60*24*7),  # 7 per week\n    'log-in.email': (10, 60*60*24),  # 10 per day\n    'log-in.email.not-verified': (2, 60*60*24),  # 2 per day\n    'log-in.email.verified': (10, 60*60*24),  # 10 per day\n    'log-in.password': (3, 60*60),  # 3 per hour\n    'sign-up.ip-addr': (5, 60*60),  # 5 per hour per IP address\n    'sign-up.ip-net': (15, 15*60),  # 15 per 15 minutes per IP network\n    'sign-up.ip-version': (15, 15*60),  # 15 per 15 minutes per IP version\n}\n\nSEPA = set(\"\"\"\n    AT BE BG CH CY CZ DE DK EE ES ES FI FR GB GI GR HR HU IE IS IT LI LT LU LV\n    MC MT NL NO PL PT RO SE SI SK\n\"\"\".split())\n\nSESSION = str('session')  # bytes in python2, unicode in python3\nSESSION_REFRESH = timedelta(hours=1)\nSESSION_TIMEOUT = timedelta(hours=6)\n\n\ndef make_standard_tip(label, weekly):\n    return StandardTip(\n        label,\n        weekly,\n        weekly / PERIOD_CONVERSION_RATES['monthly'],\n        weekly / PERIOD_CONVERSION_RATES['yearly'],\n    )\n\n\nSTANDARD_TIPS = (\n    make_standard_tip(_(\"Symbolic\"), Decimal('0.01')),\n    make_standard_tip(_(\"Small\"), Decimal('0.25')),\n    make_standard_tip(_(\"Medium\"), Decimal('1.00')),\n    make_standard_tip(_(\"Large\"), Decimal('5.00')),\n    make_standard_tip(_(\"Maximum\"), DONATION_WEEKLY_MAX),\n)\n\nSUMMARY_MAX_SIZE = 100\n\nUSERNAME_MAX_SIZE = 32\n\ndel _\n", "path": "liberapay/constants.py"}]}