We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Wrong filter order in post_list plugin
## Desc

I want to include the newest post with tag "games". But the newest "games" post isn't the newest post at all. The rest directive `post_list` (example below) doesn't return anything. It's caused by timeline filtering first.

The plugin should filter for tags first and apply the timeline filter in a second step.
## Details to reproduce
### Existing posts
- 20140719.news: tag: news
- 20140630.news: tag: photos
- 20140615.news: tag: games
### Rest directive

``` rest
.. post-list::
   :start: 0
   :stop: 1
   :tags: games
```
### Result

None
### Expected Result

headline and date of 20140615.news
### A fix may base on this patch

``` diff
--- post_list.py.old    2014-07-19 08:59:55.814081440 +0200
+++ post_list.py    2014-07-19 08:49:48.887397065 +0200
@@ -129,6 +129,7 @@
         else:
             post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex)

+        filtered_timeline = []
         posts = []
         step = -1 if reverse is None else None
         if show_all is None:
@@ -136,16 +137,21 @@
         else:
             timeline = [p for p in self.site.timeline if p.use_in_feeds]

-        for post in timeline[start:stop:step]:
+        for post in timeline:
             if tags:
                 cont = True
+                tags_lower = [t.lower() for t in post.tags]
                 for tag in tags:
-                    if tag in [t.lower() for t in post.tags]:
+                    if tag in tags_lower:
                         cont = False

                 if cont:
                     continue

+            filtered_timeline.append(post)
+
+        for post in filtered_timeline[start:stop:step]:
+
             if slugs:
                 cont = True
                 for slug in slugs:
```


--- 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/compile/rest/post_list.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 # Copyright © 2013-2014 Udo Spallek, 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 from __future__ import unicode_literals
27 
28 import uuid
29 
30 from docutils import nodes
31 from docutils.parsers.rst import Directive, directives
32 
33 from nikola import utils
34 from nikola.plugin_categories import RestExtension
35 
36 # WARNING: the directive name is post-list
37 #          (with a DASH instead of an UNDERSCORE)
38 
39 
40 class Plugin(RestExtension):
41     name = "rest_post_list"
42 
43     def set_site(self, site):
44         self.site = site
45         directives.register_directive('post-list', PostList)
46         PostList.site = site
47         return super(Plugin, self).set_site(site)
48 
49 
50 class PostList(Directive):
51     """
52     Post List
53     =========
54     :Directive Arguments: None.
55     :Directive Options: lang, start, stop, reverse, tags, template, id
56     :Directive Content: None.
57 
58     Provides a reStructuredText directive to create a list of posts.
59     The posts appearing in the list can be filtered by options.
60     *List slicing* is provided with the *start*, *stop* and *reverse* options.
61 
62     The following not required options are recognized:
63 
64     ``start`` : integer
65         The index of the first post to show.
66         A negative value like ``-3`` will show the *last* three posts in the
67         post-list.
68         Defaults to None.
69 
70     ``stop`` : integer
71         The index of the last post to show.
72         A value negative value like ``-1`` will show every post, but not the
73         *last* in the post-list.
74         Defaults to None.
75 
76     ``reverse`` : flag
77         Reverse the order of the post-list.
78         Defaults is to not reverse the order of posts.
79 
80     ``tags`` : string [, string...]
81         Filter posts to show only posts having at least one of the ``tags``.
82         Defaults to None.
83 
84     ``slugs`` : string [, string...]
85         Filter posts to show only posts having at least one of the ``slugs``.
86         Defaults to None.
87 
88     ``all`` : flag
89         Shows all posts and pages in the post list.
90         Defaults to show only posts with set *use_in_feeds*.
91 
92     ``lang`` : string
93         The language of post *titles* and *links*.
94         Defaults to default language.
95 
96     ``template`` : string
97         The name of an alternative template to render the post-list.
98         Defaults to ``post_list_directive.tmpl``
99 
100     ``id`` : string
101         A manual id for the post list.
102         Defaults to a random name composed by 'post_list_' + uuid.uuid4().hex.
103     """
104     option_spec = {
105         'start': int,
106         'stop': int,
107         'reverse': directives.flag,
108         'tags': directives.unchanged,
109         'slugs': directives.unchanged,
110         'all': directives.flag,
111         'lang': directives.unchanged,
112         'template': directives.path,
113         'id': directives.unchanged,
114     }
115 
116     def run(self):
117         start = self.options.get('start')
118         stop = self.options.get('stop')
119         reverse = self.options.get('reverse', False)
120         tags = self.options.get('tags')
121         tags = [t.strip().lower() for t in tags.split(',')] if tags else []
122         slugs = self.options.get('slugs')
123         slugs = [s.strip() for s in slugs.split(',')] if slugs else []
124         show_all = self.options.get('all', False)
125         lang = self.options.get('lang', utils.LocaleBorg().current_lang)
126         template = self.options.get('template', 'post_list_directive.tmpl')
127         if self.site.invariant:  # for testing purposes
128             post_list_id = self.options.get('id', 'post_list_' + 'fixedvaluethatisnotauuid')
129         else:
130             post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex)
131 
132         posts = []
133         step = -1 if reverse is None else None
134         if show_all is None:
135             timeline = [p for p in self.site.timeline]
136         else:
137             timeline = [p for p in self.site.timeline if p.use_in_feeds]
138 
139         for post in timeline[start:stop:step]:
140             if tags:
141                 cont = True
142                 for tag in tags:
143                     if tag in [t.lower() for t in post.tags]:
144                         cont = False
145 
146                 if cont:
147                     continue
148 
149             if slugs:
150                 cont = True
151                 for slug in slugs:
152                     if slug == post.meta('slug'):
153                         cont = False
154 
155                 if cont:
156                     continue
157 
158             posts += [post]
159 
160         if not posts:
161             return []
162 
163         template_data = {
164             'lang': lang,
165             'posts': posts,
166             'date_format': self.site.GLOBAL_CONTEXT.get('date_format'),
167             'post_list_id': post_list_id,
168         }
169         output = self.site.template_system.render_template(
170             template, None, template_data)
171         return [nodes.raw('', output, format='html')]
172
```
--- 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/nikola/plugins/compile/rest/post_list.py b/nikola/plugins/compile/rest/post_list.py
--- a/nikola/plugins/compile/rest/post_list.py
+++ b/nikola/plugins/compile/rest/post_list.py
@@ -129,6 +129,7 @@
         else:
             post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex)
 
+        filtered_timeline = []
         posts = []
         step = -1 if reverse is None else None
         if show_all is None:
@@ -136,16 +137,20 @@
         else:
             timeline = [p for p in self.site.timeline if p.use_in_feeds]
 
-        for post in timeline[start:stop:step]:
+        for post in timeline:
             if tags:
                 cont = True
+                tags_lower = [t.lower() for t in post.tags]
                 for tag in tags:
-                    if tag in [t.lower() for t in post.tags]:
+                    if tag in tags_lower:
                         cont = False
 
                 if cont:
                     continue
 
+            filtered_timeline.append(post)
+
+        for post in filtered_timeline[start:stop:step]:
             if slugs:
                 cont = True
                 for slug in slugs:

{"golden_diff": "diff --git a/nikola/plugins/compile/rest/post_list.py b/nikola/plugins/compile/rest/post_list.py\n--- a/nikola/plugins/compile/rest/post_list.py\n+++ b/nikola/plugins/compile/rest/post_list.py\n@@ -129,6 +129,7 @@\n         else:\n             post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex)\n \n+        filtered_timeline = []\n         posts = []\n         step = -1 if reverse is None else None\n         if show_all is None:\n@@ -136,16 +137,20 @@\n         else:\n             timeline = [p for p in self.site.timeline if p.use_in_feeds]\n \n-        for post in timeline[start:stop:step]:\n+        for post in timeline:\n             if tags:\n                 cont = True\n+                tags_lower = [t.lower() for t in post.tags]\n                 for tag in tags:\n-                    if tag in [t.lower() for t in post.tags]:\n+                    if tag in tags_lower:\n                         cont = False\n \n                 if cont:\n                     continue\n \n+            filtered_timeline.append(post)\n+\n+        for post in filtered_timeline[start:stop:step]:\n             if slugs:\n                 cont = True\n                 for slug in slugs:\n", "issue": "Wrong filter order in post_list plugin\n## Desc\n\nI want to include the newest post with tag \"games\". But the newest \"games\" post isn't the newest post at all. The rest directive `post_list` (example below) doesn't return anything. It's caused by timeline filtering first.\n\nThe plugin should filter for tags first and apply the timeline filter in a second step.\n## Details to reproduce\n### Existing posts\n- 20140719.news: tag: news\n- 20140630.news: tag: photos\n- 20140615.news: tag: games\n### Rest directive\n\n``` rest\n.. post-list::\n   :start: 0\n   :stop: 1\n   :tags: games\n```\n### Result\n\nNone\n### Expected Result\n\nheadline and date of 20140615.news\n### A fix may base on this patch\n\n``` diff\n--- post_list.py.old    2014-07-19 08:59:55.814081440 +0200\n+++ post_list.py    2014-07-19 08:49:48.887397065 +0200\n@@ -129,6 +129,7 @@\n         else:\n             post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex)\n\n+        filtered_timeline = []\n         posts = []\n         step = -1 if reverse is None else None\n         if show_all is None:\n@@ -136,16 +137,21 @@\n         else:\n             timeline = [p for p in self.site.timeline if p.use_in_feeds]\n\n-        for post in timeline[start:stop:step]:\n+        for post in timeline:\n             if tags:\n                 cont = True\n+                tags_lower = [t.lower() for t in post.tags]\n                 for tag in tags:\n-                    if tag in [t.lower() for t in post.tags]:\n+                    if tag in tags_lower:\n                         cont = False\n\n                 if cont:\n                     continue\n\n+            filtered_timeline.append(post)\n+\n+        for post in filtered_timeline[start:stop:step]:\n+\n             if slugs:\n                 cont = True\n                 for slug in slugs:\n```\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 2013-2014 Udo Spallek, 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.\nfrom __future__ import unicode_literals\n\nimport uuid\n\nfrom docutils import nodes\nfrom docutils.parsers.rst import Directive, directives\n\nfrom nikola import utils\nfrom nikola.plugin_categories import RestExtension\n\n# WARNING: the directive name is post-list\n#          (with a DASH instead of an UNDERSCORE)\n\n\nclass Plugin(RestExtension):\n    name = \"rest_post_list\"\n\n    def set_site(self, site):\n        self.site = site\n        directives.register_directive('post-list', PostList)\n        PostList.site = site\n        return super(Plugin, self).set_site(site)\n\n\nclass PostList(Directive):\n    \"\"\"\n    Post List\n    =========\n    :Directive Arguments: None.\n    :Directive Options: lang, start, stop, reverse, tags, template, id\n    :Directive Content: None.\n\n    Provides a reStructuredText directive to create a list of posts.\n    The posts appearing in the list can be filtered by options.\n    *List slicing* is provided with the *start*, *stop* and *reverse* options.\n\n    The following not required options are recognized:\n\n    ``start`` : integer\n        The index of the first post to show.\n        A negative value like ``-3`` will show the *last* three posts in the\n        post-list.\n        Defaults to None.\n\n    ``stop`` : integer\n        The index of the last post to show.\n        A value negative value like ``-1`` will show every post, but not the\n        *last* in the post-list.\n        Defaults to None.\n\n    ``reverse`` : flag\n        Reverse the order of the post-list.\n        Defaults is to not reverse the order of posts.\n\n    ``tags`` : string [, string...]\n        Filter posts to show only posts having at least one of the ``tags``.\n        Defaults to None.\n\n    ``slugs`` : string [, string...]\n        Filter posts to show only posts having at least one of the ``slugs``.\n        Defaults to None.\n\n    ``all`` : flag\n        Shows all posts and pages in the post list.\n        Defaults to show only posts with set *use_in_feeds*.\n\n    ``lang`` : string\n        The language of post *titles* and *links*.\n        Defaults to default language.\n\n    ``template`` : string\n        The name of an alternative template to render the post-list.\n        Defaults to ``post_list_directive.tmpl``\n\n    ``id`` : string\n        A manual id for the post list.\n        Defaults to a random name composed by 'post_list_' + uuid.uuid4().hex.\n    \"\"\"\n    option_spec = {\n        'start': int,\n        'stop': int,\n        'reverse': directives.flag,\n        'tags': directives.unchanged,\n        'slugs': directives.unchanged,\n        'all': directives.flag,\n        'lang': directives.unchanged,\n        'template': directives.path,\n        'id': directives.unchanged,\n    }\n\n    def run(self):\n        start = self.options.get('start')\n        stop = self.options.get('stop')\n        reverse = self.options.get('reverse', False)\n        tags = self.options.get('tags')\n        tags = [t.strip().lower() for t in tags.split(',')] if tags else []\n        slugs = self.options.get('slugs')\n        slugs = [s.strip() for s in slugs.split(',')] if slugs else []\n        show_all = self.options.get('all', False)\n        lang = self.options.get('lang', utils.LocaleBorg().current_lang)\n        template = self.options.get('template', 'post_list_directive.tmpl')\n        if self.site.invariant:  # for testing purposes\n            post_list_id = self.options.get('id', 'post_list_' + 'fixedvaluethatisnotauuid')\n        else:\n            post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex)\n\n        posts = []\n        step = -1 if reverse is None else None\n        if show_all is None:\n            timeline = [p for p in self.site.timeline]\n        else:\n            timeline = [p for p in self.site.timeline if p.use_in_feeds]\n\n        for post in timeline[start:stop:step]:\n            if tags:\n                cont = True\n                for tag in tags:\n                    if tag in [t.lower() for t in post.tags]:\n                        cont = False\n\n                if cont:\n                    continue\n\n            if slugs:\n                cont = True\n                for slug in slugs:\n                    if slug == post.meta('slug'):\n                        cont = False\n\n                if cont:\n                    continue\n\n            posts += [post]\n\n        if not posts:\n            return []\n\n        template_data = {\n            'lang': lang,\n            'posts': posts,\n            'date_format': self.site.GLOBAL_CONTEXT.get('date_format'),\n            'post_list_id': post_list_id,\n        }\n        output = self.site.template_system.render_template(\n            template, None, template_data)\n        return [nodes.raw('', output, format='html')]\n", "path": "nikola/plugins/compile/rest/post_list.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 2013-2014 Udo Spallek, 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.\nfrom __future__ import unicode_literals\n\nimport uuid\n\nfrom docutils import nodes\nfrom docutils.parsers.rst import Directive, directives\n\nfrom nikola import utils\nfrom nikola.plugin_categories import RestExtension\n\n# WARNING: the directive name is post-list\n#          (with a DASH instead of an UNDERSCORE)\n\n\nclass Plugin(RestExtension):\n    name = \"rest_post_list\"\n\n    def set_site(self, site):\n        self.site = site\n        directives.register_directive('post-list', PostList)\n        PostList.site = site\n        return super(Plugin, self).set_site(site)\n\n\nclass PostList(Directive):\n    \"\"\"\n    Post List\n    =========\n    :Directive Arguments: None.\n    :Directive Options: lang, start, stop, reverse, tags, template, id\n    :Directive Content: None.\n\n    Provides a reStructuredText directive to create a list of posts.\n    The posts appearing in the list can be filtered by options.\n    *List slicing* is provided with the *start*, *stop* and *reverse* options.\n\n    The following not required options are recognized:\n\n    ``start`` : integer\n        The index of the first post to show.\n        A negative value like ``-3`` will show the *last* three posts in the\n        post-list.\n        Defaults to None.\n\n    ``stop`` : integer\n        The index of the last post to show.\n        A value negative value like ``-1`` will show every post, but not the\n        *last* in the post-list.\n        Defaults to None.\n\n    ``reverse`` : flag\n        Reverse the order of the post-list.\n        Defaults is to not reverse the order of posts.\n\n    ``tags`` : string [, string...]\n        Filter posts to show only posts having at least one of the ``tags``.\n        Defaults to None.\n\n    ``slugs`` : string [, string...]\n        Filter posts to show only posts having at least one of the ``slugs``.\n        Defaults to None.\n\n    ``all`` : flag\n        Shows all posts and pages in the post list.\n        Defaults to show only posts with set *use_in_feeds*.\n\n    ``lang`` : string\n        The language of post *titles* and *links*.\n        Defaults to default language.\n\n    ``template`` : string\n        The name of an alternative template to render the post-list.\n        Defaults to ``post_list_directive.tmpl``\n\n    ``id`` : string\n        A manual id for the post list.\n        Defaults to a random name composed by 'post_list_' + uuid.uuid4().hex.\n    \"\"\"\n    option_spec = {\n        'start': int,\n        'stop': int,\n        'reverse': directives.flag,\n        'tags': directives.unchanged,\n        'slugs': directives.unchanged,\n        'all': directives.flag,\n        'lang': directives.unchanged,\n        'template': directives.path,\n        'id': directives.unchanged,\n    }\n\n    def run(self):\n        start = self.options.get('start')\n        stop = self.options.get('stop')\n        reverse = self.options.get('reverse', False)\n        tags = self.options.get('tags')\n        tags = [t.strip().lower() for t in tags.split(',')] if tags else []\n        slugs = self.options.get('slugs')\n        slugs = [s.strip() for s in slugs.split(',')] if slugs else []\n        show_all = self.options.get('all', False)\n        lang = self.options.get('lang', utils.LocaleBorg().current_lang)\n        template = self.options.get('template', 'post_list_directive.tmpl')\n        if self.site.invariant:  # for testing purposes\n            post_list_id = self.options.get('id', 'post_list_' + 'fixedvaluethatisnotauuid')\n        else:\n            post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex)\n\n        filtered_timeline = []\n        posts = []\n        step = -1 if reverse is None else None\n        if show_all is None:\n            timeline = [p for p in self.site.timeline]\n        else:\n            timeline = [p for p in self.site.timeline if p.use_in_feeds]\n\n        for post in timeline:\n            if tags:\n                cont = True\n                tags_lower = [t.lower() for t in post.tags]\n                for tag in tags:\n                    if tag in tags_lower:\n                        cont = False\n\n                if cont:\n                    continue\n\n            filtered_timeline.append(post)\n\n        for post in filtered_timeline[start:stop:step]:\n            if slugs:\n                cont = True\n                for slug in slugs:\n                    if slug == post.meta('slug'):\n                        cont = False\n\n                if cont:\n                    continue\n\n            posts += [post]\n\n        if not posts:\n            return []\n\n        template_data = {\n            'lang': lang,\n            'posts': posts,\n            'date_format': self.site.GLOBAL_CONTEXT.get('date_format'),\n            'post_list_id': post_list_id,\n        }\n        output = self.site.template_system.render_template(\n            template, None, template_data)\n        return [nodes.raw('', output, format='html')]\n", "path": "nikola/plugins/compile/rest/post_list.py"}]}