prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Cannot use "ignored_assets" properly on Windows with custom themes
  <!--
  Before creating an issue:
  * make sure you are using an up-to-date version of Nikola
  * search for existing issues that might be related
  
  Make sure to:
  * provide information about your environment (below)
  * include all the output you get, and any other information related to your problem
  
  Nikola v7.6.4, as provided by Ubuntu, is NOT SUPPORTED.
  If you are using this version, you should upgrade: https://getnikola.com/getting-started.html
  -->
  
  ### Environment
  
  **Python Version:** Python 3.7.1
  
  **Nikola Version:** Nikola v8.0.1
  
  **Operating System:** Windows 10
  
  ### Description:
  
  The option "ignored_assets" used in theme meta files does not work properly on Windows: the relative path is only recognized when using a backslash, i.e. css\theme.css instead of css/theme.css ([see doc](https://getnikola.com/theming.html#theme-meta-files)).
  
  ### Solution:
  
  Normalize the path to the convention of the operating system when parsing the theme meta file.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `nikola/plugins/task/copy_assets.py`
  Content:
  ```
  1 # -*- coding: utf-8 -*-
  2 
  3 # Copyright © 2012-2019 Roberto Alsina and others.
  4 
  5 # Permission is hereby granted, free of charge, to any
  6 # person obtaining a copy of this software and associated
  7 # documentation files (the "Software"), to deal in the
  8 # Software without restriction, including without limitation
  9 # the rights to use, copy, modify, merge, publish,
  10 # distribute, sublicense, and/or sell copies of the
  11 # Software, and to permit persons to whom the Software is
  12 # furnished to do so, subject to the following conditions:
  13 #
  14 # The above copyright notice and this permission notice
  15 # shall be included in all copies or substantial portions of
  16 # the Software.
  17 #
  18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
  19 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  20 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  21 # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
  22 # OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  23 # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  24 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26 
  27 """Copy theme assets into output."""
  28 
  29 
  30 import io
  31 import os
  32 
  33 from nikola.plugin_categories import Task
  34 from nikola import utils
  35 
  36 
  37 class CopyAssets(Task):
  38     """Copy theme assets into output."""
  39 
  40     name = "copy_assets"
  41 
  42     def gen_tasks(self):
  43         """Create tasks to copy the assets of the whole theme chain.
  44 
  45         If a file is present on two themes, use the version
  46         from the "youngest" theme.
  47         """
  48         kw = {
  49             "themes": self.site.THEMES,
  50             "translations": self.site.translations,
  51             "files_folders": self.site.config['FILES_FOLDERS'],
  52             "output_folder": self.site.config['OUTPUT_FOLDER'],
  53             "filters": self.site.config['FILTERS'],
  54             "code_color_scheme": self.site.config['CODE_COLOR_SCHEME'],
  55             "code.css_selectors": ['pre.code', '.highlight pre'],
  56             "code.css_head": '/* code.css file generated by Nikola */\n',
  57             "code.css_close": "\ntable.codetable { width: 100%;} td.linenos {text-align: right; width: 4em;}\n",
  58         }
  59         tasks = {}
  60         code_css_path = os.path.join(kw['output_folder'], 'assets', 'css', 'code.css')
  61         code_css_input = utils.get_asset_path('assets/css/code.css',
  62                                               themes=kw['themes'],
  63                                               files_folders=kw['files_folders'], output_dir=None)
  64         yield self.group_task()
  65 
  66         main_theme = utils.get_theme_path(kw['themes'][0])
  67         theme_ini = utils.parse_theme_meta(main_theme)
  68         if theme_ini:
  69             ignored_assets = theme_ini.get("Nikola", "ignored_assets", fallback='').split(',')
  70             ignored_assets = [asset_name.strip() for asset_name in ignored_assets]
  71         else:
  72             ignored_assets = []
  73 
  74         for theme_name in kw['themes']:
  75             src = os.path.join(utils.get_theme_path(theme_name), 'assets')
  76             dst = os.path.join(kw['output_folder'], 'assets')
  77             for task in utils.copy_tree(src, dst):
  78                 asset_name = os.path.relpath(task['name'], dst)
  79                 if task['name'] in tasks or asset_name in ignored_assets:
  80                     continue
  81                 tasks[task['name']] = task
  82                 task['uptodate'] = [utils.config_changed(kw, 'nikola.plugins.task.copy_assets')]
  83                 task['basename'] = self.name
  84                 if code_css_input:
  85                     if 'file_dep' not in task:
  86                         task['file_dep'] = []
  87                     task['file_dep'].append(code_css_input)
  88                 yield utils.apply_filters(task, kw['filters'])
  89 
  90         # Check whether or not there is a code.css file around.
  91         if not code_css_input and kw['code_color_scheme']:
  92             def create_code_css():
  93                 from pygments.formatters import get_formatter_by_name
  94                 formatter = get_formatter_by_name('html', style=kw["code_color_scheme"])
  95                 utils.makedirs(os.path.dirname(code_css_path))
  96                 with io.open(code_css_path, 'w+', encoding='utf8') as outf:
  97                     outf.write(kw["code.css_head"])
  98                     outf.write(formatter.get_style_defs(kw["code.css_selectors"]))
  99                     outf.write(kw["code.css_close"])
  100 
  101             if os.path.exists(code_css_path):
  102                 with io.open(code_css_path, 'r', encoding='utf-8') as fh:
  103                     testcontents = fh.read(len(kw["code.css_head"])) == kw["code.css_head"]
  104             else:
  105                 testcontents = False
  106 
  107             task = {
  108                 'basename': self.name,
  109                 'name': code_css_path,
  110                 'targets': [code_css_path],
  111                 'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.copy_assets'), testcontents],
  112                 'actions': [(create_code_css, [])],
  113                 'clean': True,
  114             }
  115             yield utils.apply_filters(task, kw['filters'])
  116
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/nikola/plugins/task/copy_assets.py b/nikola/plugins/task/copy_assets.py
  --- a/nikola/plugins/task/copy_assets.py
  +++ b/nikola/plugins/task/copy_assets.py
  @@ -67,7 +67,7 @@
           theme_ini = utils.parse_theme_meta(main_theme)
           if theme_ini:
               ignored_assets = theme_ini.get("Nikola", "ignored_assets", fallback='').split(',')
  -            ignored_assets = [asset_name.strip() for asset_name in ignored_assets]
  +            ignored_assets = [os.path.normpath(asset_name.strip()) for asset_name in ignored_assets]
           else:
               ignored_assets = []
  
verification_info: {"golden_diff": "diff --git a/nikola/plugins/task/copy_assets.py b/nikola/plugins/task/copy_assets.py\n--- a/nikola/plugins/task/copy_assets.py\n+++ b/nikola/plugins/task/copy_assets.py\n@@ -67,7 +67,7 @@\n         theme_ini = utils.parse_theme_meta(main_theme)\n         if theme_ini:\n             ignored_assets = theme_ini.get(\"Nikola\", \"ignored_assets\", fallback='').split(',')\n-            ignored_assets = [asset_name.strip() for asset_name in ignored_assets]\n+            ignored_assets = [os.path.normpath(asset_name.strip()) for asset_name in ignored_assets]\n         else:\n             ignored_assets = []\n", "issue": "Cannot use \"ignored_assets\" properly on Windows with custom themes\n<!--\r\nBefore creating an issue:\r\n* make sure you are using an up-to-date version of Nikola\r\n* search for existing issues that might be related\r\n\r\nMake sure to:\r\n* provide information about your environment (below)\r\n* include all the output you get, and any other information related to your problem\r\n\r\nNikola v7.6.4, as provided by Ubuntu, is NOT SUPPORTED.\r\nIf you are using this version, you should upgrade: https://getnikola.com/getting-started.html\r\n-->\r\n\r\n### Environment\r\n\r\n**Python Version:** Python 3.7.1\r\n\r\n**Nikola Version:** Nikola v8.0.1\r\n\r\n**Operating System:** Windows 10\r\n\r\n### Description:\r\n\r\nThe option \"ignored_assets\" used in theme meta files does not work properly on Windows: the relative path is only recognized when using a backslash, i.e. css\\theme.css instead of css/theme.css ([see doc](https://getnikola.com/theming.html#theme-meta-files)).\r\n\r\n### Solution:\r\n\r\nNormalize the path to the convention of the operating system when parsing the theme meta file.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 2012-2019 Roberto Alsina and others.\n\n# Permission is hereby granted, free of charge, to any\n# person obtaining a copy of this software and associated\n# documentation files (the \"Software\"), to deal in the\n# Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the\n# Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice\n# shall be included in all copies or substantial portions of\n# the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\n# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\"\"\"Copy theme assets into output.\"\"\"\n\n\nimport io\nimport os\n\nfrom nikola.plugin_categories import Task\nfrom nikola import utils\n\n\nclass CopyAssets(Task):\n    \"\"\"Copy theme assets into output.\"\"\"\n\n    name = \"copy_assets\"\n\n    def gen_tasks(self):\n        \"\"\"Create tasks to copy the assets of the whole theme chain.\n\n        If a file is present on two themes, use the version\n        from the \"youngest\" theme.\n        \"\"\"\n        kw = {\n            \"themes\": self.site.THEMES,\n            \"translations\": self.site.translations,\n            \"files_folders\": self.site.config['FILES_FOLDERS'],\n            \"output_folder\": self.site.config['OUTPUT_FOLDER'],\n            \"filters\": self.site.config['FILTERS'],\n            \"code_color_scheme\": self.site.config['CODE_COLOR_SCHEME'],\n            \"code.css_selectors\": ['pre.code', '.highlight pre'],\n            \"code.css_head\": '/* code.css file generated by Nikola */\\n',\n            \"code.css_close\": \"\\ntable.codetable { width: 100%;} td.linenos {text-align: right; width: 4em;}\\n\",\n        }\n        tasks = {}\n        code_css_path = os.path.join(kw['output_folder'], 'assets', 'css', 'code.css')\n        code_css_input = utils.get_asset_path('assets/css/code.css',\n                                              themes=kw['themes'],\n                                              files_folders=kw['files_folders'], output_dir=None)\n        yield self.group_task()\n\n        main_theme = utils.get_theme_path(kw['themes'][0])\n        theme_ini = utils.parse_theme_meta(main_theme)\n        if theme_ini:\n            ignored_assets = theme_ini.get(\"Nikola\", \"ignored_assets\", fallback='').split(',')\n            ignored_assets = [asset_name.strip() for asset_name in ignored_assets]\n        else:\n            ignored_assets = []\n\n        for theme_name in kw['themes']:\n            src = os.path.join(utils.get_theme_path(theme_name), 'assets')\n            dst = os.path.join(kw['output_folder'], 'assets')\n            for task in utils.copy_tree(src, dst):\n                asset_name = os.path.relpath(task['name'], dst)\n                if task['name'] in tasks or asset_name in ignored_assets:\n                    continue\n                tasks[task['name']] = task\n                task['uptodate'] = [utils.config_changed(kw, 'nikola.plugins.task.copy_assets')]\n                task['basename'] = self.name\n                if code_css_input:\n                    if 'file_dep' not in task:\n                        task['file_dep'] = []\n                    task['file_dep'].append(code_css_input)\n                yield utils.apply_filters(task, kw['filters'])\n\n        # Check whether or not there is a code.css file around.\n        if not code_css_input and kw['code_color_scheme']:\n            def create_code_css():\n                from pygments.formatters import get_formatter_by_name\n                formatter = get_formatter_by_name('html', style=kw[\"code_color_scheme\"])\n                utils.makedirs(os.path.dirname(code_css_path))\n                with io.open(code_css_path, 'w+', encoding='utf8') as outf:\n                    outf.write(kw[\"code.css_head\"])\n                    outf.write(formatter.get_style_defs(kw[\"code.css_selectors\"]))\n                    outf.write(kw[\"code.css_close\"])\n\n            if os.path.exists(code_css_path):\n                with io.open(code_css_path, 'r', encoding='utf-8') as fh:\n                    testcontents = fh.read(len(kw[\"code.css_head\"])) == kw[\"code.css_head\"]\n            else:\n                testcontents = False\n\n            task = {\n                'basename': self.name,\n                'name': code_css_path,\n                'targets': [code_css_path],\n                'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.copy_assets'), testcontents],\n                'actions': [(create_code_css, [])],\n                'clean': True,\n            }\n            yield utils.apply_filters(task, kw['filters'])\n", "path": "nikola/plugins/task/copy_assets.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 2012-2019 Roberto Alsina and others.\n\n# Permission is hereby granted, free of charge, to any\n# person obtaining a copy of this software and associated\n# documentation files (the \"Software\"), to deal in the\n# Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the\n# Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice\n# shall be included in all copies or substantial portions of\n# the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\n# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\"\"\"Copy theme assets into output.\"\"\"\n\n\nimport io\nimport os\n\nfrom nikola.plugin_categories import Task\nfrom nikola import utils\n\n\nclass CopyAssets(Task):\n    \"\"\"Copy theme assets into output.\"\"\"\n\n    name = \"copy_assets\"\n\n    def gen_tasks(self):\n        \"\"\"Create tasks to copy the assets of the whole theme chain.\n\n        If a file is present on two themes, use the version\n        from the \"youngest\" theme.\n        \"\"\"\n        kw = {\n            \"themes\": self.site.THEMES,\n            \"translations\": self.site.translations,\n            \"files_folders\": self.site.config['FILES_FOLDERS'],\n            \"output_folder\": self.site.config['OUTPUT_FOLDER'],\n            \"filters\": self.site.config['FILTERS'],\n            \"code_color_scheme\": self.site.config['CODE_COLOR_SCHEME'],\n            \"code.css_selectors\": ['pre.code', '.highlight pre'],\n            \"code.css_head\": '/* code.css file generated by Nikola */\\n',\n            \"code.css_close\": \"\\ntable.codetable { width: 100%;} td.linenos {text-align: right; width: 4em;}\\n\",\n        }\n        tasks = {}\n        code_css_path = os.path.join(kw['output_folder'], 'assets', 'css', 'code.css')\n        code_css_input = utils.get_asset_path('assets/css/code.css',\n                                              themes=kw['themes'],\n                                              files_folders=kw['files_folders'], output_dir=None)\n        yield self.group_task()\n\n        main_theme = utils.get_theme_path(kw['themes'][0])\n        theme_ini = utils.parse_theme_meta(main_theme)\n        if theme_ini:\n            ignored_assets = theme_ini.get(\"Nikola\", \"ignored_assets\", fallback='').split(',')\n            ignored_assets = [os.path.normpath(asset_name.strip()) for asset_name in ignored_assets]\n        else:\n            ignored_assets = []\n\n        for theme_name in kw['themes']:\n            src = os.path.join(utils.get_theme_path(theme_name), 'assets')\n            dst = os.path.join(kw['output_folder'], 'assets')\n            for task in utils.copy_tree(src, dst):\n                asset_name = os.path.relpath(task['name'], dst)\n                if task['name'] in tasks or asset_name in ignored_assets:\n                    continue\n                tasks[task['name']] = task\n                task['uptodate'] = [utils.config_changed(kw, 'nikola.plugins.task.copy_assets')]\n                task['basename'] = self.name\n                if code_css_input:\n                    if 'file_dep' not in task:\n                        task['file_dep'] = []\n                    task['file_dep'].append(code_css_input)\n                yield utils.apply_filters(task, kw['filters'])\n\n        # Check whether or not there is a code.css file around.\n        if not code_css_input and kw['code_color_scheme']:\n            def create_code_css():\n                from pygments.formatters import get_formatter_by_name\n                formatter = get_formatter_by_name('html', style=kw[\"code_color_scheme\"])\n                utils.makedirs(os.path.dirname(code_css_path))\n                with io.open(code_css_path, 'w+', encoding='utf8') as outf:\n                    outf.write(kw[\"code.css_head\"])\n                    outf.write(formatter.get_style_defs(kw[\"code.css_selectors\"]))\n                    outf.write(kw[\"code.css_close\"])\n\n            if os.path.exists(code_css_path):\n                with io.open(code_css_path, 'r', encoding='utf-8') as fh:\n                    testcontents = fh.read(len(kw[\"code.css_head\"])) == kw[\"code.css_head\"]\n            else:\n                testcontents = False\n\n            task = {\n                'basename': self.name,\n                'name': code_css_path,\n                'targets': [code_css_path],\n                'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.copy_assets'), testcontents],\n                'actions': [(create_code_css, [])],\n                'clean': True,\n            }\n            yield utils.apply_filters(task, kw['filters'])\n", "path": "nikola/plugins/task/copy_assets.py"}]}