prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Remove `streamlink.plugin.api.utils.itertags`
  [`streamlink.plugin.api.utils.itertags`](https://github.com/streamlink/streamlink/blob/3.2.0/src/streamlink/plugin/api/utils.py#L16-L28) has become obsolete ever since `lxml` was added as a dependency to Streamlink for parsing HTML.
  
  `itertags` is a hacky implementation via regexes, which is not only slow, but it's also impossible to correctly parse HTML nodes with regular expressions, so it shouldn't be used when better and much faster solutions are available. It also always requires unescaping tag values, which is annoying.
  
  We've already updated and replaced lots of plugins which were previously using it, but there are still some left:
  ```
  $ GIT_PAGER=cat git grep -F 'from streamlink.plugin.api.utils import' a1ce471f
  a1ce471f:src/streamlink/plugins/cdnbg.py:from streamlink.plugin.api.utils import itertags
  a1ce471f:src/streamlink/plugins/facebook.py:from streamlink.plugin.api.utils import itertags
  a1ce471f:src/streamlink/plugins/funimationnow.py:from streamlink.plugin.api.utils import itertags
  a1ce471f:src/streamlink/plugins/senategov.py:from streamlink.plugin.api.utils import itertags
  a1ce471f:src/streamlink/plugins/vrtbe.py:from streamlink.plugin.api.utils import itertags
  a1ce471f:tests/test_plugin_utils.py:from streamlink.plugin.api.utils import itertags
  ```
  
  - [x] cdnbg
  - [x] facebook
  - [x] funimationnow
  - [x] senategov
  - [x] vrtbe
  
  Once every last plugin has been updated, the entire `streamlink.plugin.api.utils` module can be removed, as it only contains the `itertags` function and some other useless export aliases which are not even used anymore in Streamlink's codebase.
  
  If we care about plugin-API stability (something which has never been discussed), removing this would be considered a breaking change. Since we've just dropped py36, that's something which could be included in the 4.0.0 release.
  
  </issue>
  <code>
  [start of src/streamlink/plugin/api/utils.py]
  1 """Useful wrappers and other tools."""
  2 import re
  3 from collections import namedtuple
  4 
  5 from streamlink.utils.parse import parse_json, parse_qsd as parse_query, parse_xml
  6 
  7 __all__ = ["parse_json", "parse_xml", "parse_query"]
  8 
  9 
  10 tag_re = re.compile(r'''(?=<(?P<tag>[a-zA-Z]+)(?P<attr>.*?)(?P<end>/)?>(?:(?P<inner>.*?)</\s*(?P=tag)\s*>)?)''',
  11                     re.MULTILINE | re.DOTALL)
  12 attr_re = re.compile(r'''\s*(?P<key>[\w-]+)\s*(?:=\s*(?P<quote>["']?)(?P<value>.*?)(?P=quote)\s*)?''')
  13 Tag = namedtuple("Tag", "tag attributes text")
  14 
  15 
  16 def itertags(html, tag):
  17     """
  18     Brute force regex based HTML tag parser. This is a rough-and-ready searcher to find HTML tags when
  19     standards compliance is not required. Will find tags that are commented out, or inside script tag etc.
  20 
  21     :param html: HTML page
  22     :param tag: tag name to find
  23     :return: generator with Tags
  24     """
  25     for match in tag_re.finditer(html):
  26         if match.group("tag") == tag:
  27             attrs = {a.group("key").lower(): a.group("value") for a in attr_re.finditer(match.group("attr"))}
  28             yield Tag(match.group("tag"), attrs, match.group("inner"))
  29
  [end of src/streamlink/plugin/api/utils.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/src/streamlink/plugin/api/utils.py b/src/streamlink/plugin/api/utils.py
  deleted file mode 100644
  --- a/src/streamlink/plugin/api/utils.py
  +++ /dev/null
  @@ -1,28 +0,0 @@
  -"""Useful wrappers and other tools."""
  -import re
  -from collections import namedtuple
  -
  -from streamlink.utils.parse import parse_json, parse_qsd as parse_query, parse_xml
  -
  -__all__ = ["parse_json", "parse_xml", "parse_query"]
  -
  -
  -tag_re = re.compile(r'''(?=<(?P<tag>[a-zA-Z]+)(?P<attr>.*?)(?P<end>/)?>(?:(?P<inner>.*?)</\s*(?P=tag)\s*>)?)''',
  -                    re.MULTILINE | re.DOTALL)
  -attr_re = re.compile(r'''\s*(?P<key>[\w-]+)\s*(?:=\s*(?P<quote>["']?)(?P<value>.*?)(?P=quote)\s*)?''')
  -Tag = namedtuple("Tag", "tag attributes text")
  -
  -
  -def itertags(html, tag):
  -    """
  -    Brute force regex based HTML tag parser. This is a rough-and-ready searcher to find HTML tags when
  -    standards compliance is not required. Will find tags that are commented out, or inside script tag etc.
  -
  -    :param html: HTML page
  -    :param tag: tag name to find
  -    :return: generator with Tags
  -    """
  -    for match in tag_re.finditer(html):
  -        if match.group("tag") == tag:
  -            attrs = {a.group("key").lower(): a.group("value") for a in attr_re.finditer(match.group("attr"))}
  -            yield Tag(match.group("tag"), attrs, match.group("inner"))
  
verification_info: {"golden_diff": "diff --git a/src/streamlink/plugin/api/utils.py b/src/streamlink/plugin/api/utils.py\ndeleted file mode 100644\n--- a/src/streamlink/plugin/api/utils.py\n+++ /dev/null\n@@ -1,28 +0,0 @@\n-\"\"\"Useful wrappers and other tools.\"\"\"\n-import re\n-from collections import namedtuple\n-\n-from streamlink.utils.parse import parse_json, parse_qsd as parse_query, parse_xml\n-\n-__all__ = [\"parse_json\", \"parse_xml\", \"parse_query\"]\n-\n-\n-tag_re = re.compile(r'''(?=<(?P<tag>[a-zA-Z]+)(?P<attr>.*?)(?P<end>/)?>(?:(?P<inner>.*?)</\\s*(?P=tag)\\s*>)?)''',\n-                    re.MULTILINE | re.DOTALL)\n-attr_re = re.compile(r'''\\s*(?P<key>[\\w-]+)\\s*(?:=\\s*(?P<quote>[\"']?)(?P<value>.*?)(?P=quote)\\s*)?''')\n-Tag = namedtuple(\"Tag\", \"tag attributes text\")\n-\n-\n-def itertags(html, tag):\n-    \"\"\"\n-    Brute force regex based HTML tag parser. This is a rough-and-ready searcher to find HTML tags when\n-    standards compliance is not required. Will find tags that are commented out, or inside script tag etc.\n-\n-    :param html: HTML page\n-    :param tag: tag name to find\n-    :return: generator with Tags\n-    \"\"\"\n-    for match in tag_re.finditer(html):\n-        if match.group(\"tag\") == tag:\n-            attrs = {a.group(\"key\").lower(): a.group(\"value\") for a in attr_re.finditer(match.group(\"attr\"))}\n-            yield Tag(match.group(\"tag\"), attrs, match.group(\"inner\"))\n", "issue": "Remove `streamlink.plugin.api.utils.itertags`\n[`streamlink.plugin.api.utils.itertags`](https://github.com/streamlink/streamlink/blob/3.2.0/src/streamlink/plugin/api/utils.py#L16-L28) has become obsolete ever since `lxml` was added as a dependency to Streamlink for parsing HTML.\r\n\r\n`itertags` is a hacky implementation via regexes, which is not only slow, but it's also impossible to correctly parse HTML nodes with regular expressions, so it shouldn't be used when better and much faster solutions are available. It also always requires unescaping tag values, which is annoying.\r\n\r\nWe've already updated and replaced lots of plugins which were previously using it, but there are still some left:\r\n```\r\n$ GIT_PAGER=cat git grep -F 'from streamlink.plugin.api.utils import' a1ce471f\r\na1ce471f:src/streamlink/plugins/cdnbg.py:from streamlink.plugin.api.utils import itertags\r\na1ce471f:src/streamlink/plugins/facebook.py:from streamlink.plugin.api.utils import itertags\r\na1ce471f:src/streamlink/plugins/funimationnow.py:from streamlink.plugin.api.utils import itertags\r\na1ce471f:src/streamlink/plugins/senategov.py:from streamlink.plugin.api.utils import itertags\r\na1ce471f:src/streamlink/plugins/vrtbe.py:from streamlink.plugin.api.utils import itertags\r\na1ce471f:tests/test_plugin_utils.py:from streamlink.plugin.api.utils import itertags\r\n```\r\n\r\n- [x] cdnbg\r\n- [x] facebook\r\n- [x] funimationnow\r\n- [x] senategov\r\n- [x] vrtbe\r\n\r\nOnce every last plugin has been updated, the entire `streamlink.plugin.api.utils` module can be removed, as it only contains the `itertags` function and some other useless export aliases which are not even used anymore in Streamlink's codebase.\r\n\r\nIf we care about plugin-API stability (something which has never been discussed), removing this would be considered a breaking change. Since we've just dropped py36, that's something which could be included in the 4.0.0 release.\n", "before_files": [{"content": "\"\"\"Useful wrappers and other tools.\"\"\"\nimport re\nfrom collections import namedtuple\n\nfrom streamlink.utils.parse import parse_json, parse_qsd as parse_query, parse_xml\n\n__all__ = [\"parse_json\", \"parse_xml\", \"parse_query\"]\n\n\ntag_re = re.compile(r'''(?=<(?P<tag>[a-zA-Z]+)(?P<attr>.*?)(?P<end>/)?>(?:(?P<inner>.*?)</\\s*(?P=tag)\\s*>)?)''',\n                    re.MULTILINE | re.DOTALL)\nattr_re = re.compile(r'''\\s*(?P<key>[\\w-]+)\\s*(?:=\\s*(?P<quote>[\"']?)(?P<value>.*?)(?P=quote)\\s*)?''')\nTag = namedtuple(\"Tag\", \"tag attributes text\")\n\n\ndef itertags(html, tag):\n    \"\"\"\n    Brute force regex based HTML tag parser. This is a rough-and-ready searcher to find HTML tags when\n    standards compliance is not required. Will find tags that are commented out, or inside script tag etc.\n\n    :param html: HTML page\n    :param tag: tag name to find\n    :return: generator with Tags\n    \"\"\"\n    for match in tag_re.finditer(html):\n        if match.group(\"tag\") == tag:\n            attrs = {a.group(\"key\").lower(): a.group(\"value\") for a in attr_re.finditer(match.group(\"attr\"))}\n            yield Tag(match.group(\"tag\"), attrs, match.group(\"inner\"))\n", "path": "src/streamlink/plugin/api/utils.py"}]}