We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
url filter gives the wrong path to local anchor links
When passed "#internal-anchor" on a page other than the top-level index, the `url` filter returns a relative path to the top-level index.

Like, if I have a page `about.md` and the page.url is `about/`; if I pass "#internal-anchor" to the `url` filter, I get `../#internal-anchor`.

The `url` filter should not modify those URLs that are internal to the current page.

(I suffer from this problem when using the material theme; in 3.0.4, in the "Skip to content" link, it passes a toc item's url to the `url` filter, which breaks it on every page except the top-level index.  HTMLProofer complains about the broken link.)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mkdocs/utils/__init__.py`
Content:
```
1 # coding: utf-8
2 
3 """
4 Standalone file utils.
5 
6 Nothing in this module should have an knowledge of config or the layout
7 and structure of the site and pages in the site.
8 """
9 
10 from __future__ import unicode_literals
11 
12 import logging
13 import os
14 import pkg_resources
15 import shutil
16 import re
17 import sys
18 import yaml
19 import fnmatch
20 import posixpath
21 
22 from mkdocs import exceptions
23 
24 try:                                                        # pragma: no cover
25     from urllib.parse import urlparse, urlunparse, urljoin  # noqa
26     from collections import UserDict                        # noqa
27 except ImportError:                                         # pragma: no cover
28     from urlparse import urlparse, urlunparse, urljoin      # noqa
29     from UserDict import UserDict                           # noqa
30 
31 
32 PY3 = sys.version_info[0] == 3
33 
34 if PY3:                         # pragma: no cover
35     string_types = str,         # noqa
36     text_type = str             # noqa
37 else:                           # pragma: no cover
38     string_types = basestring,  # noqa
39     text_type = unicode         # noqa
40 
41 log = logging.getLogger(__name__)
42 
43 markdown_extensions = [
44     '.markdown',
45     '.mdown',
46     '.mkdn',
47     '.mkd',
48     '.md'
49 ]
50 
51 
52 def yaml_load(source, loader=yaml.Loader):
53     """
54     Wrap PyYaml's loader so we can extend it to suit our needs.
55 
56     Load all strings as unicode.
57     https://stackoverflow.com/a/2967461/3609487
58     """
59 
60     def construct_yaml_str(self, node):
61         """
62         Override the default string handling function to always return
63         unicode objects.
64         """
65         return self.construct_scalar(node)
66 
67     class Loader(loader):
68         """
69         Define a custom loader derived from the global loader to leave the
70         global loader unaltered.
71         """
72 
73     # Attach our unicode constructor to our custom loader ensuring all strings
74     # will be unicode on translation.
75     Loader.add_constructor('tag:yaml.org,2002:str', construct_yaml_str)
76 
77     try:
78         return yaml.load(source, Loader)
79     finally:
80         # TODO: Remove this when external calls are properly cleaning up file
81         # objects. Some mkdocs internal calls, sometimes in test lib, will
82         # load configs with a file object but never close it.  On some
83         # systems, if a delete action is performed on that file without Python
84         # closing that object, there will be an access error. This will
85         # process the file and close it as there should be no more use for the
86         # file once we process the yaml content.
87         if hasattr(source, 'close'):
88             source.close()
89 
90 
91 def modified_time(file_path):
92     """
93     Return the modified time of the supplied file. If the file does not exists zero is returned.
94     see build_pages for use.
95     """
96     if os.path.exists(file_path):
97         return os.path.getmtime(file_path)
98     else:
99         return 0.0
100 
101 
102 def reduce_list(data_set):
103     """ Reduce duplicate items in a list and preserve order """
104     seen = set()
105     return [item for item in data_set if
106             item not in seen and not seen.add(item)]
107 
108 
109 def copy_file(source_path, output_path):
110     """
111     Copy source_path to output_path, making sure any parent directories exist.
112 
113     The output_path may be a directory.
114     """
115     output_dir = os.path.dirname(output_path)
116     if not os.path.exists(output_dir):
117         os.makedirs(output_dir)
118     if os.path.isdir(output_path):
119         output_path = os.path.join(output_path, os.path.basename(source_path))
120     shutil.copyfile(source_path, output_path)
121 
122 
123 def write_file(content, output_path):
124     """
125     Write content to output_path, making sure any parent directories exist.
126     """
127     output_dir = os.path.dirname(output_path)
128     if not os.path.exists(output_dir):
129         os.makedirs(output_dir)
130     with open(output_path, 'wb') as f:
131         f.write(content)
132 
133 
134 def clean_directory(directory):
135     """
136     Remove the content of a directory recursively but not the directory itself.
137     """
138     if not os.path.exists(directory):
139         return
140 
141     for entry in os.listdir(directory):
142 
143         # Don't remove hidden files from the directory. We never copy files
144         # that are hidden, so we shouldn't delete them either.
145         if entry.startswith('.'):
146             continue
147 
148         path = os.path.join(directory, entry)
149         if os.path.isdir(path):
150             shutil.rmtree(path, True)
151         else:
152             os.unlink(path)
153 
154 
155 def get_html_path(path):
156     """
157     Map a source file path to an output html path.
158 
159     Paths like 'index.md' will be converted to 'index.html'
160     Paths like 'about.md' will be converted to 'about/index.html'
161     Paths like 'api-guide/core.md' will be converted to 'api-guide/core/index.html'
162     """
163     path = os.path.splitext(path)[0]
164     if os.path.basename(path) == 'index':
165         return path + '.html'
166     return "/".join((path, 'index.html'))
167 
168 
169 def get_url_path(path, use_directory_urls=True):
170     """
171     Map a source file path to an output html path.
172 
173     Paths like 'index.md' will be converted to '/'
174     Paths like 'about.md' will be converted to '/about/'
175     Paths like 'api-guide/core.md' will be converted to '/api-guide/core/'
176 
177     If `use_directory_urls` is `False`, returned URLs will include the a trailing
178     `index.html` rather than just returning the directory path.
179     """
180     path = get_html_path(path)
181     url = '/' + path.replace(os.path.sep, '/')
182     if use_directory_urls:
183         return url[:-len('index.html')]
184     return url
185 
186 
187 def is_markdown_file(path):
188     """
189     Return True if the given file path is a Markdown file.
190 
191     https://superuser.com/questions/249436/file-extension-for-markdown-files
192     """
193     return any(fnmatch.fnmatch(path.lower(), '*{0}'.format(x)) for x in markdown_extensions)
194 
195 
196 def is_html_file(path):
197     """
198     Return True if the given file path is an HTML file.
199     """
200     ext = os.path.splitext(path)[1].lower()
201     return ext in [
202         '.html',
203         '.htm',
204     ]
205 
206 
207 def is_template_file(path):
208     """
209     Return True if the given file path is an HTML file.
210     """
211     ext = os.path.splitext(path)[1].lower()
212     return ext in [
213         '.html',
214         '.htm',
215         '.xml',
216     ]
217 
218 
219 _ERROR_TEMPLATE_RE = re.compile(r'^\d{3}\.html?$')
220 
221 
222 def is_error_template(path):
223     """
224     Return True if the given file path is an HTTP error template.
225     """
226     return bool(_ERROR_TEMPLATE_RE.match(path))
227 
228 
229 def get_relative_url(url, other):
230     """
231     Return given url relative to other.
232     """
233     if other != '.':
234         # Remove filename from other url if it has one.
235         parts = posixpath.split(other)
236         other = parts[0] if '.' in parts[1] else other
237     relurl = posixpath.relpath(url, other)
238     return relurl + '/' if url.endswith('/') else relurl
239 
240 
241 def normalize_url(path, page=None, base=''):
242     """ Return a URL relative to the given page or using the base. """
243     path = path_to_url(path or '.')
244     # Allow links to be fully qualified URL's
245     parsed = urlparse(path)
246     if parsed.scheme or parsed.netloc or path.startswith('/'):
247         return path
248 
249     # We must be looking at a local path.
250     if page is not None:
251         return get_relative_url(path, page.url)
252     else:
253         return posixpath.join(base, path)
254 
255 
256 def create_media_urls(path_list, page=None, base=''):
257     """
258     Return a list of URLs relative to the given page or using the base.
259     """
260     urls = []
261 
262     for path in path_list:
263         urls.append(normalize_url(path, page, base))
264 
265     return urls
266 
267 
268 def path_to_url(path):
269     """Convert a system path to a URL."""
270 
271     return '/'.join(path.split('\\'))
272 
273 
274 def get_theme_dir(name):
275     """ Return the directory of an installed theme by name. """
276 
277     theme = get_themes()[name]
278     return os.path.dirname(os.path.abspath(theme.load().__file__))
279 
280 
281 def get_themes():
282     """ Return a dict of all installed themes as (name, entry point) pairs. """
283 
284     themes = {}
285     builtins = pkg_resources.get_entry_map(dist='mkdocs', group='mkdocs.themes')
286 
287     for theme in pkg_resources.iter_entry_points(group='mkdocs.themes'):
288 
289         if theme.name in builtins and theme.dist.key != 'mkdocs':
290             raise exceptions.ConfigurationError(
291                 "The theme {0} is a builtin theme but {1} provides a theme "
292                 "with the same name".format(theme.name, theme.dist.key))
293 
294         elif theme.name in themes:
295             multiple_packages = [themes[theme.name].dist.key, theme.dist.key]
296             log.warning("The theme %s is provided by the Python packages "
297                         "'%s'. The one in %s will be used.",
298                         theme.name, ','.join(multiple_packages), theme.dist.key)
299 
300         themes[theme.name] = theme
301 
302     return themes
303 
304 
305 def get_theme_names():
306     """Return a list of all installed themes by name."""
307 
308     return get_themes().keys()
309 
310 
311 def dirname_to_title(dirname):
312 
313     title = dirname
314     title = title.replace('-', ' ').replace('_', ' ')
315     # Capitalize if the dirname was all lowercase, otherwise leave it as-is.
316     if title.lower() == title:
317         title = title.capitalize()
318 
319     return title
320 
321 
322 def get_markdown_title(markdown_src):
323         """
324         Get the title of a Markdown document. The title in this case is considered
325         to be a H1 that occurs before any other content in the document.
326         The procedure is then to iterate through the lines, stopping at the first
327         non-whitespace content. If it is a title, return that, otherwise return
328         None.
329         """
330 
331         lines = markdown_src.replace('\r\n', '\n').replace('\r', '\n').split('\n')
332         while lines:
333             line = lines.pop(0).strip()
334             if not line.strip():
335                 continue
336             if not line.startswith('# '):
337                 return
338             return line.lstrip('# ')
339 
340 
341 def find_or_create_node(branch, key):
342     """
343     Given a list, look for dictionary with a key matching key and return it's
344     value. If it doesn't exist, create it with the value of an empty list and
345     return that.
346     """
347 
348     for node in branch:
349         if not isinstance(node, dict):
350             continue
351 
352         if key in node:
353             return node[key]
354 
355     new_branch = []
356     node = {key: new_branch}
357     branch.append(node)
358     return new_branch
359 
360 
361 def nest_paths(paths):
362     """
363     Given a list of paths, convert them into a nested structure that will match
364     the pages config.
365     """
366     nested = []
367 
368     for path in paths:
369 
370         if os.path.sep not in path:
371             nested.append(path)
372             continue
373 
374         directory, _ = os.path.split(path)
375         parts = directory.split(os.path.sep)
376 
377         branch = nested
378         for part in parts:
379             part = dirname_to_title(part)
380             branch = find_or_create_node(branch, part)
381 
382         branch.append(path)
383 
384     return nested
385 
386 
387 class WarningFilter(logging.Filter):
388     """ Counts all WARNING level log messages. """
389     count = 0
390 
391     def filter(self, record):
392         if record.levelno == logging.WARNING:
393             self.count += 1
394         return True
395 
396 
397 # A global instance to use throughout package
398 warning_filter = WarningFilter()
399
```
--- 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/mkdocs/utils/__init__.py b/mkdocs/utils/__init__.py
--- a/mkdocs/utils/__init__.py
+++ b/mkdocs/utils/__init__.py
@@ -243,7 +243,7 @@
     path = path_to_url(path or '.')
     # Allow links to be fully qualified URL's
     parsed = urlparse(path)
-    if parsed.scheme or parsed.netloc or path.startswith('/'):
+    if parsed.scheme or parsed.netloc or path.startswith(('/', '#')):
         return path
 
     # We must be looking at a local path.

{"golden_diff": "diff --git a/mkdocs/utils/__init__.py b/mkdocs/utils/__init__.py\n--- a/mkdocs/utils/__init__.py\n+++ b/mkdocs/utils/__init__.py\n@@ -243,7 +243,7 @@\n     path = path_to_url(path or '.')\n     # Allow links to be fully qualified URL's\n     parsed = urlparse(path)\n-    if parsed.scheme or parsed.netloc or path.startswith('/'):\n+    if parsed.scheme or parsed.netloc or path.startswith(('/', '#')):\n         return path\n \n     # We must be looking at a local path.\n", "issue": "url filter gives the wrong path to local anchor links\nWhen passed \"#internal-anchor\" on a page other than the top-level index, the `url` filter returns a relative path to the top-level index.\r\n\r\nLike, if I have a page `about.md` and the page.url is `about/`; if I pass \"#internal-anchor\" to the `url` filter, I get `../#internal-anchor`.\r\n\r\nThe `url` filter should not modify those URLs that are internal to the current page.\r\n\r\n(I suffer from this problem when using the material theme; in 3.0.4, in the \"Skip to content\" link, it passes a toc item's url to the `url` filter, which breaks it on every page except the top-level index.  HTMLProofer complains about the broken link.)\n", "before_files": [{"content": "# coding: utf-8\n\n\"\"\"\nStandalone file utils.\n\nNothing in this module should have an knowledge of config or the layout\nand structure of the site and pages in the site.\n\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport logging\nimport os\nimport pkg_resources\nimport shutil\nimport re\nimport sys\nimport yaml\nimport fnmatch\nimport posixpath\n\nfrom mkdocs import exceptions\n\ntry:                                                        # pragma: no cover\n    from urllib.parse import urlparse, urlunparse, urljoin  # noqa\n    from collections import UserDict                        # noqa\nexcept ImportError:                                         # pragma: no cover\n    from urlparse import urlparse, urlunparse, urljoin      # noqa\n    from UserDict import UserDict                           # noqa\n\n\nPY3 = sys.version_info[0] == 3\n\nif PY3:                         # pragma: no cover\n    string_types = str,         # noqa\n    text_type = str             # noqa\nelse:                           # pragma: no cover\n    string_types = basestring,  # noqa\n    text_type = unicode         # noqa\n\nlog = logging.getLogger(__name__)\n\nmarkdown_extensions = [\n    '.markdown',\n    '.mdown',\n    '.mkdn',\n    '.mkd',\n    '.md'\n]\n\n\ndef yaml_load(source, loader=yaml.Loader):\n    \"\"\"\n    Wrap PyYaml's loader so we can extend it to suit our needs.\n\n    Load all strings as unicode.\n    https://stackoverflow.com/a/2967461/3609487\n    \"\"\"\n\n    def construct_yaml_str(self, node):\n        \"\"\"\n        Override the default string handling function to always return\n        unicode objects.\n        \"\"\"\n        return self.construct_scalar(node)\n\n    class Loader(loader):\n        \"\"\"\n        Define a custom loader derived from the global loader to leave the\n        global loader unaltered.\n        \"\"\"\n\n    # Attach our unicode constructor to our custom loader ensuring all strings\n    # will be unicode on translation.\n    Loader.add_constructor('tag:yaml.org,2002:str', construct_yaml_str)\n\n    try:\n        return yaml.load(source, Loader)\n    finally:\n        # TODO: Remove this when external calls are properly cleaning up file\n        # objects. Some mkdocs internal calls, sometimes in test lib, will\n        # load configs with a file object but never close it.  On some\n        # systems, if a delete action is performed on that file without Python\n        # closing that object, there will be an access error. This will\n        # process the file and close it as there should be no more use for the\n        # file once we process the yaml content.\n        if hasattr(source, 'close'):\n            source.close()\n\n\ndef modified_time(file_path):\n    \"\"\"\n    Return the modified time of the supplied file. If the file does not exists zero is returned.\n    see build_pages for use.\n    \"\"\"\n    if os.path.exists(file_path):\n        return os.path.getmtime(file_path)\n    else:\n        return 0.0\n\n\ndef reduce_list(data_set):\n    \"\"\" Reduce duplicate items in a list and preserve order \"\"\"\n    seen = set()\n    return [item for item in data_set if\n            item not in seen and not seen.add(item)]\n\n\ndef copy_file(source_path, output_path):\n    \"\"\"\n    Copy source_path to output_path, making sure any parent directories exist.\n\n    The output_path may be a directory.\n    \"\"\"\n    output_dir = os.path.dirname(output_path)\n    if not os.path.exists(output_dir):\n        os.makedirs(output_dir)\n    if os.path.isdir(output_path):\n        output_path = os.path.join(output_path, os.path.basename(source_path))\n    shutil.copyfile(source_path, output_path)\n\n\ndef write_file(content, output_path):\n    \"\"\"\n    Write content to output_path, making sure any parent directories exist.\n    \"\"\"\n    output_dir = os.path.dirname(output_path)\n    if not os.path.exists(output_dir):\n        os.makedirs(output_dir)\n    with open(output_path, 'wb') as f:\n        f.write(content)\n\n\ndef clean_directory(directory):\n    \"\"\"\n    Remove the content of a directory recursively but not the directory itself.\n    \"\"\"\n    if not os.path.exists(directory):\n        return\n\n    for entry in os.listdir(directory):\n\n        # Don't remove hidden files from the directory. We never copy files\n        # that are hidden, so we shouldn't delete them either.\n        if entry.startswith('.'):\n            continue\n\n        path = os.path.join(directory, entry)\n        if os.path.isdir(path):\n            shutil.rmtree(path, True)\n        else:\n            os.unlink(path)\n\n\ndef get_html_path(path):\n    \"\"\"\n    Map a source file path to an output html path.\n\n    Paths like 'index.md' will be converted to 'index.html'\n    Paths like 'about.md' will be converted to 'about/index.html'\n    Paths like 'api-guide/core.md' will be converted to 'api-guide/core/index.html'\n    \"\"\"\n    path = os.path.splitext(path)[0]\n    if os.path.basename(path) == 'index':\n        return path + '.html'\n    return \"/\".join((path, 'index.html'))\n\n\ndef get_url_path(path, use_directory_urls=True):\n    \"\"\"\n    Map a source file path to an output html path.\n\n    Paths like 'index.md' will be converted to '/'\n    Paths like 'about.md' will be converted to '/about/'\n    Paths like 'api-guide/core.md' will be converted to '/api-guide/core/'\n\n    If `use_directory_urls` is `False`, returned URLs will include the a trailing\n    `index.html` rather than just returning the directory path.\n    \"\"\"\n    path = get_html_path(path)\n    url = '/' + path.replace(os.path.sep, '/')\n    if use_directory_urls:\n        return url[:-len('index.html')]\n    return url\n\n\ndef is_markdown_file(path):\n    \"\"\"\n    Return True if the given file path is a Markdown file.\n\n    https://superuser.com/questions/249436/file-extension-for-markdown-files\n    \"\"\"\n    return any(fnmatch.fnmatch(path.lower(), '*{0}'.format(x)) for x in markdown_extensions)\n\n\ndef is_html_file(path):\n    \"\"\"\n    Return True if the given file path is an HTML file.\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.html',\n        '.htm',\n    ]\n\n\ndef is_template_file(path):\n    \"\"\"\n    Return True if the given file path is an HTML file.\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.html',\n        '.htm',\n        '.xml',\n    ]\n\n\n_ERROR_TEMPLATE_RE = re.compile(r'^\\d{3}\\.html?$')\n\n\ndef is_error_template(path):\n    \"\"\"\n    Return True if the given file path is an HTTP error template.\n    \"\"\"\n    return bool(_ERROR_TEMPLATE_RE.match(path))\n\n\ndef get_relative_url(url, other):\n    \"\"\"\n    Return given url relative to other.\n    \"\"\"\n    if other != '.':\n        # Remove filename from other url if it has one.\n        parts = posixpath.split(other)\n        other = parts[0] if '.' in parts[1] else other\n    relurl = posixpath.relpath(url, other)\n    return relurl + '/' if url.endswith('/') else relurl\n\n\ndef normalize_url(path, page=None, base=''):\n    \"\"\" Return a URL relative to the given page or using the base. \"\"\"\n    path = path_to_url(path or '.')\n    # Allow links to be fully qualified URL's\n    parsed = urlparse(path)\n    if parsed.scheme or parsed.netloc or path.startswith('/'):\n        return path\n\n    # We must be looking at a local path.\n    if page is not None:\n        return get_relative_url(path, page.url)\n    else:\n        return posixpath.join(base, path)\n\n\ndef create_media_urls(path_list, page=None, base=''):\n    \"\"\"\n    Return a list of URLs relative to the given page or using the base.\n    \"\"\"\n    urls = []\n\n    for path in path_list:\n        urls.append(normalize_url(path, page, base))\n\n    return urls\n\n\ndef path_to_url(path):\n    \"\"\"Convert a system path to a URL.\"\"\"\n\n    return '/'.join(path.split('\\\\'))\n\n\ndef get_theme_dir(name):\n    \"\"\" Return the directory of an installed theme by name. \"\"\"\n\n    theme = get_themes()[name]\n    return os.path.dirname(os.path.abspath(theme.load().__file__))\n\n\ndef get_themes():\n    \"\"\" Return a dict of all installed themes as (name, entry point) pairs. \"\"\"\n\n    themes = {}\n    builtins = pkg_resources.get_entry_map(dist='mkdocs', group='mkdocs.themes')\n\n    for theme in pkg_resources.iter_entry_points(group='mkdocs.themes'):\n\n        if theme.name in builtins and theme.dist.key != 'mkdocs':\n            raise exceptions.ConfigurationError(\n                \"The theme {0} is a builtin theme but {1} provides a theme \"\n                \"with the same name\".format(theme.name, theme.dist.key))\n\n        elif theme.name in themes:\n            multiple_packages = [themes[theme.name].dist.key, theme.dist.key]\n            log.warning(\"The theme %s is provided by the Python packages \"\n                        \"'%s'. The one in %s will be used.\",\n                        theme.name, ','.join(multiple_packages), theme.dist.key)\n\n        themes[theme.name] = theme\n\n    return themes\n\n\ndef get_theme_names():\n    \"\"\"Return a list of all installed themes by name.\"\"\"\n\n    return get_themes().keys()\n\n\ndef dirname_to_title(dirname):\n\n    title = dirname\n    title = title.replace('-', ' ').replace('_', ' ')\n    # Capitalize if the dirname was all lowercase, otherwise leave it as-is.\n    if title.lower() == title:\n        title = title.capitalize()\n\n    return title\n\n\ndef get_markdown_title(markdown_src):\n        \"\"\"\n        Get the title of a Markdown document. The title in this case is considered\n        to be a H1 that occurs before any other content in the document.\n        The procedure is then to iterate through the lines, stopping at the first\n        non-whitespace content. If it is a title, return that, otherwise return\n        None.\n        \"\"\"\n\n        lines = markdown_src.replace('\\r\\n', '\\n').replace('\\r', '\\n').split('\\n')\n        while lines:\n            line = lines.pop(0).strip()\n            if not line.strip():\n                continue\n            if not line.startswith('# '):\n                return\n            return line.lstrip('# ')\n\n\ndef find_or_create_node(branch, key):\n    \"\"\"\n    Given a list, look for dictionary with a key matching key and return it's\n    value. If it doesn't exist, create it with the value of an empty list and\n    return that.\n    \"\"\"\n\n    for node in branch:\n        if not isinstance(node, dict):\n            continue\n\n        if key in node:\n            return node[key]\n\n    new_branch = []\n    node = {key: new_branch}\n    branch.append(node)\n    return new_branch\n\n\ndef nest_paths(paths):\n    \"\"\"\n    Given a list of paths, convert them into a nested structure that will match\n    the pages config.\n    \"\"\"\n    nested = []\n\n    for path in paths:\n\n        if os.path.sep not in path:\n            nested.append(path)\n            continue\n\n        directory, _ = os.path.split(path)\n        parts = directory.split(os.path.sep)\n\n        branch = nested\n        for part in parts:\n            part = dirname_to_title(part)\n            branch = find_or_create_node(branch, part)\n\n        branch.append(path)\n\n    return nested\n\n\nclass WarningFilter(logging.Filter):\n    \"\"\" Counts all WARNING level log messages. \"\"\"\n    count = 0\n\n    def filter(self, record):\n        if record.levelno == logging.WARNING:\n            self.count += 1\n        return True\n\n\n# A global instance to use throughout package\nwarning_filter = WarningFilter()\n", "path": "mkdocs/utils/__init__.py"}], "after_files": [{"content": "# coding: utf-8\n\n\"\"\"\nStandalone file utils.\n\nNothing in this module should have an knowledge of config or the layout\nand structure of the site and pages in the site.\n\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport logging\nimport os\nimport pkg_resources\nimport shutil\nimport re\nimport sys\nimport yaml\nimport fnmatch\nimport posixpath\n\nfrom mkdocs import exceptions\n\ntry:                                                        # pragma: no cover\n    from urllib.parse import urlparse, urlunparse, urljoin  # noqa\n    from collections import UserDict                        # noqa\nexcept ImportError:                                         # pragma: no cover\n    from urlparse import urlparse, urlunparse, urljoin      # noqa\n    from UserDict import UserDict                           # noqa\n\n\nPY3 = sys.version_info[0] == 3\n\nif PY3:                         # pragma: no cover\n    string_types = str,         # noqa\n    text_type = str             # noqa\nelse:                           # pragma: no cover\n    string_types = basestring,  # noqa\n    text_type = unicode         # noqa\n\nlog = logging.getLogger(__name__)\n\nmarkdown_extensions = [\n    '.markdown',\n    '.mdown',\n    '.mkdn',\n    '.mkd',\n    '.md'\n]\n\n\ndef yaml_load(source, loader=yaml.Loader):\n    \"\"\"\n    Wrap PyYaml's loader so we can extend it to suit our needs.\n\n    Load all strings as unicode.\n    https://stackoverflow.com/a/2967461/3609487\n    \"\"\"\n\n    def construct_yaml_str(self, node):\n        \"\"\"\n        Override the default string handling function to always return\n        unicode objects.\n        \"\"\"\n        return self.construct_scalar(node)\n\n    class Loader(loader):\n        \"\"\"\n        Define a custom loader derived from the global loader to leave the\n        global loader unaltered.\n        \"\"\"\n\n    # Attach our unicode constructor to our custom loader ensuring all strings\n    # will be unicode on translation.\n    Loader.add_constructor('tag:yaml.org,2002:str', construct_yaml_str)\n\n    try:\n        return yaml.load(source, Loader)\n    finally:\n        # TODO: Remove this when external calls are properly cleaning up file\n        # objects. Some mkdocs internal calls, sometimes in test lib, will\n        # load configs with a file object but never close it.  On some\n        # systems, if a delete action is performed on that file without Python\n        # closing that object, there will be an access error. This will\n        # process the file and close it as there should be no more use for the\n        # file once we process the yaml content.\n        if hasattr(source, 'close'):\n            source.close()\n\n\ndef modified_time(file_path):\n    \"\"\"\n    Return the modified time of the supplied file. If the file does not exists zero is returned.\n    see build_pages for use.\n    \"\"\"\n    if os.path.exists(file_path):\n        return os.path.getmtime(file_path)\n    else:\n        return 0.0\n\n\ndef reduce_list(data_set):\n    \"\"\" Reduce duplicate items in a list and preserve order \"\"\"\n    seen = set()\n    return [item for item in data_set if\n            item not in seen and not seen.add(item)]\n\n\ndef copy_file(source_path, output_path):\n    \"\"\"\n    Copy source_path to output_path, making sure any parent directories exist.\n\n    The output_path may be a directory.\n    \"\"\"\n    output_dir = os.path.dirname(output_path)\n    if not os.path.exists(output_dir):\n        os.makedirs(output_dir)\n    if os.path.isdir(output_path):\n        output_path = os.path.join(output_path, os.path.basename(source_path))\n    shutil.copyfile(source_path, output_path)\n\n\ndef write_file(content, output_path):\n    \"\"\"\n    Write content to output_path, making sure any parent directories exist.\n    \"\"\"\n    output_dir = os.path.dirname(output_path)\n    if not os.path.exists(output_dir):\n        os.makedirs(output_dir)\n    with open(output_path, 'wb') as f:\n        f.write(content)\n\n\ndef clean_directory(directory):\n    \"\"\"\n    Remove the content of a directory recursively but not the directory itself.\n    \"\"\"\n    if not os.path.exists(directory):\n        return\n\n    for entry in os.listdir(directory):\n\n        # Don't remove hidden files from the directory. We never copy files\n        # that are hidden, so we shouldn't delete them either.\n        if entry.startswith('.'):\n            continue\n\n        path = os.path.join(directory, entry)\n        if os.path.isdir(path):\n            shutil.rmtree(path, True)\n        else:\n            os.unlink(path)\n\n\ndef get_html_path(path):\n    \"\"\"\n    Map a source file path to an output html path.\n\n    Paths like 'index.md' will be converted to 'index.html'\n    Paths like 'about.md' will be converted to 'about/index.html'\n    Paths like 'api-guide/core.md' will be converted to 'api-guide/core/index.html'\n    \"\"\"\n    path = os.path.splitext(path)[0]\n    if os.path.basename(path) == 'index':\n        return path + '.html'\n    return \"/\".join((path, 'index.html'))\n\n\ndef get_url_path(path, use_directory_urls=True):\n    \"\"\"\n    Map a source file path to an output html path.\n\n    Paths like 'index.md' will be converted to '/'\n    Paths like 'about.md' will be converted to '/about/'\n    Paths like 'api-guide/core.md' will be converted to '/api-guide/core/'\n\n    If `use_directory_urls` is `False`, returned URLs will include the a trailing\n    `index.html` rather than just returning the directory path.\n    \"\"\"\n    path = get_html_path(path)\n    url = '/' + path.replace(os.path.sep, '/')\n    if use_directory_urls:\n        return url[:-len('index.html')]\n    return url\n\n\ndef is_markdown_file(path):\n    \"\"\"\n    Return True if the given file path is a Markdown file.\n\n    https://superuser.com/questions/249436/file-extension-for-markdown-files\n    \"\"\"\n    return any(fnmatch.fnmatch(path.lower(), '*{0}'.format(x)) for x in markdown_extensions)\n\n\ndef is_html_file(path):\n    \"\"\"\n    Return True if the given file path is an HTML file.\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.html',\n        '.htm',\n    ]\n\n\ndef is_template_file(path):\n    \"\"\"\n    Return True if the given file path is an HTML file.\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.html',\n        '.htm',\n        '.xml',\n    ]\n\n\n_ERROR_TEMPLATE_RE = re.compile(r'^\\d{3}\\.html?$')\n\n\ndef is_error_template(path):\n    \"\"\"\n    Return True if the given file path is an HTTP error template.\n    \"\"\"\n    return bool(_ERROR_TEMPLATE_RE.match(path))\n\n\ndef get_relative_url(url, other):\n    \"\"\"\n    Return given url relative to other.\n    \"\"\"\n    if other != '.':\n        # Remove filename from other url if it has one.\n        parts = posixpath.split(other)\n        other = parts[0] if '.' in parts[1] else other\n    relurl = posixpath.relpath(url, other)\n    return relurl + '/' if url.endswith('/') else relurl\n\n\ndef normalize_url(path, page=None, base=''):\n    \"\"\" Return a URL relative to the given page or using the base. \"\"\"\n    path = path_to_url(path or '.')\n    # Allow links to be fully qualified URL's\n    parsed = urlparse(path)\n    if parsed.scheme or parsed.netloc or path.startswith(('/', '#')):\n        return path\n\n    # We must be looking at a local path.\n    if page is not None:\n        return get_relative_url(path, page.url)\n    else:\n        return posixpath.join(base, path)\n\n\ndef create_media_urls(path_list, page=None, base=''):\n    \"\"\"\n    Return a list of URLs relative to the given page or using the base.\n    \"\"\"\n    urls = []\n\n    for path in path_list:\n        urls.append(normalize_url(path, page, base))\n\n    return urls\n\n\ndef path_to_url(path):\n    \"\"\"Convert a system path to a URL.\"\"\"\n\n    return '/'.join(path.split('\\\\'))\n\n\ndef get_theme_dir(name):\n    \"\"\" Return the directory of an installed theme by name. \"\"\"\n\n    theme = get_themes()[name]\n    return os.path.dirname(os.path.abspath(theme.load().__file__))\n\n\ndef get_themes():\n    \"\"\" Return a dict of all installed themes as (name, entry point) pairs. \"\"\"\n\n    themes = {}\n    builtins = pkg_resources.get_entry_map(dist='mkdocs', group='mkdocs.themes')\n\n    for theme in pkg_resources.iter_entry_points(group='mkdocs.themes'):\n\n        if theme.name in builtins and theme.dist.key != 'mkdocs':\n            raise exceptions.ConfigurationError(\n                \"The theme {0} is a builtin theme but {1} provides a theme \"\n                \"with the same name\".format(theme.name, theme.dist.key))\n\n        elif theme.name in themes:\n            multiple_packages = [themes[theme.name].dist.key, theme.dist.key]\n            log.warning(\"The theme %s is provided by the Python packages \"\n                        \"'%s'. The one in %s will be used.\",\n                        theme.name, ','.join(multiple_packages), theme.dist.key)\n\n        themes[theme.name] = theme\n\n    return themes\n\n\ndef get_theme_names():\n    \"\"\"Return a list of all installed themes by name.\"\"\"\n\n    return get_themes().keys()\n\n\ndef dirname_to_title(dirname):\n\n    title = dirname\n    title = title.replace('-', ' ').replace('_', ' ')\n    # Capitalize if the dirname was all lowercase, otherwise leave it as-is.\n    if title.lower() == title:\n        title = title.capitalize()\n\n    return title\n\n\ndef get_markdown_title(markdown_src):\n        \"\"\"\n        Get the title of a Markdown document. The title in this case is considered\n        to be a H1 that occurs before any other content in the document.\n        The procedure is then to iterate through the lines, stopping at the first\n        non-whitespace content. If it is a title, return that, otherwise return\n        None.\n        \"\"\"\n\n        lines = markdown_src.replace('\\r\\n', '\\n').replace('\\r', '\\n').split('\\n')\n        while lines:\n            line = lines.pop(0).strip()\n            if not line.strip():\n                continue\n            if not line.startswith('# '):\n                return\n            return line.lstrip('# ')\n\n\ndef find_or_create_node(branch, key):\n    \"\"\"\n    Given a list, look for dictionary with a key matching key and return it's\n    value. If it doesn't exist, create it with the value of an empty list and\n    return that.\n    \"\"\"\n\n    for node in branch:\n        if not isinstance(node, dict):\n            continue\n\n        if key in node:\n            return node[key]\n\n    new_branch = []\n    node = {key: new_branch}\n    branch.append(node)\n    return new_branch\n\n\ndef nest_paths(paths):\n    \"\"\"\n    Given a list of paths, convert them into a nested structure that will match\n    the pages config.\n    \"\"\"\n    nested = []\n\n    for path in paths:\n\n        if os.path.sep not in path:\n            nested.append(path)\n            continue\n\n        directory, _ = os.path.split(path)\n        parts = directory.split(os.path.sep)\n\n        branch = nested\n        for part in parts:\n            part = dirname_to_title(part)\n            branch = find_or_create_node(branch, part)\n\n        branch.append(path)\n\n    return nested\n\n\nclass WarningFilter(logging.Filter):\n    \"\"\" Counts all WARNING level log messages. \"\"\"\n    count = 0\n\n    def filter(self, record):\n        if record.levelno == logging.WARNING:\n            self.count += 1\n        return True\n\n\n# A global instance to use throughout package\nwarning_filter = WarningFilter()\n", "path": "mkdocs/utils/__init__.py"}]}