We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Integrate SASS compilation into development environment
This started in [IRC](https://botbot.me/freenode/gittip/msg/8682409/).

The goal here is to use the same SASS compiler that we use in production, in development. We currently use the standard Ruby version, but that won't quite work for development since we shouldn't require all of Ruby just to run a single tool. So it seems the best course of action is to move to a Python-based SASS compiler.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gittip/wireup.py`
Content:
```
1 """Wireup
2 """
3 from __future__ import absolute_import, division, print_function, unicode_literals
4 import os
5 import sys
6 import threading
7 import time
8 
9 import aspen
10 import balanced
11 import gittip
12 import raven
13 import psycopg2
14 import stripe
15 import gittip.utils.mixpanel
16 from gittip.models.community import Community
17 from gittip.models.participant import Participant
18 from postgres import Postgres
19 
20 
21 def canonical():
22     gittip.canonical_scheme = os.environ['CANONICAL_SCHEME']
23     gittip.canonical_host = os.environ['CANONICAL_HOST']
24 
25 
26 # wireup.db() should only ever be called once by the application
27 def db():
28     dburl = os.environ['DATABASE_URL']
29     maxconn = int(os.environ['DATABASE_MAXCONN'])
30     db = Postgres(dburl, maxconn=maxconn)
31 
32     # register hstore type
33     with db.get_cursor() as cursor:
34         psycopg2.extras.register_hstore(cursor, globally=True, unicode=True)
35 
36     db.register_model(Community)
37     db.register_model(Participant)
38 
39     return db
40 
41 
42 def billing():
43     stripe.api_key= os.environ['STRIPE_SECRET_API_KEY']
44     stripe.publishable_api_key= os.environ['STRIPE_PUBLISHABLE_API_KEY']
45     balanced.configure(os.environ['BALANCED_API_SECRET'])
46 
47 
48 def username_restrictions(website):
49     gittip.RESTRICTED_USERNAMES = os.listdir(website.www_root)
50 
51 
52 def request_metrics(website):
53     def add_start_timestamp(request):
54         request.x_start = time.time()
55     def log_request_count_and_response_time(response):
56         print("count#requests=1")
57         response_time = time.time() - response.request.x_start
58         print("measure#response_time={}ms".format(response_time * 1000))
59     website.hooks.inbound_early.insert(0, add_start_timestamp)
60     website.hooks.outbound += [log_request_count_and_response_time]
61 
62 
63 def sentry(website):
64     if not website.sentry_dsn:
65         aspen.log_dammit("Won't log to Sentry (SENTRY_DSN is empty).")
66         return
67 
68     sentry = raven.Client(website.sentry_dsn)
69 
70     def tell_sentry(request):
71         cls, response = sys.exc_info()[:2]
72 
73 
74         # Decide if we care.
75         # ==================
76 
77         if cls is aspen.Response:
78 
79             if response.code < 500:
80 
81                 # Only log server errors to Sentry. For responses < 500 we use
82                 # stream-/line-based access logging. See discussion on:
83 
84                 # https://github.com/gittip/www.gittip.com/pull/1560.
85 
86                 return
87 
88 
89         # Find a user.
90         # ============
91         # | is disallowed in usernames, so we can use it here to indicate
92         # situations in which we can't get a username.
93 
94         request_context = getattr(request, 'context', None)
95         user = {}
96         user_id = 'n/a'
97         if request_context is None:
98             username = '| no context'
99         else:
100             user = request.context.get('user', None)
101             if user is None:
102                 username = '| no user'
103             else:
104                 is_anon = getattr(user, 'ANON', None)
105                 if is_anon is None:
106                     username = '| no ANON'
107                 elif is_anon:
108                     username = '| anonymous'
109                 else:
110                     participant = getattr(user, 'participant', None)
111                     if participant is None:
112                         username = '| no participant'
113                     else:
114                         username = getattr(user.participant, 'username', None)
115                         if username is None:
116                             username = '| no username'
117                         else:
118                             user_id = user.participant.id
119                             username = username.encode('utf8')
120                             user = { 'id': user_id
121                                    , 'is_admin': user.participant.is_admin
122                                    , 'is_suspicious': user.participant.is_suspicious
123                                    , 'claimed_time': user.participant.claimed_time.isoformat()
124                                    , 'url': 'https://www.gittip.com/{}/'.format(username)
125                                     }
126 
127 
128         # Fire off a Sentry call.
129         # =======================
130 
131         tags = { 'username': username
132                , 'user_id': user_id
133                 }
134         extra = { 'filepath': getattr(request, 'fs', None)
135                 , 'request': str(request).splitlines()
136                 , 'user': user
137                  }
138         result = sentry.captureException(tags=tags, extra=extra)
139 
140 
141         # Emit a reference string to stdout.
142         # ==================================
143 
144         ident = sentry.get_ident(result)
145         aspen.log_dammit('Exception reference: ' + ident)
146 
147 
148     website.hooks.error_early += [tell_sentry]
149     return tell_sentry
150 
151 
152 def mixpanel(website):
153     website.mixpanel_token = os.environ['MIXPANEL_TOKEN']
154     gittip.utils.mixpanel.MIXPANEL_TOKEN = os.environ['MIXPANEL_TOKEN']
155 
156 def nanswers():
157     from gittip.models import participant
158     participant.NANSWERS_THRESHOLD = int(os.environ['NANSWERS_THRESHOLD'])
159 
160 def nmembers(website):
161     from gittip.models import community
162     community.NMEMBERS_THRESHOLD = int(os.environ['NMEMBERS_THRESHOLD'])
163     website.NMEMBERS_THRESHOLD = community.NMEMBERS_THRESHOLD
164 
165 def envvars(website):
166 
167     missing_keys = []
168     malformed_values = []
169 
170     def envvar(key, cast=None):
171         if key not in os.environ:
172             missing_keys.append(key)
173             return ""
174         value = os.environ[key].decode('ASCII')
175         if cast is not None:
176             try:
177                 value = cast(value)
178             except:
179                 err = str(sys.exc_info()[1])
180                 malformed_values.append((key, err))
181                 return ""
182         return value
183 
184     def is_yesish(val):
185         return val.lower() in ('1', 'true', 'yes')
186 
187     website.bitbucket_consumer_key = envvar('BITBUCKET_CONSUMER_KEY')
188     website.bitbucket_consumer_secret = envvar('BITBUCKET_CONSUMER_SECRET')
189     website.bitbucket_callback = envvar('BITBUCKET_CALLBACK')
190 
191     website.github_client_id = envvar('GITHUB_CLIENT_ID')
192     website.github_client_secret = envvar('GITHUB_CLIENT_SECRET')
193     website.github_callback = envvar('GITHUB_CALLBACK')
194 
195     website.twitter_consumer_key = envvar('TWITTER_CONSUMER_KEY')
196     website.twitter_consumer_secret = envvar('TWITTER_CONSUMER_SECRET')
197     website.twitter_access_token = envvar('TWITTER_ACCESS_TOKEN')
198     website.twitter_access_token_secret = envvar('TWITTER_ACCESS_TOKEN_SECRET')
199     website.twitter_callback = envvar('TWITTER_CALLBACK')
200 
201     website.bountysource_www_host = envvar('BOUNTYSOURCE_WWW_HOST')
202     website.bountysource_api_host = envvar('BOUNTYSOURCE_API_HOST')
203     website.bountysource_api_secret = envvar('BOUNTYSOURCE_API_SECRET')
204     website.bountysource_callback = envvar('BOUNTYSOURCE_CALLBACK')
205 
206     website.css_href = envvar('GITTIP_CSS_HREF') \
207                                           .replace('%version', website.version)
208     website.js_src = envvar('GITTIP_JS_SRC') \
209                                           .replace('%version', website.version)
210     website.cache_static = is_yesish(envvar('GITTIP_CACHE_STATIC'))
211 
212     website.google_analytics_id = envvar('GOOGLE_ANALYTICS_ID')
213     website.gauges_id = envvar('GAUGES_ID')
214     website.sentry_dsn = envvar('SENTRY_DSN')
215 
216     website.min_threads = envvar('MIN_THREADS', int)
217     website.log_busy_threads_every = envvar('LOG_BUSY_THREADS_EVERY', int)
218     website.log_metrics = is_yesish(envvar('LOG_METRICS'))
219 
220     if malformed_values:
221         malformed_values.sort()
222         these = len(malformed_values) != 1 and 'these' or 'this'
223         plural = len(malformed_values) != 1 and 's' or ''
224         aspen.log_dammit("=" * 42)
225         aspen.log_dammit( "Oh no! Gittip.com couldn't understand %s " % these
226                         , "environment variable%s:" % plural
227                          )
228         aspen.log_dammit(" ")
229         for key, err in malformed_values:
230             aspen.log_dammit("  {} ({})".format(key, err))
231         aspen.log_dammit(" ")
232         aspen.log_dammit("See ./default_local.env for hints.")
233 
234         aspen.log_dammit("=" * 42)
235         raise SystemExit
236 
237     if missing_keys:
238         missing_keys.sort()
239         these = len(missing_keys) != 1 and 'these' or 'this'
240         plural = len(missing_keys) != 1 and 's' or ''
241         aspen.log_dammit("=" * 42)
242         aspen.log_dammit( "Oh no! Gittip.com needs %s missing " % these
243                         , "environment variable%s:" % plural
244                          )
245         aspen.log_dammit(" ")
246         for key in missing_keys:
247             aspen.log_dammit("  " + key)
248         aspen.log_dammit(" ")
249         aspen.log_dammit( "(Sorry, we must've started looking for "
250                         , "%s since you last updated Gittip!)" % these
251                          )
252         aspen.log_dammit(" ")
253         aspen.log_dammit("Running Gittip locally? Edit ./local.env.")
254         aspen.log_dammit("Running the test suite? Edit ./tests/env.")
255         aspen.log_dammit(" ")
256         aspen.log_dammit("See ./default_local.env for hints.")
257 
258         aspen.log_dammit("=" * 42)
259         raise SystemExit
260
```
--- 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/gittip/wireup.py b/gittip/wireup.py
--- a/gittip/wireup.py
+++ b/gittip/wireup.py
@@ -208,6 +208,7 @@
     website.js_src = envvar('GITTIP_JS_SRC') \
                                           .replace('%version', website.version)
     website.cache_static = is_yesish(envvar('GITTIP_CACHE_STATIC'))
+    website.compress_assets = is_yesish(envvar('GITTIP_COMPRESS_ASSETS'))
 
     website.google_analytics_id = envvar('GOOGLE_ANALYTICS_ID')
     website.gauges_id = envvar('GAUGES_ID')

{"golden_diff": "diff --git a/gittip/wireup.py b/gittip/wireup.py\n--- a/gittip/wireup.py\n+++ b/gittip/wireup.py\n@@ -208,6 +208,7 @@\n     website.js_src = envvar('GITTIP_JS_SRC') \\\n                                           .replace('%version', website.version)\n     website.cache_static = is_yesish(envvar('GITTIP_CACHE_STATIC'))\n+    website.compress_assets = is_yesish(envvar('GITTIP_COMPRESS_ASSETS'))\n \n     website.google_analytics_id = envvar('GOOGLE_ANALYTICS_ID')\n     website.gauges_id = envvar('GAUGES_ID')\n", "issue": "Integrate SASS compilation into development environment\nThis started in [IRC](https://botbot.me/freenode/gittip/msg/8682409/).\n\nThe goal here is to use the same SASS compiler that we use in production, in development. We currently use the standard Ruby version, but that won't quite work for development since we shouldn't require all of Ruby just to run a single tool. So it seems the best course of action is to move to a Python-based SASS compiler.\n\n", "before_files": [{"content": "\"\"\"Wireup\n\"\"\"\nfrom __future__ import absolute_import, division, print_function, unicode_literals\nimport os\nimport sys\nimport threading\nimport time\n\nimport aspen\nimport balanced\nimport gittip\nimport raven\nimport psycopg2\nimport stripe\nimport gittip.utils.mixpanel\nfrom gittip.models.community import Community\nfrom gittip.models.participant import Participant\nfrom postgres import Postgres\n\n\ndef canonical():\n    gittip.canonical_scheme = os.environ['CANONICAL_SCHEME']\n    gittip.canonical_host = os.environ['CANONICAL_HOST']\n\n\n# wireup.db() should only ever be called once by the application\ndef db():\n    dburl = os.environ['DATABASE_URL']\n    maxconn = int(os.environ['DATABASE_MAXCONN'])\n    db = Postgres(dburl, maxconn=maxconn)\n\n    # register hstore type\n    with db.get_cursor() as cursor:\n        psycopg2.extras.register_hstore(cursor, globally=True, unicode=True)\n\n    db.register_model(Community)\n    db.register_model(Participant)\n\n    return db\n\n\ndef billing():\n    stripe.api_key= os.environ['STRIPE_SECRET_API_KEY']\n    stripe.publishable_api_key= os.environ['STRIPE_PUBLISHABLE_API_KEY']\n    balanced.configure(os.environ['BALANCED_API_SECRET'])\n\n\ndef username_restrictions(website):\n    gittip.RESTRICTED_USERNAMES = os.listdir(website.www_root)\n\n\ndef request_metrics(website):\n    def add_start_timestamp(request):\n        request.x_start = time.time()\n    def log_request_count_and_response_time(response):\n        print(\"count#requests=1\")\n        response_time = time.time() - response.request.x_start\n        print(\"measure#response_time={}ms\".format(response_time * 1000))\n    website.hooks.inbound_early.insert(0, add_start_timestamp)\n    website.hooks.outbound += [log_request_count_and_response_time]\n\n\ndef sentry(website):\n    if not website.sentry_dsn:\n        aspen.log_dammit(\"Won't log to Sentry (SENTRY_DSN is empty).\")\n        return\n\n    sentry = raven.Client(website.sentry_dsn)\n\n    def tell_sentry(request):\n        cls, response = sys.exc_info()[:2]\n\n\n        # Decide if we care.\n        # ==================\n\n        if cls is aspen.Response:\n\n            if response.code < 500:\n\n                # Only log server errors to Sentry. For responses < 500 we use\n                # stream-/line-based access logging. See discussion on:\n\n                # https://github.com/gittip/www.gittip.com/pull/1560.\n\n                return\n\n\n        # Find a user.\n        # ============\n        # | is disallowed in usernames, so we can use it here to indicate\n        # situations in which we can't get a username.\n\n        request_context = getattr(request, 'context', None)\n        user = {}\n        user_id = 'n/a'\n        if request_context is None:\n            username = '| no context'\n        else:\n            user = request.context.get('user', None)\n            if user is None:\n                username = '| no user'\n            else:\n                is_anon = getattr(user, 'ANON', None)\n                if is_anon is None:\n                    username = '| no ANON'\n                elif is_anon:\n                    username = '| anonymous'\n                else:\n                    participant = getattr(user, 'participant', None)\n                    if participant is None:\n                        username = '| no participant'\n                    else:\n                        username = getattr(user.participant, 'username', None)\n                        if username is None:\n                            username = '| no username'\n                        else:\n                            user_id = user.participant.id\n                            username = username.encode('utf8')\n                            user = { 'id': user_id\n                                   , 'is_admin': user.participant.is_admin\n                                   , 'is_suspicious': user.participant.is_suspicious\n                                   , 'claimed_time': user.participant.claimed_time.isoformat()\n                                   , 'url': 'https://www.gittip.com/{}/'.format(username)\n                                    }\n\n\n        # Fire off a Sentry call.\n        # =======================\n\n        tags = { 'username': username\n               , 'user_id': user_id\n                }\n        extra = { 'filepath': getattr(request, 'fs', None)\n                , 'request': str(request).splitlines()\n                , 'user': user\n                 }\n        result = sentry.captureException(tags=tags, extra=extra)\n\n\n        # Emit a reference string to stdout.\n        # ==================================\n\n        ident = sentry.get_ident(result)\n        aspen.log_dammit('Exception reference: ' + ident)\n\n\n    website.hooks.error_early += [tell_sentry]\n    return tell_sentry\n\n\ndef mixpanel(website):\n    website.mixpanel_token = os.environ['MIXPANEL_TOKEN']\n    gittip.utils.mixpanel.MIXPANEL_TOKEN = os.environ['MIXPANEL_TOKEN']\n\ndef nanswers():\n    from gittip.models import participant\n    participant.NANSWERS_THRESHOLD = int(os.environ['NANSWERS_THRESHOLD'])\n\ndef nmembers(website):\n    from gittip.models import community\n    community.NMEMBERS_THRESHOLD = int(os.environ['NMEMBERS_THRESHOLD'])\n    website.NMEMBERS_THRESHOLD = community.NMEMBERS_THRESHOLD\n\ndef envvars(website):\n\n    missing_keys = []\n    malformed_values = []\n\n    def envvar(key, cast=None):\n        if key not in os.environ:\n            missing_keys.append(key)\n            return \"\"\n        value = os.environ[key].decode('ASCII')\n        if cast is not None:\n            try:\n                value = cast(value)\n            except:\n                err = str(sys.exc_info()[1])\n                malformed_values.append((key, err))\n                return \"\"\n        return value\n\n    def is_yesish(val):\n        return val.lower() in ('1', 'true', 'yes')\n\n    website.bitbucket_consumer_key = envvar('BITBUCKET_CONSUMER_KEY')\n    website.bitbucket_consumer_secret = envvar('BITBUCKET_CONSUMER_SECRET')\n    website.bitbucket_callback = envvar('BITBUCKET_CALLBACK')\n\n    website.github_client_id = envvar('GITHUB_CLIENT_ID')\n    website.github_client_secret = envvar('GITHUB_CLIENT_SECRET')\n    website.github_callback = envvar('GITHUB_CALLBACK')\n\n    website.twitter_consumer_key = envvar('TWITTER_CONSUMER_KEY')\n    website.twitter_consumer_secret = envvar('TWITTER_CONSUMER_SECRET')\n    website.twitter_access_token = envvar('TWITTER_ACCESS_TOKEN')\n    website.twitter_access_token_secret = envvar('TWITTER_ACCESS_TOKEN_SECRET')\n    website.twitter_callback = envvar('TWITTER_CALLBACK')\n\n    website.bountysource_www_host = envvar('BOUNTYSOURCE_WWW_HOST')\n    website.bountysource_api_host = envvar('BOUNTYSOURCE_API_HOST')\n    website.bountysource_api_secret = envvar('BOUNTYSOURCE_API_SECRET')\n    website.bountysource_callback = envvar('BOUNTYSOURCE_CALLBACK')\n\n    website.css_href = envvar('GITTIP_CSS_HREF') \\\n                                          .replace('%version', website.version)\n    website.js_src = envvar('GITTIP_JS_SRC') \\\n                                          .replace('%version', website.version)\n    website.cache_static = is_yesish(envvar('GITTIP_CACHE_STATIC'))\n\n    website.google_analytics_id = envvar('GOOGLE_ANALYTICS_ID')\n    website.gauges_id = envvar('GAUGES_ID')\n    website.sentry_dsn = envvar('SENTRY_DSN')\n\n    website.min_threads = envvar('MIN_THREADS', int)\n    website.log_busy_threads_every = envvar('LOG_BUSY_THREADS_EVERY', int)\n    website.log_metrics = is_yesish(envvar('LOG_METRICS'))\n\n    if malformed_values:\n        malformed_values.sort()\n        these = len(malformed_values) != 1 and 'these' or 'this'\n        plural = len(malformed_values) != 1 and 's' or ''\n        aspen.log_dammit(\"=\" * 42)\n        aspen.log_dammit( \"Oh no! Gittip.com couldn't understand %s \" % these\n                        , \"environment variable%s:\" % plural\n                         )\n        aspen.log_dammit(\" \")\n        for key, err in malformed_values:\n            aspen.log_dammit(\"  {} ({})\".format(key, err))\n        aspen.log_dammit(\" \")\n        aspen.log_dammit(\"See ./default_local.env for hints.\")\n\n        aspen.log_dammit(\"=\" * 42)\n        raise SystemExit\n\n    if missing_keys:\n        missing_keys.sort()\n        these = len(missing_keys) != 1 and 'these' or 'this'\n        plural = len(missing_keys) != 1 and 's' or ''\n        aspen.log_dammit(\"=\" * 42)\n        aspen.log_dammit( \"Oh no! Gittip.com needs %s missing \" % these\n                        , \"environment variable%s:\" % plural\n                         )\n        aspen.log_dammit(\" \")\n        for key in missing_keys:\n            aspen.log_dammit(\"  \" + key)\n        aspen.log_dammit(\" \")\n        aspen.log_dammit( \"(Sorry, we must've started looking for \"\n                        , \"%s since you last updated Gittip!)\" % these\n                         )\n        aspen.log_dammit(\" \")\n        aspen.log_dammit(\"Running Gittip locally? Edit ./local.env.\")\n        aspen.log_dammit(\"Running the test suite? Edit ./tests/env.\")\n        aspen.log_dammit(\" \")\n        aspen.log_dammit(\"See ./default_local.env for hints.\")\n\n        aspen.log_dammit(\"=\" * 42)\n        raise SystemExit\n", "path": "gittip/wireup.py"}], "after_files": [{"content": "\"\"\"Wireup\n\"\"\"\nfrom __future__ import absolute_import, division, print_function, unicode_literals\nimport os\nimport sys\nimport threading\nimport time\n\nimport aspen\nimport balanced\nimport gittip\nimport raven\nimport psycopg2\nimport stripe\nimport gittip.utils.mixpanel\nfrom gittip.models.community import Community\nfrom gittip.models.participant import Participant\nfrom postgres import Postgres\n\n\ndef canonical():\n    gittip.canonical_scheme = os.environ['CANONICAL_SCHEME']\n    gittip.canonical_host = os.environ['CANONICAL_HOST']\n\n\n# wireup.db() should only ever be called once by the application\ndef db():\n    dburl = os.environ['DATABASE_URL']\n    maxconn = int(os.environ['DATABASE_MAXCONN'])\n    db = Postgres(dburl, maxconn=maxconn)\n\n    # register hstore type\n    with db.get_cursor() as cursor:\n        psycopg2.extras.register_hstore(cursor, globally=True, unicode=True)\n\n    db.register_model(Community)\n    db.register_model(Participant)\n\n    return db\n\n\ndef billing():\n    stripe.api_key= os.environ['STRIPE_SECRET_API_KEY']\n    stripe.publishable_api_key= os.environ['STRIPE_PUBLISHABLE_API_KEY']\n    balanced.configure(os.environ['BALANCED_API_SECRET'])\n\n\ndef username_restrictions(website):\n    gittip.RESTRICTED_USERNAMES = os.listdir(website.www_root)\n\n\ndef request_metrics(website):\n    def add_start_timestamp(request):\n        request.x_start = time.time()\n    def log_request_count_and_response_time(response):\n        print(\"count#requests=1\")\n        response_time = time.time() - response.request.x_start\n        print(\"measure#response_time={}ms\".format(response_time * 1000))\n    website.hooks.inbound_early.insert(0, add_start_timestamp)\n    website.hooks.outbound += [log_request_count_and_response_time]\n\n\ndef sentry(website):\n    if not website.sentry_dsn:\n        aspen.log_dammit(\"Won't log to Sentry (SENTRY_DSN is empty).\")\n        return\n\n    sentry = raven.Client(website.sentry_dsn)\n\n    def tell_sentry(request):\n        cls, response = sys.exc_info()[:2]\n\n\n        # Decide if we care.\n        # ==================\n\n        if cls is aspen.Response:\n\n            if response.code < 500:\n\n                # Only log server errors to Sentry. For responses < 500 we use\n                # stream-/line-based access logging. See discussion on:\n\n                # https://github.com/gittip/www.gittip.com/pull/1560.\n\n                return\n\n\n        # Find a user.\n        # ============\n        # | is disallowed in usernames, so we can use it here to indicate\n        # situations in which we can't get a username.\n\n        request_context = getattr(request, 'context', None)\n        user = {}\n        user_id = 'n/a'\n        if request_context is None:\n            username = '| no context'\n        else:\n            user = request.context.get('user', None)\n            if user is None:\n                username = '| no user'\n            else:\n                is_anon = getattr(user, 'ANON', None)\n                if is_anon is None:\n                    username = '| no ANON'\n                elif is_anon:\n                    username = '| anonymous'\n                else:\n                    participant = getattr(user, 'participant', None)\n                    if participant is None:\n                        username = '| no participant'\n                    else:\n                        username = getattr(user.participant, 'username', None)\n                        if username is None:\n                            username = '| no username'\n                        else:\n                            user_id = user.participant.id\n                            username = username.encode('utf8')\n                            user = { 'id': user_id\n                                   , 'is_admin': user.participant.is_admin\n                                   , 'is_suspicious': user.participant.is_suspicious\n                                   , 'claimed_time': user.participant.claimed_time.isoformat()\n                                   , 'url': 'https://www.gittip.com/{}/'.format(username)\n                                    }\n\n\n        # Fire off a Sentry call.\n        # =======================\n\n        tags = { 'username': username\n               , 'user_id': user_id\n                }\n        extra = { 'filepath': getattr(request, 'fs', None)\n                , 'request': str(request).splitlines()\n                , 'user': user\n                 }\n        result = sentry.captureException(tags=tags, extra=extra)\n\n\n        # Emit a reference string to stdout.\n        # ==================================\n\n        ident = sentry.get_ident(result)\n        aspen.log_dammit('Exception reference: ' + ident)\n\n\n    website.hooks.error_early += [tell_sentry]\n    return tell_sentry\n\n\ndef mixpanel(website):\n    website.mixpanel_token = os.environ['MIXPANEL_TOKEN']\n    gittip.utils.mixpanel.MIXPANEL_TOKEN = os.environ['MIXPANEL_TOKEN']\n\ndef nanswers():\n    from gittip.models import participant\n    participant.NANSWERS_THRESHOLD = int(os.environ['NANSWERS_THRESHOLD'])\n\ndef nmembers(website):\n    from gittip.models import community\n    community.NMEMBERS_THRESHOLD = int(os.environ['NMEMBERS_THRESHOLD'])\n    website.NMEMBERS_THRESHOLD = community.NMEMBERS_THRESHOLD\n\ndef envvars(website):\n\n    missing_keys = []\n    malformed_values = []\n\n    def envvar(key, cast=None):\n        if key not in os.environ:\n            missing_keys.append(key)\n            return \"\"\n        value = os.environ[key].decode('ASCII')\n        if cast is not None:\n            try:\n                value = cast(value)\n            except:\n                err = str(sys.exc_info()[1])\n                malformed_values.append((key, err))\n                return \"\"\n        return value\n\n    def is_yesish(val):\n        return val.lower() in ('1', 'true', 'yes')\n\n    website.bitbucket_consumer_key = envvar('BITBUCKET_CONSUMER_KEY')\n    website.bitbucket_consumer_secret = envvar('BITBUCKET_CONSUMER_SECRET')\n    website.bitbucket_callback = envvar('BITBUCKET_CALLBACK')\n\n    website.github_client_id = envvar('GITHUB_CLIENT_ID')\n    website.github_client_secret = envvar('GITHUB_CLIENT_SECRET')\n    website.github_callback = envvar('GITHUB_CALLBACK')\n\n    website.twitter_consumer_key = envvar('TWITTER_CONSUMER_KEY')\n    website.twitter_consumer_secret = envvar('TWITTER_CONSUMER_SECRET')\n    website.twitter_access_token = envvar('TWITTER_ACCESS_TOKEN')\n    website.twitter_access_token_secret = envvar('TWITTER_ACCESS_TOKEN_SECRET')\n    website.twitter_callback = envvar('TWITTER_CALLBACK')\n\n    website.bountysource_www_host = envvar('BOUNTYSOURCE_WWW_HOST')\n    website.bountysource_api_host = envvar('BOUNTYSOURCE_API_HOST')\n    website.bountysource_api_secret = envvar('BOUNTYSOURCE_API_SECRET')\n    website.bountysource_callback = envvar('BOUNTYSOURCE_CALLBACK')\n\n    website.css_href = envvar('GITTIP_CSS_HREF') \\\n                                          .replace('%version', website.version)\n    website.js_src = envvar('GITTIP_JS_SRC') \\\n                                          .replace('%version', website.version)\n    website.cache_static = is_yesish(envvar('GITTIP_CACHE_STATIC'))\n    website.compress_assets = is_yesish(envvar('GITTIP_COMPRESS_ASSETS'))\n\n    website.google_analytics_id = envvar('GOOGLE_ANALYTICS_ID')\n    website.gauges_id = envvar('GAUGES_ID')\n    website.sentry_dsn = envvar('SENTRY_DSN')\n\n    website.min_threads = envvar('MIN_THREADS', int)\n    website.log_busy_threads_every = envvar('LOG_BUSY_THREADS_EVERY', int)\n    website.log_metrics = is_yesish(envvar('LOG_METRICS'))\n\n    if malformed_values:\n        malformed_values.sort()\n        these = len(malformed_values) != 1 and 'these' or 'this'\n        plural = len(malformed_values) != 1 and 's' or ''\n        aspen.log_dammit(\"=\" * 42)\n        aspen.log_dammit( \"Oh no! Gittip.com couldn't understand %s \" % these\n                        , \"environment variable%s:\" % plural\n                         )\n        aspen.log_dammit(\" \")\n        for key, err in malformed_values:\n            aspen.log_dammit(\"  {} ({})\".format(key, err))\n        aspen.log_dammit(\" \")\n        aspen.log_dammit(\"See ./default_local.env for hints.\")\n\n        aspen.log_dammit(\"=\" * 42)\n        raise SystemExit\n\n    if missing_keys:\n        missing_keys.sort()\n        these = len(missing_keys) != 1 and 'these' or 'this'\n        plural = len(missing_keys) != 1 and 's' or ''\n        aspen.log_dammit(\"=\" * 42)\n        aspen.log_dammit( \"Oh no! Gittip.com needs %s missing \" % these\n                        , \"environment variable%s:\" % plural\n                         )\n        aspen.log_dammit(\" \")\n        for key in missing_keys:\n            aspen.log_dammit(\"  \" + key)\n        aspen.log_dammit(\" \")\n        aspen.log_dammit( \"(Sorry, we must've started looking for \"\n                        , \"%s since you last updated Gittip!)\" % these\n                         )\n        aspen.log_dammit(\" \")\n        aspen.log_dammit(\"Running Gittip locally? Edit ./local.env.\")\n        aspen.log_dammit(\"Running the test suite? Edit ./tests/env.\")\n        aspen.log_dammit(\" \")\n        aspen.log_dammit(\"See ./default_local.env for hints.\")\n\n        aspen.log_dammit(\"=\" * 42)\n        raise SystemExit\n", "path": "gittip/wireup.py"}]}