We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
routes manual reference URL in comment is broken
**CKAN version**
latest

**Describe the bug**
The url in [comment ](https://github.com/ckan/ckan/blob/0f87337fd937a15545ed761367b5d27d888e3803/ckan/config/routing.py#L6) is broken.

**Steps to reproduce**
Steps to reproduce the behavior:
Open a browser and go to "http://routes.groovie.org/docs/"
![image](https://user-images.githubusercontent.com/37072369/86097650-42283680-bab5-11ea-9210-cd5baf3dded4.png)


**Expected behavior**
A valid documentation reference.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ckan/config/routing.py`
Content:
```
1 # encoding: utf-8
2 """Routes configuration
3 
4 The more specific and detailed routes should be defined first so they
5 may take precedent over the more generic routes. For more information
6 refer to the routes manual at http://routes.groovie.org/docs/
7 
8 """
9 import re
10 
11 from routes.mapper import SubMapper, Mapper as _Mapper
12 
13 import ckan.plugins as p
14 from ckan.common import config, current_app
15 
16 named_routes = {}
17 
18 
19 class Mapper(_Mapper):
20     ''' This Mapper allows us to intercept the connect calls used by routes
21     so that we can collect named routes and later use them to create links
22     via some helper functions like build_nav(). '''
23 
24     def connect(self, *args, **kw):
25         '''Connect a new route, storing any named routes for later.
26 
27         This custom connect() method wraps the standard connect() method,
28         and additionally saves any named routes that are connected in a dict
29         ckan.routing.named_routes, which ends up being accessible via the
30         Pylons config as config['routes.named_routes'].
31 
32         Also takes some additional params:
33 
34         :param ckan_icon: name of the icon to be associated with this route,
35             e.g. 'group', 'time'. Available icons are listed here:
36             http://fortawesome.github.io/Font-Awesome/3.2.1/icons/
37         :type ckan_icon: string
38         :param highlight_actions: space-separated list of controller actions
39             that should be treated as the same as this named route for menu
40             highlighting purposes, e.g. 'index search'
41         :type highlight_actions: string
42 
43         '''
44 
45         ckan_icon = kw.pop('ckan_icon', None)
46         highlight_actions = kw.pop('highlight_actions', kw.get('action', ''))
47         ckan_core = kw.pop('ckan_core', None)
48         out = _Mapper.connect(self, *args, **kw)
49         route = self.matchlist[-1]
50         if ckan_core is not None:
51             route._ckan_core = ckan_core
52         if len(args) == 1 or args[0].startswith('_redirect_'):
53             return out
54         # we have a named route
55         needed = []
56         matches = re.findall('\{([^:}]*)(\}|:)', args[1])
57         for match in matches:
58             needed.append(match[0])
59         route_data = {
60             'icon': ckan_icon,
61             # needed lists the names of the parameters that need defining
62             # for the route to be generated
63             'needed': needed,
64             'controller': kw.get('controller'),
65             'action': kw.get('action', ''),
66             'highlight_actions': highlight_actions
67         }
68         named_routes[args[0]] = route_data
69         return out
70 
71 
72 def make_map():
73     """Create, configure and return the routes Mapper"""
74     # import controllers here rather than at root level because
75     # pylons config is initialised by this point.
76 
77     # Helpers to reduce code clutter
78     GET = dict(method=['GET'])
79     PUT = dict(method=['PUT'])
80     POST = dict(method=['POST'])
81     DELETE = dict(method=['DELETE'])
82     GET_POST = dict(method=['GET', 'POST'])
83     PUT_POST = dict(method=['PUT', 'POST'])
84     PUT_POST_DELETE = dict(method=['PUT', 'POST', 'DELETE'])
85     OPTIONS = dict(method=['OPTIONS'])
86 
87     map = Mapper(
88         directory=config['pylons.paths']['controllers'],
89         always_scan=config['debug'])
90     map.minimization = False
91     map.explicit = True
92 
93     # CUSTOM ROUTES HERE
94     for plugin in p.PluginImplementations(p.IRoutes):
95         map = plugin.before_map(map)
96 
97     # The ErrorController route (handles 404/500 error pages); it should
98     # likely stay at the top, ensuring it can always be resolved.
99     map.connect('/error/{action}', controller='error', ckan_core=True)
100     map.connect('/error/{action}/{id}', controller='error', ckan_core=True)
101 
102     map.connect(
103         '*url',
104         controller='home',
105         action='cors_options',
106         conditions=OPTIONS,
107         ckan_core=True)
108 
109     # Mark all routes added from extensions on the `before_map` extension point
110     # as non-core
111     for route in map.matchlist:
112         if not hasattr(route, '_ckan_core'):
113             route._ckan_core = False
114 
115     # /api/util ver 1, 2 or none
116     with SubMapper(
117             map, controller='api', path_prefix='/api{ver:/1|/2|}',
118             ver='/1') as m:
119         m.connect('/util/dataset/munge_name', action='munge_package_name')
120         m.connect(
121             '/util/dataset/munge_title_to_name',
122             action='munge_title_to_package_name')
123         m.connect('/util/tag/munge', action='munge_tag')
124 
125     ###########
126     ## /END API
127     ###########
128 
129     map.redirect('/packages', '/dataset')
130     map.redirect('/packages/{url:.*}', '/dataset/{url}')
131     map.redirect('/package', '/dataset')
132     map.redirect('/package/{url:.*}', '/dataset/{url}')
133 
134     # users
135     map.redirect('/users/{url:.*}', '/user/{url}')
136 
137     # Mark all unmarked routes added up until now as core routes
138     for route in map.matchlist:
139         if not hasattr(route, '_ckan_core'):
140             route._ckan_core = True
141 
142     for plugin in p.PluginImplementations(p.IRoutes):
143         map = plugin.after_map(map)
144 
145     # Mark all routes added from extensions on the `after_map` extension point
146     # as non-core
147     for route in map.matchlist:
148         if not hasattr(route, '_ckan_core'):
149             route._ckan_core = False
150 
151     # sometimes we get requests for favicon.ico we should redirect to
152     # the real favicon location.
153     map.redirect('/favicon.ico', config.get('ckan.favicon'))
154 
155     map.redirect('/*(url)/', '/{url}', _redirect_code='301 Moved Permanently')
156 
157     return map
158
```
--- 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/ckan/config/routing.py b/ckan/config/routing.py
--- a/ckan/config/routing.py
+++ b/ckan/config/routing.py
@@ -3,7 +3,7 @@
 
 The more specific and detailed routes should be defined first so they
 may take precedent over the more generic routes. For more information
-refer to the routes manual at http://routes.groovie.org/docs/
+refer to the routes manual at https://routes.readthedocs.io/en/latest/
 
 """
 import re

{"golden_diff": "diff --git a/ckan/config/routing.py b/ckan/config/routing.py\n--- a/ckan/config/routing.py\n+++ b/ckan/config/routing.py\n@@ -3,7 +3,7 @@\n \n The more specific and detailed routes should be defined first so they\n may take precedent over the more generic routes. For more information\n-refer to the routes manual at http://routes.groovie.org/docs/\n+refer to the routes manual at https://routes.readthedocs.io/en/latest/\n \n \"\"\"\n import re\n", "issue": "routes manual reference URL in comment is broken\n**CKAN version**\r\nlatest\r\n\r\n**Describe the bug**\r\nThe url in [comment ](https://github.com/ckan/ckan/blob/0f87337fd937a15545ed761367b5d27d888e3803/ckan/config/routing.py#L6) is broken.\r\n\r\n**Steps to reproduce**\r\nSteps to reproduce the behavior:\r\nOpen a browser and go to \"http://routes.groovie.org/docs/\"\r\n![image](https://user-images.githubusercontent.com/37072369/86097650-42283680-bab5-11ea-9210-cd5baf3dded4.png)\r\n\r\n\r\n**Expected behavior**\r\nA valid documentation reference.\r\n\r\n\n", "before_files": [{"content": "# encoding: utf-8\n\"\"\"Routes configuration\n\nThe more specific and detailed routes should be defined first so they\nmay take precedent over the more generic routes. For more information\nrefer to the routes manual at http://routes.groovie.org/docs/\n\n\"\"\"\nimport re\n\nfrom routes.mapper import SubMapper, Mapper as _Mapper\n\nimport ckan.plugins as p\nfrom ckan.common import config, current_app\n\nnamed_routes = {}\n\n\nclass Mapper(_Mapper):\n    ''' This Mapper allows us to intercept the connect calls used by routes\n    so that we can collect named routes and later use them to create links\n    via some helper functions like build_nav(). '''\n\n    def connect(self, *args, **kw):\n        '''Connect a new route, storing any named routes for later.\n\n        This custom connect() method wraps the standard connect() method,\n        and additionally saves any named routes that are connected in a dict\n        ckan.routing.named_routes, which ends up being accessible via the\n        Pylons config as config['routes.named_routes'].\n\n        Also takes some additional params:\n\n        :param ckan_icon: name of the icon to be associated with this route,\n            e.g. 'group', 'time'. Available icons are listed here:\n            http://fortawesome.github.io/Font-Awesome/3.2.1/icons/\n        :type ckan_icon: string\n        :param highlight_actions: space-separated list of controller actions\n            that should be treated as the same as this named route for menu\n            highlighting purposes, e.g. 'index search'\n        :type highlight_actions: string\n\n        '''\n\n        ckan_icon = kw.pop('ckan_icon', None)\n        highlight_actions = kw.pop('highlight_actions', kw.get('action', ''))\n        ckan_core = kw.pop('ckan_core', None)\n        out = _Mapper.connect(self, *args, **kw)\n        route = self.matchlist[-1]\n        if ckan_core is not None:\n            route._ckan_core = ckan_core\n        if len(args) == 1 or args[0].startswith('_redirect_'):\n            return out\n        # we have a named route\n        needed = []\n        matches = re.findall('\\{([^:}]*)(\\}|:)', args[1])\n        for match in matches:\n            needed.append(match[0])\n        route_data = {\n            'icon': ckan_icon,\n            # needed lists the names of the parameters that need defining\n            # for the route to be generated\n            'needed': needed,\n            'controller': kw.get('controller'),\n            'action': kw.get('action', ''),\n            'highlight_actions': highlight_actions\n        }\n        named_routes[args[0]] = route_data\n        return out\n\n\ndef make_map():\n    \"\"\"Create, configure and return the routes Mapper\"\"\"\n    # import controllers here rather than at root level because\n    # pylons config is initialised by this point.\n\n    # Helpers to reduce code clutter\n    GET = dict(method=['GET'])\n    PUT = dict(method=['PUT'])\n    POST = dict(method=['POST'])\n    DELETE = dict(method=['DELETE'])\n    GET_POST = dict(method=['GET', 'POST'])\n    PUT_POST = dict(method=['PUT', 'POST'])\n    PUT_POST_DELETE = dict(method=['PUT', 'POST', 'DELETE'])\n    OPTIONS = dict(method=['OPTIONS'])\n\n    map = Mapper(\n        directory=config['pylons.paths']['controllers'],\n        always_scan=config['debug'])\n    map.minimization = False\n    map.explicit = True\n\n    # CUSTOM ROUTES HERE\n    for plugin in p.PluginImplementations(p.IRoutes):\n        map = plugin.before_map(map)\n\n    # The ErrorController route (handles 404/500 error pages); it should\n    # likely stay at the top, ensuring it can always be resolved.\n    map.connect('/error/{action}', controller='error', ckan_core=True)\n    map.connect('/error/{action}/{id}', controller='error', ckan_core=True)\n\n    map.connect(\n        '*url',\n        controller='home',\n        action='cors_options',\n        conditions=OPTIONS,\n        ckan_core=True)\n\n    # Mark all routes added from extensions on the `before_map` extension point\n    # as non-core\n    for route in map.matchlist:\n        if not hasattr(route, '_ckan_core'):\n            route._ckan_core = False\n\n    # /api/util ver 1, 2 or none\n    with SubMapper(\n            map, controller='api', path_prefix='/api{ver:/1|/2|}',\n            ver='/1') as m:\n        m.connect('/util/dataset/munge_name', action='munge_package_name')\n        m.connect(\n            '/util/dataset/munge_title_to_name',\n            action='munge_title_to_package_name')\n        m.connect('/util/tag/munge', action='munge_tag')\n\n    ###########\n    ## /END API\n    ###########\n\n    map.redirect('/packages', '/dataset')\n    map.redirect('/packages/{url:.*}', '/dataset/{url}')\n    map.redirect('/package', '/dataset')\n    map.redirect('/package/{url:.*}', '/dataset/{url}')\n\n    # users\n    map.redirect('/users/{url:.*}', '/user/{url}')\n\n    # Mark all unmarked routes added up until now as core routes\n    for route in map.matchlist:\n        if not hasattr(route, '_ckan_core'):\n            route._ckan_core = True\n\n    for plugin in p.PluginImplementations(p.IRoutes):\n        map = plugin.after_map(map)\n\n    # Mark all routes added from extensions on the `after_map` extension point\n    # as non-core\n    for route in map.matchlist:\n        if not hasattr(route, '_ckan_core'):\n            route._ckan_core = False\n\n    # sometimes we get requests for favicon.ico we should redirect to\n    # the real favicon location.\n    map.redirect('/favicon.ico', config.get('ckan.favicon'))\n\n    map.redirect('/*(url)/', '/{url}', _redirect_code='301 Moved Permanently')\n\n    return map\n", "path": "ckan/config/routing.py"}], "after_files": [{"content": "# encoding: utf-8\n\"\"\"Routes configuration\n\nThe more specific and detailed routes should be defined first so they\nmay take precedent over the more generic routes. For more information\nrefer to the routes manual at https://routes.readthedocs.io/en/latest/\n\n\"\"\"\nimport re\n\nfrom routes.mapper import SubMapper, Mapper as _Mapper\n\nimport ckan.plugins as p\nfrom ckan.common import config, current_app\n\nnamed_routes = {}\n\n\nclass Mapper(_Mapper):\n    ''' This Mapper allows us to intercept the connect calls used by routes\n    so that we can collect named routes and later use them to create links\n    via some helper functions like build_nav(). '''\n\n    def connect(self, *args, **kw):\n        '''Connect a new route, storing any named routes for later.\n\n        This custom connect() method wraps the standard connect() method,\n        and additionally saves any named routes that are connected in a dict\n        ckan.routing.named_routes, which ends up being accessible via the\n        Pylons config as config['routes.named_routes'].\n\n        Also takes some additional params:\n\n        :param ckan_icon: name of the icon to be associated with this route,\n            e.g. 'group', 'time'. Available icons are listed here:\n            http://fortawesome.github.io/Font-Awesome/3.2.1/icons/\n        :type ckan_icon: string\n        :param highlight_actions: space-separated list of controller actions\n            that should be treated as the same as this named route for menu\n            highlighting purposes, e.g. 'index search'\n        :type highlight_actions: string\n\n        '''\n\n        ckan_icon = kw.pop('ckan_icon', None)\n        highlight_actions = kw.pop('highlight_actions', kw.get('action', ''))\n        ckan_core = kw.pop('ckan_core', None)\n        out = _Mapper.connect(self, *args, **kw)\n        route = self.matchlist[-1]\n        if ckan_core is not None:\n            route._ckan_core = ckan_core\n        if len(args) == 1 or args[0].startswith('_redirect_'):\n            return out\n        # we have a named route\n        needed = []\n        matches = re.findall('\\{([^:}]*)(\\}|:)', args[1])\n        for match in matches:\n            needed.append(match[0])\n        route_data = {\n            'icon': ckan_icon,\n            # needed lists the names of the parameters that need defining\n            # for the route to be generated\n            'needed': needed,\n            'controller': kw.get('controller'),\n            'action': kw.get('action', ''),\n            'highlight_actions': highlight_actions\n        }\n        named_routes[args[0]] = route_data\n        return out\n\n\ndef make_map():\n    \"\"\"Create, configure and return the routes Mapper\"\"\"\n    # import controllers here rather than at root level because\n    # pylons config is initialised by this point.\n\n    # Helpers to reduce code clutter\n    GET = dict(method=['GET'])\n    PUT = dict(method=['PUT'])\n    POST = dict(method=['POST'])\n    DELETE = dict(method=['DELETE'])\n    GET_POST = dict(method=['GET', 'POST'])\n    PUT_POST = dict(method=['PUT', 'POST'])\n    PUT_POST_DELETE = dict(method=['PUT', 'POST', 'DELETE'])\n    OPTIONS = dict(method=['OPTIONS'])\n\n    map = Mapper(\n        directory=config['pylons.paths']['controllers'],\n        always_scan=config['debug'])\n    map.minimization = False\n    map.explicit = True\n\n    # CUSTOM ROUTES HERE\n    for plugin in p.PluginImplementations(p.IRoutes):\n        map = plugin.before_map(map)\n\n    # The ErrorController route (handles 404/500 error pages); it should\n    # likely stay at the top, ensuring it can always be resolved.\n    map.connect('/error/{action}', controller='error', ckan_core=True)\n    map.connect('/error/{action}/{id}', controller='error', ckan_core=True)\n\n    map.connect(\n        '*url',\n        controller='home',\n        action='cors_options',\n        conditions=OPTIONS,\n        ckan_core=True)\n\n    # Mark all routes added from extensions on the `before_map` extension point\n    # as non-core\n    for route in map.matchlist:\n        if not hasattr(route, '_ckan_core'):\n            route._ckan_core = False\n\n    # /api/util ver 1, 2 or none\n    with SubMapper(\n            map, controller='api', path_prefix='/api{ver:/1|/2|}',\n            ver='/1') as m:\n        m.connect('/util/dataset/munge_name', action='munge_package_name')\n        m.connect(\n            '/util/dataset/munge_title_to_name',\n            action='munge_title_to_package_name')\n        m.connect('/util/tag/munge', action='munge_tag')\n\n    ###########\n    ## /END API\n    ###########\n\n    map.redirect('/packages', '/dataset')\n    map.redirect('/packages/{url:.*}', '/dataset/{url}')\n    map.redirect('/package', '/dataset')\n    map.redirect('/package/{url:.*}', '/dataset/{url}')\n\n    # users\n    map.redirect('/users/{url:.*}', '/user/{url}')\n\n    # Mark all unmarked routes added up until now as core routes\n    for route in map.matchlist:\n        if not hasattr(route, '_ckan_core'):\n            route._ckan_core = True\n\n    for plugin in p.PluginImplementations(p.IRoutes):\n        map = plugin.after_map(map)\n\n    # Mark all routes added from extensions on the `after_map` extension point\n    # as non-core\n    for route in map.matchlist:\n        if not hasattr(route, '_ckan_core'):\n            route._ckan_core = False\n\n    # sometimes we get requests for favicon.ico we should redirect to\n    # the real favicon location.\n    map.redirect('/favicon.ico', config.get('ckan.favicon'))\n\n    map.redirect('/*(url)/', '/{url}', _redirect_code='301 Moved Permanently')\n\n    return map\n", "path": "ckan/config/routing.py"}]}