We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
PrefixRedirectUrl redirect `/hub` to `/hub/hub`
It might be an edge case, which is not really important, 
but I expected `/hub` -> `/hub/` and not `/hub/hub`. This is to to `uri.startswith(self.base_url)`, and `base_url` is guarantied to end with a `/`. Now of course we can't just strip the trailing slash from `base_url` or things like `/hubot` will not be redirected to `/hub/hubot`, and doing nothing may be the right answer. 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `jupyterhub/handlers/pages.py`
Content:
```
1 """Basic html-rendering handlers."""
2 
3 # Copyright (c) Jupyter Development Team.
4 # Distributed under the terms of the Modified BSD License.
5 
6 from http.client import responses
7 
8 from jinja2 import TemplateNotFound
9 from tornado import web, gen
10 from tornado.httputil import url_concat
11 
12 from .. import orm
13 from ..utils import admin_only, url_path_join
14 from .base import BaseHandler
15 
16 
17 class RootHandler(BaseHandler):
18     """Render the Hub root page.
19 
20     If next argument is passed by single-user server,
21     redirect to base_url + single-user page.
22 
23     If logged in, redirects to:
24 
25     - single-user server if running
26     - hub home, otherwise
27 
28     Otherwise, renders login page.
29     """
30     def get(self):
31         next_url = self.get_argument('next', '')
32         if next_url and not next_url.startswith('/'):
33             self.log.warning("Disallowing redirect outside JupyterHub: %r", next_url)
34             next_url = ''
35         if next_url and next_url.startswith(url_path_join(self.base_url, 'user/')):
36             # add /hub/ prefix, to ensure we redirect to the right user's server.
37             # The next request will be handled by UserSpawnHandler,
38             # ultimately redirecting to the logged-in user's server.
39             without_prefix = next_url[len(self.base_url):]
40             next_url = url_path_join(self.hub.base_url, without_prefix)
41             self.log.warning("Redirecting %s to %s. For sharing public links, use /user-redirect/",
42                 self.request.uri, next_url,
43             )
44             self.redirect(next_url)
45             return
46         user = self.get_current_user()
47         if user:
48             if user.running:
49                 url = user.url
50                 self.log.debug("User is running: %s", url)
51                 self.set_login_cookie(user) # set cookie
52             else:
53                 url = url_path_join(self.hub.base_url, 'home')
54                 self.log.debug("User is not running: %s", url)
55         else:
56             url = self.settings['login_url']
57         self.redirect(url)
58 
59 
60 class HomeHandler(BaseHandler):
61     """Render the user's home page."""
62 
63     @web.authenticated
64     @gen.coroutine
65     def get(self):
66         user = self.get_current_user()
67         if user.running:
68             # trigger poll_and_notify event in case of a server that died
69             yield user.spawner.poll_and_notify()
70         html = self.render_template('home.html',
71             user=user,
72             url=user.url,
73         )
74         self.finish(html)
75 
76 
77 class SpawnHandler(BaseHandler):
78     """Handle spawning of single-user servers via form.
79 
80     GET renders the form, POST handles form submission.
81 
82     Only enabled when Spawner.options_form is defined.
83     """
84     def _render_form(self, message=''):
85         user = self.get_current_user()
86         return self.render_template('spawn.html',
87             user=user,
88             spawner_options_form=user.spawner.options_form,
89             error_message=message,
90             url=self.request.uri,
91         )
92 
93     @web.authenticated
94     def get(self):
95         """GET renders form for spawning with user-specified options"""
96         user = self.get_current_user()
97         if not self.allow_named_servers and user.running:
98             url = user.url
99             self.log.debug("User is running: %s", url)
100             self.redirect(url)
101             return
102         if user.spawner.options_form:
103             self.finish(self._render_form())
104         else:
105             # not running, no form. Trigger spawn.
106             self.redirect(user.url)
107 
108     @web.authenticated
109     @gen.coroutine
110     def post(self):
111         """POST spawns with user-specified options"""
112         user = self.get_current_user()
113         if not self.allow_named_servers and user.running:
114             url = user.url
115             self.log.warning("User is already running: %s", url)
116             self.redirect(url)
117             return
118         form_options = {}
119         for key, byte_list in self.request.body_arguments.items():
120             form_options[key] = [ bs.decode('utf8') for bs in byte_list ]
121         for key, byte_list in self.request.files.items():
122             form_options["%s_file"%key] = byte_list
123         try:
124             options = user.spawner.options_from_form(form_options)
125             yield self.spawn_single_user(user, options=options)
126         except Exception as e:
127             self.log.error("Failed to spawn single-user server with form", exc_info=True)
128             self.finish(self._render_form(str(e)))
129             return
130         self.set_login_cookie(user)
131         url = user.url
132 
133         next_url = self.get_argument('next', '')
134         if next_url and not next_url.startswith('/'):
135             self.log.warning("Disallowing redirect outside JupyterHub: %r", next_url)
136         elif next_url:
137             url = next_url
138 
139         self.redirect(url)
140 
141 class AdminHandler(BaseHandler):
142     """Render the admin page."""
143 
144     @admin_only
145     def get(self):
146         available = {'name', 'admin', 'running', 'last_activity'}
147         default_sort = ['admin', 'name']
148         mapping = {
149             'running': '_server_id'
150         }
151         default_order = {
152             'name': 'asc',
153             'last_activity': 'desc',
154             'admin': 'desc',
155             'running': 'desc',
156         }
157         sorts = self.get_arguments('sort') or default_sort
158         orders = self.get_arguments('order')
159 
160         for bad in set(sorts).difference(available):
161             self.log.warning("ignoring invalid sort: %r", bad)
162             sorts.remove(bad)
163         for bad in set(orders).difference({'asc', 'desc'}):
164             self.log.warning("ignoring invalid order: %r", bad)
165             orders.remove(bad)
166 
167         # add default sort as secondary
168         for s in default_sort:
169             if s not in sorts:
170                 sorts.append(s)
171         if len(orders) < len(sorts):
172             for col in sorts[len(orders):]:
173                 orders.append(default_order[col])
174         else:
175             orders = orders[:len(sorts)]
176 
177         # this could be one incomprehensible nested list comprehension
178         # get User columns
179         cols = [ getattr(orm.User, mapping.get(c, c)) for c in sorts ]
180         # get User.col.desc() order objects
181         ordered = [ getattr(c, o)() for c, o in zip(cols, orders) ]
182 
183         users = self.db.query(orm.User).order_by(*ordered)
184         users = [ self._user_from_orm(u) for u in users ]
185         running = [ u for u in users if u.running ]
186 
187         html = self.render_template('admin.html',
188             user=self.get_current_user(),
189             admin_access=self.settings.get('admin_access', False),
190             users=users,
191             running=running,
192             sort={s:o for s,o in zip(sorts, orders)},
193         )
194         self.finish(html)
195 
196 
197 class TokenPageHandler(BaseHandler):
198     """Handler for page requesting new API tokens"""
199 
200     @web.authenticated
201     def get(self):
202         html = self.render_template('token.html')
203         self.finish(html)
204 
205 
206 class ProxyErrorHandler(BaseHandler):
207     """Handler for rendering proxy error pages"""
208     
209     def get(self, status_code_s):
210         status_code = int(status_code_s)
211         status_message = responses.get(status_code, 'Unknown HTTP Error')
212         # build template namespace
213         
214         hub_home = url_path_join(self.hub.base_url, 'home')
215         message_html = ''
216         if status_code == 503:
217             message_html = ' '.join([
218                 "Your server appears to be down.",
219                 "Try restarting it <a href='%s'>from the hub</a>" % hub_home
220             ])
221         ns = dict(
222             status_code=status_code,
223             status_message=status_message,
224             message_html=message_html,
225             logo_url=hub_home,
226         )
227 
228         self.set_header('Content-Type', 'text/html')
229         # render the template
230         try:
231             html = self.render_template('%s.html' % status_code, **ns)
232         except TemplateNotFound:
233             self.log.debug("No template for %d", status_code)
234             html = self.render_template('error.html', **ns)
235 
236         self.write(html)
237 
238 
239 default_handlers = [
240     (r'/', RootHandler),
241     (r'/home', HomeHandler),
242     (r'/admin', AdminHandler),
243     (r'/spawn', SpawnHandler),
244     (r'/token', TokenPageHandler),
245     (r'/error/(\d+)', ProxyErrorHandler),
246 ]
247
```
--- 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/jupyterhub/handlers/pages.py b/jupyterhub/handlers/pages.py
--- a/jupyterhub/handlers/pages.py
+++ b/jupyterhub/handlers/pages.py
@@ -237,7 +237,7 @@
 
 
 default_handlers = [
-    (r'/', RootHandler),
+    (r'/?', RootHandler),
     (r'/home', HomeHandler),
     (r'/admin', AdminHandler),
     (r'/spawn', SpawnHandler),

{"golden_diff": "diff --git a/jupyterhub/handlers/pages.py b/jupyterhub/handlers/pages.py\n--- a/jupyterhub/handlers/pages.py\n+++ b/jupyterhub/handlers/pages.py\n@@ -237,7 +237,7 @@\n \n \n default_handlers = [\n-    (r'/', RootHandler),\n+    (r'/?', RootHandler),\n     (r'/home', HomeHandler),\n     (r'/admin', AdminHandler),\n     (r'/spawn', SpawnHandler),\n", "issue": "PrefixRedirectUrl redirect `/hub` to `/hub/hub`\nIt might be an edge case, which is not really important, \r\nbut I expected `/hub` -> `/hub/` and not `/hub/hub`. This is to to `uri.startswith(self.base_url)`, and `base_url` is guarantied to end with a `/`. Now of course we can't just strip the trailing slash from `base_url` or things like `/hubot` will not be redirected to `/hub/hubot`, and doing nothing may be the right answer. \n", "before_files": [{"content": "\"\"\"Basic html-rendering handlers.\"\"\"\n\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nfrom http.client import responses\n\nfrom jinja2 import TemplateNotFound\nfrom tornado import web, gen\nfrom tornado.httputil import url_concat\n\nfrom .. import orm\nfrom ..utils import admin_only, url_path_join\nfrom .base import BaseHandler\n\n\nclass RootHandler(BaseHandler):\n    \"\"\"Render the Hub root page.\n\n    If next argument is passed by single-user server,\n    redirect to base_url + single-user page.\n\n    If logged in, redirects to:\n\n    - single-user server if running\n    - hub home, otherwise\n\n    Otherwise, renders login page.\n    \"\"\"\n    def get(self):\n        next_url = self.get_argument('next', '')\n        if next_url and not next_url.startswith('/'):\n            self.log.warning(\"Disallowing redirect outside JupyterHub: %r\", next_url)\n            next_url = ''\n        if next_url and next_url.startswith(url_path_join(self.base_url, 'user/')):\n            # add /hub/ prefix, to ensure we redirect to the right user's server.\n            # The next request will be handled by UserSpawnHandler,\n            # ultimately redirecting to the logged-in user's server.\n            without_prefix = next_url[len(self.base_url):]\n            next_url = url_path_join(self.hub.base_url, without_prefix)\n            self.log.warning(\"Redirecting %s to %s. For sharing public links, use /user-redirect/\",\n                self.request.uri, next_url,\n            )\n            self.redirect(next_url)\n            return\n        user = self.get_current_user()\n        if user:\n            if user.running:\n                url = user.url\n                self.log.debug(\"User is running: %s\", url)\n                self.set_login_cookie(user) # set cookie\n            else:\n                url = url_path_join(self.hub.base_url, 'home')\n                self.log.debug(\"User is not running: %s\", url)\n        else:\n            url = self.settings['login_url']\n        self.redirect(url)\n\n\nclass HomeHandler(BaseHandler):\n    \"\"\"Render the user's home page.\"\"\"\n\n    @web.authenticated\n    @gen.coroutine\n    def get(self):\n        user = self.get_current_user()\n        if user.running:\n            # trigger poll_and_notify event in case of a server that died\n            yield user.spawner.poll_and_notify()\n        html = self.render_template('home.html',\n            user=user,\n            url=user.url,\n        )\n        self.finish(html)\n\n\nclass SpawnHandler(BaseHandler):\n    \"\"\"Handle spawning of single-user servers via form.\n\n    GET renders the form, POST handles form submission.\n\n    Only enabled when Spawner.options_form is defined.\n    \"\"\"\n    def _render_form(self, message=''):\n        user = self.get_current_user()\n        return self.render_template('spawn.html',\n            user=user,\n            spawner_options_form=user.spawner.options_form,\n            error_message=message,\n            url=self.request.uri,\n        )\n\n    @web.authenticated\n    def get(self):\n        \"\"\"GET renders form for spawning with user-specified options\"\"\"\n        user = self.get_current_user()\n        if not self.allow_named_servers and user.running:\n            url = user.url\n            self.log.debug(\"User is running: %s\", url)\n            self.redirect(url)\n            return\n        if user.spawner.options_form:\n            self.finish(self._render_form())\n        else:\n            # not running, no form. Trigger spawn.\n            self.redirect(user.url)\n\n    @web.authenticated\n    @gen.coroutine\n    def post(self):\n        \"\"\"POST spawns with user-specified options\"\"\"\n        user = self.get_current_user()\n        if not self.allow_named_servers and user.running:\n            url = user.url\n            self.log.warning(\"User is already running: %s\", url)\n            self.redirect(url)\n            return\n        form_options = {}\n        for key, byte_list in self.request.body_arguments.items():\n            form_options[key] = [ bs.decode('utf8') for bs in byte_list ]\n        for key, byte_list in self.request.files.items():\n            form_options[\"%s_file\"%key] = byte_list\n        try:\n            options = user.spawner.options_from_form(form_options)\n            yield self.spawn_single_user(user, options=options)\n        except Exception as e:\n            self.log.error(\"Failed to spawn single-user server with form\", exc_info=True)\n            self.finish(self._render_form(str(e)))\n            return\n        self.set_login_cookie(user)\n        url = user.url\n\n        next_url = self.get_argument('next', '')\n        if next_url and not next_url.startswith('/'):\n            self.log.warning(\"Disallowing redirect outside JupyterHub: %r\", next_url)\n        elif next_url:\n            url = next_url\n\n        self.redirect(url)\n\nclass AdminHandler(BaseHandler):\n    \"\"\"Render the admin page.\"\"\"\n\n    @admin_only\n    def get(self):\n        available = {'name', 'admin', 'running', 'last_activity'}\n        default_sort = ['admin', 'name']\n        mapping = {\n            'running': '_server_id'\n        }\n        default_order = {\n            'name': 'asc',\n            'last_activity': 'desc',\n            'admin': 'desc',\n            'running': 'desc',\n        }\n        sorts = self.get_arguments('sort') or default_sort\n        orders = self.get_arguments('order')\n\n        for bad in set(sorts).difference(available):\n            self.log.warning(\"ignoring invalid sort: %r\", bad)\n            sorts.remove(bad)\n        for bad in set(orders).difference({'asc', 'desc'}):\n            self.log.warning(\"ignoring invalid order: %r\", bad)\n            orders.remove(bad)\n\n        # add default sort as secondary\n        for s in default_sort:\n            if s not in sorts:\n                sorts.append(s)\n        if len(orders) < len(sorts):\n            for col in sorts[len(orders):]:\n                orders.append(default_order[col])\n        else:\n            orders = orders[:len(sorts)]\n\n        # this could be one incomprehensible nested list comprehension\n        # get User columns\n        cols = [ getattr(orm.User, mapping.get(c, c)) for c in sorts ]\n        # get User.col.desc() order objects\n        ordered = [ getattr(c, o)() for c, o in zip(cols, orders) ]\n\n        users = self.db.query(orm.User).order_by(*ordered)\n        users = [ self._user_from_orm(u) for u in users ]\n        running = [ u for u in users if u.running ]\n\n        html = self.render_template('admin.html',\n            user=self.get_current_user(),\n            admin_access=self.settings.get('admin_access', False),\n            users=users,\n            running=running,\n            sort={s:o for s,o in zip(sorts, orders)},\n        )\n        self.finish(html)\n\n\nclass TokenPageHandler(BaseHandler):\n    \"\"\"Handler for page requesting new API tokens\"\"\"\n\n    @web.authenticated\n    def get(self):\n        html = self.render_template('token.html')\n        self.finish(html)\n\n\nclass ProxyErrorHandler(BaseHandler):\n    \"\"\"Handler for rendering proxy error pages\"\"\"\n    \n    def get(self, status_code_s):\n        status_code = int(status_code_s)\n        status_message = responses.get(status_code, 'Unknown HTTP Error')\n        # build template namespace\n        \n        hub_home = url_path_join(self.hub.base_url, 'home')\n        message_html = ''\n        if status_code == 503:\n            message_html = ' '.join([\n                \"Your server appears to be down.\",\n                \"Try restarting it <a href='%s'>from the hub</a>\" % hub_home\n            ])\n        ns = dict(\n            status_code=status_code,\n            status_message=status_message,\n            message_html=message_html,\n            logo_url=hub_home,\n        )\n\n        self.set_header('Content-Type', 'text/html')\n        # render the template\n        try:\n            html = self.render_template('%s.html' % status_code, **ns)\n        except TemplateNotFound:\n            self.log.debug(\"No template for %d\", status_code)\n            html = self.render_template('error.html', **ns)\n\n        self.write(html)\n\n\ndefault_handlers = [\n    (r'/', RootHandler),\n    (r'/home', HomeHandler),\n    (r'/admin', AdminHandler),\n    (r'/spawn', SpawnHandler),\n    (r'/token', TokenPageHandler),\n    (r'/error/(\\d+)', ProxyErrorHandler),\n]\n", "path": "jupyterhub/handlers/pages.py"}], "after_files": [{"content": "\"\"\"Basic html-rendering handlers.\"\"\"\n\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nfrom http.client import responses\n\nfrom jinja2 import TemplateNotFound\nfrom tornado import web, gen\nfrom tornado.httputil import url_concat\n\nfrom .. import orm\nfrom ..utils import admin_only, url_path_join\nfrom .base import BaseHandler\n\n\nclass RootHandler(BaseHandler):\n    \"\"\"Render the Hub root page.\n\n    If next argument is passed by single-user server,\n    redirect to base_url + single-user page.\n\n    If logged in, redirects to:\n\n    - single-user server if running\n    - hub home, otherwise\n\n    Otherwise, renders login page.\n    \"\"\"\n    def get(self):\n        next_url = self.get_argument('next', '')\n        if next_url and not next_url.startswith('/'):\n            self.log.warning(\"Disallowing redirect outside JupyterHub: %r\", next_url)\n            next_url = ''\n        if next_url and next_url.startswith(url_path_join(self.base_url, 'user/')):\n            # add /hub/ prefix, to ensure we redirect to the right user's server.\n            # The next request will be handled by UserSpawnHandler,\n            # ultimately redirecting to the logged-in user's server.\n            without_prefix = next_url[len(self.base_url):]\n            next_url = url_path_join(self.hub.base_url, without_prefix)\n            self.log.warning(\"Redirecting %s to %s. For sharing public links, use /user-redirect/\",\n                self.request.uri, next_url,\n            )\n            self.redirect(next_url)\n            return\n        user = self.get_current_user()\n        if user:\n            if user.running:\n                url = user.url\n                self.log.debug(\"User is running: %s\", url)\n                self.set_login_cookie(user) # set cookie\n            else:\n                url = url_path_join(self.hub.base_url, 'home')\n                self.log.debug(\"User is not running: %s\", url)\n        else:\n            url = self.settings['login_url']\n        self.redirect(url)\n\n\nclass HomeHandler(BaseHandler):\n    \"\"\"Render the user's home page.\"\"\"\n\n    @web.authenticated\n    @gen.coroutine\n    def get(self):\n        user = self.get_current_user()\n        if user.running:\n            # trigger poll_and_notify event in case of a server that died\n            yield user.spawner.poll_and_notify()\n        html = self.render_template('home.html',\n            user=user,\n            url=user.url,\n        )\n        self.finish(html)\n\n\nclass SpawnHandler(BaseHandler):\n    \"\"\"Handle spawning of single-user servers via form.\n\n    GET renders the form, POST handles form submission.\n\n    Only enabled when Spawner.options_form is defined.\n    \"\"\"\n    def _render_form(self, message=''):\n        user = self.get_current_user()\n        return self.render_template('spawn.html',\n            user=user,\n            spawner_options_form=user.spawner.options_form,\n            error_message=message,\n            url=self.request.uri,\n        )\n\n    @web.authenticated\n    def get(self):\n        \"\"\"GET renders form for spawning with user-specified options\"\"\"\n        user = self.get_current_user()\n        if not self.allow_named_servers and user.running:\n            url = user.url\n            self.log.debug(\"User is running: %s\", url)\n            self.redirect(url)\n            return\n        if user.spawner.options_form:\n            self.finish(self._render_form())\n        else:\n            # not running, no form. Trigger spawn.\n            self.redirect(user.url)\n\n    @web.authenticated\n    @gen.coroutine\n    def post(self):\n        \"\"\"POST spawns with user-specified options\"\"\"\n        user = self.get_current_user()\n        if not self.allow_named_servers and user.running:\n            url = user.url\n            self.log.warning(\"User is already running: %s\", url)\n            self.redirect(url)\n            return\n        form_options = {}\n        for key, byte_list in self.request.body_arguments.items():\n            form_options[key] = [ bs.decode('utf8') for bs in byte_list ]\n        for key, byte_list in self.request.files.items():\n            form_options[\"%s_file\"%key] = byte_list\n        try:\n            options = user.spawner.options_from_form(form_options)\n            yield self.spawn_single_user(user, options=options)\n        except Exception as e:\n            self.log.error(\"Failed to spawn single-user server with form\", exc_info=True)\n            self.finish(self._render_form(str(e)))\n            return\n        self.set_login_cookie(user)\n        url = user.url\n\n        next_url = self.get_argument('next', '')\n        if next_url and not next_url.startswith('/'):\n            self.log.warning(\"Disallowing redirect outside JupyterHub: %r\", next_url)\n        elif next_url:\n            url = next_url\n\n        self.redirect(url)\n\nclass AdminHandler(BaseHandler):\n    \"\"\"Render the admin page.\"\"\"\n\n    @admin_only\n    def get(self):\n        available = {'name', 'admin', 'running', 'last_activity'}\n        default_sort = ['admin', 'name']\n        mapping = {\n            'running': '_server_id'\n        }\n        default_order = {\n            'name': 'asc',\n            'last_activity': 'desc',\n            'admin': 'desc',\n            'running': 'desc',\n        }\n        sorts = self.get_arguments('sort') or default_sort\n        orders = self.get_arguments('order')\n\n        for bad in set(sorts).difference(available):\n            self.log.warning(\"ignoring invalid sort: %r\", bad)\n            sorts.remove(bad)\n        for bad in set(orders).difference({'asc', 'desc'}):\n            self.log.warning(\"ignoring invalid order: %r\", bad)\n            orders.remove(bad)\n\n        # add default sort as secondary\n        for s in default_sort:\n            if s not in sorts:\n                sorts.append(s)\n        if len(orders) < len(sorts):\n            for col in sorts[len(orders):]:\n                orders.append(default_order[col])\n        else:\n            orders = orders[:len(sorts)]\n\n        # this could be one incomprehensible nested list comprehension\n        # get User columns\n        cols = [ getattr(orm.User, mapping.get(c, c)) for c in sorts ]\n        # get User.col.desc() order objects\n        ordered = [ getattr(c, o)() for c, o in zip(cols, orders) ]\n\n        users = self.db.query(orm.User).order_by(*ordered)\n        users = [ self._user_from_orm(u) for u in users ]\n        running = [ u for u in users if u.running ]\n\n        html = self.render_template('admin.html',\n            user=self.get_current_user(),\n            admin_access=self.settings.get('admin_access', False),\n            users=users,\n            running=running,\n            sort={s:o for s,o in zip(sorts, orders)},\n        )\n        self.finish(html)\n\n\nclass TokenPageHandler(BaseHandler):\n    \"\"\"Handler for page requesting new API tokens\"\"\"\n\n    @web.authenticated\n    def get(self):\n        html = self.render_template('token.html')\n        self.finish(html)\n\n\nclass ProxyErrorHandler(BaseHandler):\n    \"\"\"Handler for rendering proxy error pages\"\"\"\n    \n    def get(self, status_code_s):\n        status_code = int(status_code_s)\n        status_message = responses.get(status_code, 'Unknown HTTP Error')\n        # build template namespace\n        \n        hub_home = url_path_join(self.hub.base_url, 'home')\n        message_html = ''\n        if status_code == 503:\n            message_html = ' '.join([\n                \"Your server appears to be down.\",\n                \"Try restarting it <a href='%s'>from the hub</a>\" % hub_home\n            ])\n        ns = dict(\n            status_code=status_code,\n            status_message=status_message,\n            message_html=message_html,\n            logo_url=hub_home,\n        )\n\n        self.set_header('Content-Type', 'text/html')\n        # render the template\n        try:\n            html = self.render_template('%s.html' % status_code, **ns)\n        except TemplateNotFound:\n            self.log.debug(\"No template for %d\", status_code)\n            html = self.render_template('error.html', **ns)\n\n        self.write(html)\n\n\ndefault_handlers = [\n    (r'/?', RootHandler),\n    (r'/home', HomeHandler),\n    (r'/admin', AdminHandler),\n    (r'/spawn', SpawnHandler),\n    (r'/token', TokenPageHandler),\n    (r'/error/(\\d+)', ProxyErrorHandler),\n]\n", "path": "jupyterhub/handlers/pages.py"}]}