We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Correction of cfg-www.rst documentation
change StopBuildEndpointMatcher(role="owner") to
util.StopBuildEndpointMatcher(role="owner")

issue ref: #3043

Signed-off-by: desurd <david.desurmont@gmail.com>

## Remove this paragraph
Please have a look at our developer documentation before submitting your Pull Request.

http://trac.buildbot.net/wiki/Development
And especially:
http://trac.buildbot.net/wiki/SubmittingPatches

## Contributor Checklist:

* [ ] I have updated the unit tests
* [ ] I have created a file in the master/buildbot/newsfragment directory (and read the README.txt in that directory)
* [ ] I have updated the appropriate documentation



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `master/buildbot/db/logs.py`
Content:
```
1 # This file is part of Buildbot.  Buildbot is free software: you can
2 # redistribute it and/or modify it under the terms of the GNU General Public
3 # License as published by the Free Software Foundation, version 2.
4 #
5 # This program is distributed in the hope that it will be useful, but WITHOUT
6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
8 # details.
9 #
10 # You should have received a copy of the GNU General Public License along with
11 # this program; if not, write to the Free Software Foundation, Inc., 51
12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
13 #
14 # Copyright Buildbot Team Members
15 
16 import sqlalchemy as sa
17 
18 from buildbot.db import base
19 from twisted.internet import defer
20 from twisted.python import log
21 
22 
23 class LogsConnectorComponent(base.DBConnectorComponent):
24 
25     # Postgres and MySQL will both allow bigger sizes than this.  The limit
26     # for MySQL appears to be max_packet_size (default 1M).
27     MAX_CHUNK_SIZE = 65536
28 
29     def _getLog(self, whereclause):
30         def thd(conn):
31             q = self.db.model.logs.select(whereclause=whereclause)
32             res = conn.execute(q)
33             row = res.fetchone()
34 
35             rv = None
36             if row:
37                 rv = self._logdictFromRow(row)
38             res.close()
39             return rv
40         return self.db.pool.do(thd)
41 
42     def getLog(self, logid):
43         return self._getLog(self.db.model.logs.c.id == logid)
44 
45     def getLogBySlug(self, stepid, slug):
46         tbl = self.db.model.logs
47         return self._getLog((tbl.c.slug == slug) & (tbl.c.stepid == stepid))
48 
49     def getLogs(self, stepid):
50         def thd(conn):
51             tbl = self.db.model.logs
52             q = tbl.select()
53             q = q.where(tbl.c.stepid == stepid)
54             q = q.order_by(tbl.c.id)
55             res = conn.execute(q)
56             return [self._logdictFromRow(row) for row in res.fetchall()]
57         return self.db.pool.do(thd)
58 
59     def getLogLines(self, logid, first_line, last_line):
60         def thd(conn):
61             # get a set of chunks that completely cover the requested range
62             tbl = self.db.model.logchunks
63             q = sa.select([tbl.c.first_line, tbl.c.last_line,
64                            tbl.c.content, tbl.c.compressed])
65             q = q.where(tbl.c.logid == logid)
66             q = q.where(tbl.c.first_line <= last_line)
67             q = q.where(tbl.c.last_line >= first_line)
68             q = q.order_by(tbl.c.first_line)
69             rv = []
70             for row in conn.execute(q):
71                 assert not row.compressed, "compressed rows not supported yet"
72                 content = row.content.decode('utf-8')
73                 if row.first_line < first_line:
74                     idx = -1
75                     count = first_line - row.first_line
76                     for _ in xrange(count):
77                         idx = content.index('\n', idx + 1)
78                     content = content[idx + 1:]
79                 if row.last_line > last_line:
80                     idx = len(content) + 1
81                     count = row.last_line - last_line
82                     for _ in xrange(count):
83                         idx = content.rindex('\n', 0, idx - 1)
84                     content = content[:idx]
85                 rv.append(content)
86             return u'\n'.join(rv) + u'\n' if rv else u''
87         return self.db.pool.do(thd)
88 
89     def addLog(self, stepid, name, slug, type):
90         assert type in 'tsh', "Log type must be one of t, s, or h"
91 
92         def thd(conn):
93             try:
94                 r = conn.execute(self.db.model.logs.insert(),
95                                  dict(name=name, slug=slug, stepid=stepid,
96                                       complete=0, num_lines=0, type=type))
97                 return r.inserted_primary_key[0]
98             except (sa.exc.IntegrityError, sa.exc.ProgrammingError):
99                 raise KeyError(
100                     "log with slug '%r' already exists in this step" % (slug,))
101         return self.db.pool.do(thd)
102 
103     def appendLog(self, logid, content):
104         # check for trailing newline and strip it for storage -- chunks omit
105         # the trailing newline
106         assert content[-1] == u'\n'
107         content = content[:-1]
108 
109         def thd(conn):
110             q = sa.select([self.db.model.logs.c.num_lines])
111             q = q.where(self.db.model.logs.c.id == logid)
112             res = conn.execute(q)
113             row = res.fetchone()
114             res.close()
115             if not row:
116                 return  # ignore a missing log
117 
118             # Break the content up into chunks.  This takes advantage of the
119             # fact that no character but u'\n' maps to b'\n' in UTF-8.
120 
121             first_line = chunk_first_line = row[0]
122             remaining = content.encode('utf-8')
123             while remaining:
124                 chunk, remaining = self._splitBigChunk(remaining, logid)
125 
126                 last_line = chunk_first_line + chunk.count('\n')
127                 conn.execute(self.db.model.logchunks.insert(),
128                              dict(logid=logid, first_line=chunk_first_line,
129                                   last_line=last_line, content=chunk,
130                                   compressed=0))
131                 chunk_first_line = last_line + 1
132 
133             conn.execute(self.db.model.logs.update(whereclause=(self.db.model.logs.c.id == logid)),
134                          num_lines=last_line + 1)
135             return (first_line, last_line)
136         return self.db.pool.do(thd)
137 
138     def _splitBigChunk(self, content, logid):
139         """
140         Split CONTENT on a line boundary into a prefix smaller than 64k and
141         a suffix containing the remainder, omitting the splitting newline.
142         """
143         # if it's small enough, just return it
144         if len(content) < self.MAX_CHUNK_SIZE:
145             return content, None
146 
147         # find the last newline before the limit
148         i = content.rfind('\n', 0, self.MAX_CHUNK_SIZE)
149         if i != -1:
150             return content[:i], content[i + 1:]
151 
152         log.msg('truncating long line for log %d' % logid)
153 
154         # first, truncate this down to something that decodes correctly
155         truncline = content[:self.MAX_CHUNK_SIZE]
156         while truncline:
157             try:
158                 truncline.decode('utf-8')
159                 break
160             except UnicodeDecodeError:
161                 truncline = truncline[:-1]
162 
163         # then find the beginning of the next line
164         i = content.find('\n', self.MAX_CHUNK_SIZE)
165         if i == -1:
166             return truncline, None
167         else:
168             return truncline, content[i + 1:]
169 
170     def finishLog(self, logid):
171         def thd(conn):
172             tbl = self.db.model.logs
173             q = tbl.update(whereclause=(tbl.c.id == logid))
174             conn.execute(q, complete=1)
175         return self.db.pool.do(thd)
176 
177     def compressLog(self, logid):
178         # TODO: compression not supported yet
179         return defer.succeed(None)
180 
181     def _logdictFromRow(self, row):
182         rv = dict(row)
183         rv['complete'] = bool(rv['complete'])
184         return rv
185
```
--- 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/master/buildbot/db/logs.py b/master/buildbot/db/logs.py
--- a/master/buildbot/db/logs.py
+++ b/master/buildbot/db/logs.py
@@ -80,7 +80,7 @@
                     idx = len(content) + 1
                     count = row.last_line - last_line
                     for _ in xrange(count):
-                        idx = content.rindex('\n', 0, idx - 1)
+                        idx = content.rindex('\n', 0, idx)
                     content = content[:idx]
                 rv.append(content)
             return u'\n'.join(rv) + u'\n' if rv else u''

{"golden_diff": "diff --git a/master/buildbot/db/logs.py b/master/buildbot/db/logs.py\n--- a/master/buildbot/db/logs.py\n+++ b/master/buildbot/db/logs.py\n@@ -80,7 +80,7 @@\n                     idx = len(content) + 1\n                     count = row.last_line - last_line\n                     for _ in xrange(count):\n-                        idx = content.rindex('\\n', 0, idx - 1)\n+                        idx = content.rindex('\\n', 0, idx)\n                     content = content[:idx]\n                 rv.append(content)\n             return u'\\n'.join(rv) + u'\\n' if rv else u''\n", "issue": "Correction of cfg-www.rst documentation\nchange StopBuildEndpointMatcher(role=\"owner\") to\r\nutil.StopBuildEndpointMatcher(role=\"owner\")\r\n\r\nissue ref: #3043\r\n\r\nSigned-off-by: desurd <david.desurmont@gmail.com>\r\n\r\n## Remove this paragraph\r\nPlease have a look at our developer documentation before submitting your Pull Request.\r\n\r\nhttp://trac.buildbot.net/wiki/Development\r\nAnd especially:\r\nhttp://trac.buildbot.net/wiki/SubmittingPatches\r\n\r\n## Contributor Checklist:\r\n\r\n* [ ] I have updated the unit tests\r\n* [ ] I have created a file in the master/buildbot/newsfragment directory (and read the README.txt in that directory)\r\n* [ ] I have updated the appropriate documentation\r\n\r\n\n", "before_files": [{"content": "# This file is part of Buildbot.  Buildbot is free software: you can\n# redistribute it and/or modify it under the terms of the GNU General Public\n# License as published by the Free Software Foundation, version 2.\n#\n# This program is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\n# details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51\n# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Copyright Buildbot Team Members\n\nimport sqlalchemy as sa\n\nfrom buildbot.db import base\nfrom twisted.internet import defer\nfrom twisted.python import log\n\n\nclass LogsConnectorComponent(base.DBConnectorComponent):\n\n    # Postgres and MySQL will both allow bigger sizes than this.  The limit\n    # for MySQL appears to be max_packet_size (default 1M).\n    MAX_CHUNK_SIZE = 65536\n\n    def _getLog(self, whereclause):\n        def thd(conn):\n            q = self.db.model.logs.select(whereclause=whereclause)\n            res = conn.execute(q)\n            row = res.fetchone()\n\n            rv = None\n            if row:\n                rv = self._logdictFromRow(row)\n            res.close()\n            return rv\n        return self.db.pool.do(thd)\n\n    def getLog(self, logid):\n        return self._getLog(self.db.model.logs.c.id == logid)\n\n    def getLogBySlug(self, stepid, slug):\n        tbl = self.db.model.logs\n        return self._getLog((tbl.c.slug == slug) & (tbl.c.stepid == stepid))\n\n    def getLogs(self, stepid):\n        def thd(conn):\n            tbl = self.db.model.logs\n            q = tbl.select()\n            q = q.where(tbl.c.stepid == stepid)\n            q = q.order_by(tbl.c.id)\n            res = conn.execute(q)\n            return [self._logdictFromRow(row) for row in res.fetchall()]\n        return self.db.pool.do(thd)\n\n    def getLogLines(self, logid, first_line, last_line):\n        def thd(conn):\n            # get a set of chunks that completely cover the requested range\n            tbl = self.db.model.logchunks\n            q = sa.select([tbl.c.first_line, tbl.c.last_line,\n                           tbl.c.content, tbl.c.compressed])\n            q = q.where(tbl.c.logid == logid)\n            q = q.where(tbl.c.first_line <= last_line)\n            q = q.where(tbl.c.last_line >= first_line)\n            q = q.order_by(tbl.c.first_line)\n            rv = []\n            for row in conn.execute(q):\n                assert not row.compressed, \"compressed rows not supported yet\"\n                content = row.content.decode('utf-8')\n                if row.first_line < first_line:\n                    idx = -1\n                    count = first_line - row.first_line\n                    for _ in xrange(count):\n                        idx = content.index('\\n', idx + 1)\n                    content = content[idx + 1:]\n                if row.last_line > last_line:\n                    idx = len(content) + 1\n                    count = row.last_line - last_line\n                    for _ in xrange(count):\n                        idx = content.rindex('\\n', 0, idx - 1)\n                    content = content[:idx]\n                rv.append(content)\n            return u'\\n'.join(rv) + u'\\n' if rv else u''\n        return self.db.pool.do(thd)\n\n    def addLog(self, stepid, name, slug, type):\n        assert type in 'tsh', \"Log type must be one of t, s, or h\"\n\n        def thd(conn):\n            try:\n                r = conn.execute(self.db.model.logs.insert(),\n                                 dict(name=name, slug=slug, stepid=stepid,\n                                      complete=0, num_lines=0, type=type))\n                return r.inserted_primary_key[0]\n            except (sa.exc.IntegrityError, sa.exc.ProgrammingError):\n                raise KeyError(\n                    \"log with slug '%r' already exists in this step\" % (slug,))\n        return self.db.pool.do(thd)\n\n    def appendLog(self, logid, content):\n        # check for trailing newline and strip it for storage -- chunks omit\n        # the trailing newline\n        assert content[-1] == u'\\n'\n        content = content[:-1]\n\n        def thd(conn):\n            q = sa.select([self.db.model.logs.c.num_lines])\n            q = q.where(self.db.model.logs.c.id == logid)\n            res = conn.execute(q)\n            row = res.fetchone()\n            res.close()\n            if not row:\n                return  # ignore a missing log\n\n            # Break the content up into chunks.  This takes advantage of the\n            # fact that no character but u'\\n' maps to b'\\n' in UTF-8.\n\n            first_line = chunk_first_line = row[0]\n            remaining = content.encode('utf-8')\n            while remaining:\n                chunk, remaining = self._splitBigChunk(remaining, logid)\n\n                last_line = chunk_first_line + chunk.count('\\n')\n                conn.execute(self.db.model.logchunks.insert(),\n                             dict(logid=logid, first_line=chunk_first_line,\n                                  last_line=last_line, content=chunk,\n                                  compressed=0))\n                chunk_first_line = last_line + 1\n\n            conn.execute(self.db.model.logs.update(whereclause=(self.db.model.logs.c.id == logid)),\n                         num_lines=last_line + 1)\n            return (first_line, last_line)\n        return self.db.pool.do(thd)\n\n    def _splitBigChunk(self, content, logid):\n        \"\"\"\n        Split CONTENT on a line boundary into a prefix smaller than 64k and\n        a suffix containing the remainder, omitting the splitting newline.\n        \"\"\"\n        # if it's small enough, just return it\n        if len(content) < self.MAX_CHUNK_SIZE:\n            return content, None\n\n        # find the last newline before the limit\n        i = content.rfind('\\n', 0, self.MAX_CHUNK_SIZE)\n        if i != -1:\n            return content[:i], content[i + 1:]\n\n        log.msg('truncating long line for log %d' % logid)\n\n        # first, truncate this down to something that decodes correctly\n        truncline = content[:self.MAX_CHUNK_SIZE]\n        while truncline:\n            try:\n                truncline.decode('utf-8')\n                break\n            except UnicodeDecodeError:\n                truncline = truncline[:-1]\n\n        # then find the beginning of the next line\n        i = content.find('\\n', self.MAX_CHUNK_SIZE)\n        if i == -1:\n            return truncline, None\n        else:\n            return truncline, content[i + 1:]\n\n    def finishLog(self, logid):\n        def thd(conn):\n            tbl = self.db.model.logs\n            q = tbl.update(whereclause=(tbl.c.id == logid))\n            conn.execute(q, complete=1)\n        return self.db.pool.do(thd)\n\n    def compressLog(self, logid):\n        # TODO: compression not supported yet\n        return defer.succeed(None)\n\n    def _logdictFromRow(self, row):\n        rv = dict(row)\n        rv['complete'] = bool(rv['complete'])\n        return rv\n", "path": "master/buildbot/db/logs.py"}], "after_files": [{"content": "# This file is part of Buildbot.  Buildbot is free software: you can\n# redistribute it and/or modify it under the terms of the GNU General Public\n# License as published by the Free Software Foundation, version 2.\n#\n# This program is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\n# details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51\n# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Copyright Buildbot Team Members\n\nimport sqlalchemy as sa\n\nfrom buildbot.db import base\nfrom twisted.internet import defer\nfrom twisted.python import log\n\n\nclass LogsConnectorComponent(base.DBConnectorComponent):\n\n    # Postgres and MySQL will both allow bigger sizes than this.  The limit\n    # for MySQL appears to be max_packet_size (default 1M).\n    MAX_CHUNK_SIZE = 65536\n\n    def _getLog(self, whereclause):\n        def thd(conn):\n            q = self.db.model.logs.select(whereclause=whereclause)\n            res = conn.execute(q)\n            row = res.fetchone()\n\n            rv = None\n            if row:\n                rv = self._logdictFromRow(row)\n            res.close()\n            return rv\n        return self.db.pool.do(thd)\n\n    def getLog(self, logid):\n        return self._getLog(self.db.model.logs.c.id == logid)\n\n    def getLogBySlug(self, stepid, slug):\n        tbl = self.db.model.logs\n        return self._getLog((tbl.c.slug == slug) & (tbl.c.stepid == stepid))\n\n    def getLogs(self, stepid):\n        def thd(conn):\n            tbl = self.db.model.logs\n            q = tbl.select()\n            q = q.where(tbl.c.stepid == stepid)\n            q = q.order_by(tbl.c.id)\n            res = conn.execute(q)\n            return [self._logdictFromRow(row) for row in res.fetchall()]\n        return self.db.pool.do(thd)\n\n    def getLogLines(self, logid, first_line, last_line):\n        def thd(conn):\n            # get a set of chunks that completely cover the requested range\n            tbl = self.db.model.logchunks\n            q = sa.select([tbl.c.first_line, tbl.c.last_line,\n                           tbl.c.content, tbl.c.compressed])\n            q = q.where(tbl.c.logid == logid)\n            q = q.where(tbl.c.first_line <= last_line)\n            q = q.where(tbl.c.last_line >= first_line)\n            q = q.order_by(tbl.c.first_line)\n            rv = []\n            for row in conn.execute(q):\n                assert not row.compressed, \"compressed rows not supported yet\"\n                content = row.content.decode('utf-8')\n                if row.first_line < first_line:\n                    idx = -1\n                    count = first_line - row.first_line\n                    for _ in xrange(count):\n                        idx = content.index('\\n', idx + 1)\n                    content = content[idx + 1:]\n                if row.last_line > last_line:\n                    idx = len(content) + 1\n                    count = row.last_line - last_line\n                    for _ in xrange(count):\n                        idx = content.rindex('\\n', 0, idx)\n                    content = content[:idx]\n                rv.append(content)\n            return u'\\n'.join(rv) + u'\\n' if rv else u''\n        return self.db.pool.do(thd)\n\n    def addLog(self, stepid, name, slug, type):\n        assert type in 'tsh', \"Log type must be one of t, s, or h\"\n\n        def thd(conn):\n            try:\n                r = conn.execute(self.db.model.logs.insert(),\n                                 dict(name=name, slug=slug, stepid=stepid,\n                                      complete=0, num_lines=0, type=type))\n                return r.inserted_primary_key[0]\n            except (sa.exc.IntegrityError, sa.exc.ProgrammingError):\n                raise KeyError(\n                    \"log with slug '%r' already exists in this step\" % (slug,))\n        return self.db.pool.do(thd)\n\n    def appendLog(self, logid, content):\n        # check for trailing newline and strip it for storage -- chunks omit\n        # the trailing newline\n        assert content[-1] == u'\\n'\n        content = content[:-1]\n\n        def thd(conn):\n            q = sa.select([self.db.model.logs.c.num_lines])\n            q = q.where(self.db.model.logs.c.id == logid)\n            res = conn.execute(q)\n            row = res.fetchone()\n            res.close()\n            if not row:\n                return  # ignore a missing log\n\n            # Break the content up into chunks.  This takes advantage of the\n            # fact that no character but u'\\n' maps to b'\\n' in UTF-8.\n\n            first_line = chunk_first_line = row[0]\n            remaining = content.encode('utf-8')\n            while remaining:\n                chunk, remaining = self._splitBigChunk(remaining, logid)\n\n                last_line = chunk_first_line + chunk.count('\\n')\n                conn.execute(self.db.model.logchunks.insert(),\n                             dict(logid=logid, first_line=chunk_first_line,\n                                  last_line=last_line, content=chunk,\n                                  compressed=0))\n                chunk_first_line = last_line + 1\n\n            conn.execute(self.db.model.logs.update(whereclause=(self.db.model.logs.c.id == logid)),\n                         num_lines=last_line + 1)\n            return (first_line, last_line)\n        return self.db.pool.do(thd)\n\n    def _splitBigChunk(self, content, logid):\n        \"\"\"\n        Split CONTENT on a line boundary into a prefix smaller than 64k and\n        a suffix containing the remainder, omitting the splitting newline.\n        \"\"\"\n        # if it's small enough, just return it\n        if len(content) < self.MAX_CHUNK_SIZE:\n            return content, None\n\n        # find the last newline before the limit\n        i = content.rfind('\\n', 0, self.MAX_CHUNK_SIZE)\n        if i != -1:\n            return content[:i], content[i + 1:]\n\n        log.msg('truncating long line for log %d' % logid)\n\n        # first, truncate this down to something that decodes correctly\n        truncline = content[:self.MAX_CHUNK_SIZE]\n        while truncline:\n            try:\n                truncline.decode('utf-8')\n                break\n            except UnicodeDecodeError:\n                truncline = truncline[:-1]\n\n        # then find the beginning of the next line\n        i = content.find('\\n', self.MAX_CHUNK_SIZE)\n        if i == -1:\n            return truncline, None\n        else:\n            return truncline, content[i + 1:]\n\n    def finishLog(self, logid):\n        def thd(conn):\n            tbl = self.db.model.logs\n            q = tbl.update(whereclause=(tbl.c.id == logid))\n            conn.execute(q, complete=1)\n        return self.db.pool.do(thd)\n\n    def compressLog(self, logid):\n        # TODO: compression not supported yet\n        return defer.succeed(None)\n\n    def _logdictFromRow(self, row):\n        rv = dict(row)\n        rv['complete'] = bool(rv['complete'])\n        return rv\n", "path": "master/buildbot/db/logs.py"}]}