We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
New Microsoft Edge User Agent
## Background
Microsoft Edge now based on Chromium and the user agent string is updated.
`Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68`

## Simple Code
```python
@app.route('/browser')
def browser():
    from flask import request
    ua = request.user_agent
    return jsonify({
        'browser': ua.browser,
        'platform': ua.platform,
        'user_agent': ua.string,
        'version': ua.version,
    })
```

## Expected Result
```json
{
  "browser": "edge", 
  "platform": "windows", 
  "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68", 
  "version": "81.0.416.68"
}
```

| Key | Value |
| --- | --- |
| browser | **edge** |
| platform | windows |
| user_agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68 |
| version | **81.0.416.68** |


## Actual Result
```json
{
  "browser": "chrome", 
  "platform": "windows", 
  "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68", 
  "version": "81.0.4044.129"
}
```

| Key | Value |
| --- | --- |
| browser | **chrome** |
| platform | windows |
| user_agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68 |
| version | **81.0.4044.129** |

## Environment
- Windows 10 Pro 1909
- Python 3.6.6
- Werkzeug 0.16.1
- Flask 1.1.1

### Related Issues
#818, #1556

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/werkzeug/useragents.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 """
3     werkzeug.useragents
4     ~~~~~~~~~~~~~~~~~~~
5 
6     This module provides a helper to inspect user agent strings.  This module
7     is far from complete but should work for most of the currently available
8     browsers.
9 
10 
11     :copyright: 2007 Pallets
12     :license: BSD-3-Clause
13 """
14 import re
15 
16 
17 class UserAgentParser(object):
18     """A simple user agent parser.  Used by the `UserAgent`."""
19 
20     platforms = (
21         (" cros ", "chromeos"),
22         ("iphone|ios", "iphone"),
23         ("ipad", "ipad"),
24         (r"darwin|mac|os\s*x", "macos"),
25         ("win", "windows"),
26         (r"android", "android"),
27         ("netbsd", "netbsd"),
28         ("openbsd", "openbsd"),
29         ("freebsd", "freebsd"),
30         ("dragonfly", "dragonflybsd"),
31         ("(sun|i86)os", "solaris"),
32         (r"x11|lin(\b|ux)?", "linux"),
33         (r"nintendo\s+wii", "wii"),
34         ("irix", "irix"),
35         ("hp-?ux", "hpux"),
36         ("aix", "aix"),
37         ("sco|unix_sv", "sco"),
38         ("bsd", "bsd"),
39         ("amiga", "amiga"),
40         ("blackberry|playbook", "blackberry"),
41         ("symbian", "symbian"),
42     )
43     browsers = (
44         ("googlebot", "google"),
45         ("msnbot", "msn"),
46         ("yahoo", "yahoo"),
47         ("ask jeeves", "ask"),
48         (r"aol|america\s+online\s+browser", "aol"),
49         (r"opera|opr", "opera"),
50         ("edge", "edge"),
51         ("chrome|crios", "chrome"),
52         ("seamonkey", "seamonkey"),
53         ("firefox|firebird|phoenix|iceweasel", "firefox"),
54         ("galeon", "galeon"),
55         ("safari|version", "safari"),
56         ("webkit", "webkit"),
57         ("camino", "camino"),
58         ("konqueror", "konqueror"),
59         ("k-meleon", "kmeleon"),
60         ("netscape", "netscape"),
61         (r"msie|microsoft\s+internet\s+explorer|trident/.+? rv:", "msie"),
62         ("lynx", "lynx"),
63         ("links", "links"),
64         ("Baiduspider", "baidu"),
65         ("bingbot", "bing"),
66         ("mozilla", "mozilla"),
67     )
68 
69     _browser_version_re = r"(?:%s)[/\sa-z(]*(\d+[.\da-z]+)?"
70     _language_re = re.compile(
71         r"(?:;\s*|\s+)(\b\w{2}\b(?:-\b\w{2}\b)?)\s*;|"
72         r"(?:\(|\[|;)\s*(\b\w{2}\b(?:-\b\w{2}\b)?)\s*(?:\]|\)|;)"
73     )
74 
75     def __init__(self):
76         self.platforms = [(b, re.compile(a, re.I)) for a, b in self.platforms]
77         self.browsers = [
78             (b, re.compile(self._browser_version_re % a, re.I))
79             for a, b in self.browsers
80         ]
81 
82     def __call__(self, user_agent):
83         for platform, regex in self.platforms:  # noqa: B007
84             match = regex.search(user_agent)
85             if match is not None:
86                 break
87         else:
88             platform = None
89         for browser, regex in self.browsers:  # noqa: B007
90             match = regex.search(user_agent)
91             if match is not None:
92                 version = match.group(1)
93                 break
94         else:
95             browser = version = None
96         match = self._language_re.search(user_agent)
97         if match is not None:
98             language = match.group(1) or match.group(2)
99         else:
100             language = None
101         return platform, browser, version, language
102 
103 
104 class UserAgent(object):
105     """Represents a user agent.  Pass it a WSGI environment or a user agent
106     string and you can inspect some of the details from the user agent
107     string via the attributes.  The following attributes exist:
108 
109     .. attribute:: string
110 
111        the raw user agent string
112 
113     .. attribute:: platform
114 
115        the browser platform. ``None`` if not recognized.
116        The following platforms are currently recognized:
117 
118        -   `aix`
119        -   `amiga`
120        -   `android`
121        -   `blackberry`
122        -   `bsd`
123        -   `chromeos`
124        -   `dragonflybsd`
125        -   `freebsd`
126        -   `hpux`
127        -   `ipad`
128        -   `iphone`
129        -   `irix`
130        -   `linux`
131        -   `macos`
132        -   `netbsd`
133        -   `openbsd`
134        -   `sco`
135        -   `solaris`
136        -   `symbian`
137        -   `wii`
138        -   `windows`
139 
140     .. attribute:: browser
141 
142         the name of the browser. ``None`` if not recognized.
143         The following browsers are currently recognized:
144 
145         -   `aol` *
146         -   `ask` *
147         -   `baidu` *
148         -   `bing` *
149         -   `camino`
150         -   `chrome`
151         -   `edge`
152         -   `firefox`
153         -   `galeon`
154         -   `google` *
155         -   `kmeleon`
156         -   `konqueror`
157         -   `links`
158         -   `lynx`
159         -   `mozilla`
160         -   `msie`
161         -   `msn`
162         -   `netscape`
163         -   `opera`
164         -   `safari`
165         -   `seamonkey`
166         -   `webkit`
167         -   `yahoo` *
168 
169         (Browsers marked with a star (``*``) are crawlers.)
170 
171     .. attribute:: version
172 
173         the version of the browser. ``None`` if not recognized.
174 
175     .. attribute:: language
176 
177         the language of the browser. ``None`` if not recognized.
178     """
179 
180     _parser = UserAgentParser()
181 
182     def __init__(self, environ_or_string):
183         if isinstance(environ_or_string, dict):
184             environ_or_string = environ_or_string.get("HTTP_USER_AGENT", "")
185         self.string = environ_or_string
186         self.platform, self.browser, self.version, self.language = self._parser(
187             environ_or_string
188         )
189 
190     def to_header(self):
191         return self.string
192 
193     def __str__(self):
194         return self.string
195 
196     def __nonzero__(self):
197         return bool(self.browser)
198 
199     __bool__ = __nonzero__
200 
201     def __repr__(self):
202         return "<%s %r/%s>" % (self.__class__.__name__, self.browser, self.version)
203
```
--- 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/src/werkzeug/useragents.py b/src/werkzeug/useragents.py
--- a/src/werkzeug/useragents.py
+++ b/src/werkzeug/useragents.py
@@ -47,7 +47,7 @@
         ("ask jeeves", "ask"),
         (r"aol|america\s+online\s+browser", "aol"),
         (r"opera|opr", "opera"),
-        ("edge", "edge"),
+        ("edge|edg", "edge"),
         ("chrome|crios", "chrome"),
         ("seamonkey", "seamonkey"),
         ("firefox|firebird|phoenix|iceweasel", "firefox"),

{"golden_diff": "diff --git a/src/werkzeug/useragents.py b/src/werkzeug/useragents.py\n--- a/src/werkzeug/useragents.py\n+++ b/src/werkzeug/useragents.py\n@@ -47,7 +47,7 @@\n         (\"ask jeeves\", \"ask\"),\n         (r\"aol|america\\s+online\\s+browser\", \"aol\"),\n         (r\"opera|opr\", \"opera\"),\n-        (\"edge\", \"edge\"),\n+        (\"edge|edg\", \"edge\"),\n         (\"chrome|crios\", \"chrome\"),\n         (\"seamonkey\", \"seamonkey\"),\n         (\"firefox|firebird|phoenix|iceweasel\", \"firefox\"),\n", "issue": "New Microsoft Edge User Agent\n## Background\r\nMicrosoft Edge now based on Chromium and the user agent string is updated.\r\n`Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68`\r\n\r\n## Simple Code\r\n```python\r\n@app.route('/browser')\r\ndef browser():\r\n    from flask import request\r\n    ua = request.user_agent\r\n    return jsonify({\r\n        'browser': ua.browser,\r\n        'platform': ua.platform,\r\n        'user_agent': ua.string,\r\n        'version': ua.version,\r\n    })\r\n```\r\n\r\n## Expected Result\r\n```json\r\n{\r\n  \"browser\": \"edge\", \r\n  \"platform\": \"windows\", \r\n  \"user_agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68\", \r\n  \"version\": \"81.0.416.68\"\r\n}\r\n```\r\n\r\n| Key | Value |\r\n| --- | --- |\r\n| browser | **edge** |\r\n| platform | windows |\r\n| user_agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68 |\r\n| version | **81.0.416.68** |\r\n\r\n\r\n## Actual Result\r\n```json\r\n{\r\n  \"browser\": \"chrome\", \r\n  \"platform\": \"windows\", \r\n  \"user_agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68\", \r\n  \"version\": \"81.0.4044.129\"\r\n}\r\n```\r\n\r\n| Key | Value |\r\n| --- | --- |\r\n| browser | **chrome** |\r\n| platform | windows |\r\n| user_agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68 |\r\n| version | **81.0.4044.129** |\r\n\r\n## Environment\r\n- Windows 10 Pro 1909\r\n- Python 3.6.6\r\n- Werkzeug 0.16.1\r\n- Flask 1.1.1\r\n\r\n### Related Issues\r\n#818, #1556\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\n    werkzeug.useragents\n    ~~~~~~~~~~~~~~~~~~~\n\n    This module provides a helper to inspect user agent strings.  This module\n    is far from complete but should work for most of the currently available\n    browsers.\n\n\n    :copyright: 2007 Pallets\n    :license: BSD-3-Clause\n\"\"\"\nimport re\n\n\nclass UserAgentParser(object):\n    \"\"\"A simple user agent parser.  Used by the `UserAgent`.\"\"\"\n\n    platforms = (\n        (\" cros \", \"chromeos\"),\n        (\"iphone|ios\", \"iphone\"),\n        (\"ipad\", \"ipad\"),\n        (r\"darwin|mac|os\\s*x\", \"macos\"),\n        (\"win\", \"windows\"),\n        (r\"android\", \"android\"),\n        (\"netbsd\", \"netbsd\"),\n        (\"openbsd\", \"openbsd\"),\n        (\"freebsd\", \"freebsd\"),\n        (\"dragonfly\", \"dragonflybsd\"),\n        (\"(sun|i86)os\", \"solaris\"),\n        (r\"x11|lin(\\b|ux)?\", \"linux\"),\n        (r\"nintendo\\s+wii\", \"wii\"),\n        (\"irix\", \"irix\"),\n        (\"hp-?ux\", \"hpux\"),\n        (\"aix\", \"aix\"),\n        (\"sco|unix_sv\", \"sco\"),\n        (\"bsd\", \"bsd\"),\n        (\"amiga\", \"amiga\"),\n        (\"blackberry|playbook\", \"blackberry\"),\n        (\"symbian\", \"symbian\"),\n    )\n    browsers = (\n        (\"googlebot\", \"google\"),\n        (\"msnbot\", \"msn\"),\n        (\"yahoo\", \"yahoo\"),\n        (\"ask jeeves\", \"ask\"),\n        (r\"aol|america\\s+online\\s+browser\", \"aol\"),\n        (r\"opera|opr\", \"opera\"),\n        (\"edge\", \"edge\"),\n        (\"chrome|crios\", \"chrome\"),\n        (\"seamonkey\", \"seamonkey\"),\n        (\"firefox|firebird|phoenix|iceweasel\", \"firefox\"),\n        (\"galeon\", \"galeon\"),\n        (\"safari|version\", \"safari\"),\n        (\"webkit\", \"webkit\"),\n        (\"camino\", \"camino\"),\n        (\"konqueror\", \"konqueror\"),\n        (\"k-meleon\", \"kmeleon\"),\n        (\"netscape\", \"netscape\"),\n        (r\"msie|microsoft\\s+internet\\s+explorer|trident/.+? rv:\", \"msie\"),\n        (\"lynx\", \"lynx\"),\n        (\"links\", \"links\"),\n        (\"Baiduspider\", \"baidu\"),\n        (\"bingbot\", \"bing\"),\n        (\"mozilla\", \"mozilla\"),\n    )\n\n    _browser_version_re = r\"(?:%s)[/\\sa-z(]*(\\d+[.\\da-z]+)?\"\n    _language_re = re.compile(\n        r\"(?:;\\s*|\\s+)(\\b\\w{2}\\b(?:-\\b\\w{2}\\b)?)\\s*;|\"\n        r\"(?:\\(|\\[|;)\\s*(\\b\\w{2}\\b(?:-\\b\\w{2}\\b)?)\\s*(?:\\]|\\)|;)\"\n    )\n\n    def __init__(self):\n        self.platforms = [(b, re.compile(a, re.I)) for a, b in self.platforms]\n        self.browsers = [\n            (b, re.compile(self._browser_version_re % a, re.I))\n            for a, b in self.browsers\n        ]\n\n    def __call__(self, user_agent):\n        for platform, regex in self.platforms:  # noqa: B007\n            match = regex.search(user_agent)\n            if match is not None:\n                break\n        else:\n            platform = None\n        for browser, regex in self.browsers:  # noqa: B007\n            match = regex.search(user_agent)\n            if match is not None:\n                version = match.group(1)\n                break\n        else:\n            browser = version = None\n        match = self._language_re.search(user_agent)\n        if match is not None:\n            language = match.group(1) or match.group(2)\n        else:\n            language = None\n        return platform, browser, version, language\n\n\nclass UserAgent(object):\n    \"\"\"Represents a user agent.  Pass it a WSGI environment or a user agent\n    string and you can inspect some of the details from the user agent\n    string via the attributes.  The following attributes exist:\n\n    .. attribute:: string\n\n       the raw user agent string\n\n    .. attribute:: platform\n\n       the browser platform. ``None`` if not recognized.\n       The following platforms are currently recognized:\n\n       -   `aix`\n       -   `amiga`\n       -   `android`\n       -   `blackberry`\n       -   `bsd`\n       -   `chromeos`\n       -   `dragonflybsd`\n       -   `freebsd`\n       -   `hpux`\n       -   `ipad`\n       -   `iphone`\n       -   `irix`\n       -   `linux`\n       -   `macos`\n       -   `netbsd`\n       -   `openbsd`\n       -   `sco`\n       -   `solaris`\n       -   `symbian`\n       -   `wii`\n       -   `windows`\n\n    .. attribute:: browser\n\n        the name of the browser. ``None`` if not recognized.\n        The following browsers are currently recognized:\n\n        -   `aol` *\n        -   `ask` *\n        -   `baidu` *\n        -   `bing` *\n        -   `camino`\n        -   `chrome`\n        -   `edge`\n        -   `firefox`\n        -   `galeon`\n        -   `google` *\n        -   `kmeleon`\n        -   `konqueror`\n        -   `links`\n        -   `lynx`\n        -   `mozilla`\n        -   `msie`\n        -   `msn`\n        -   `netscape`\n        -   `opera`\n        -   `safari`\n        -   `seamonkey`\n        -   `webkit`\n        -   `yahoo` *\n\n        (Browsers marked with a star (``*``) are crawlers.)\n\n    .. attribute:: version\n\n        the version of the browser. ``None`` if not recognized.\n\n    .. attribute:: language\n\n        the language of the browser. ``None`` if not recognized.\n    \"\"\"\n\n    _parser = UserAgentParser()\n\n    def __init__(self, environ_or_string):\n        if isinstance(environ_or_string, dict):\n            environ_or_string = environ_or_string.get(\"HTTP_USER_AGENT\", \"\")\n        self.string = environ_or_string\n        self.platform, self.browser, self.version, self.language = self._parser(\n            environ_or_string\n        )\n\n    def to_header(self):\n        return self.string\n\n    def __str__(self):\n        return self.string\n\n    def __nonzero__(self):\n        return bool(self.browser)\n\n    __bool__ = __nonzero__\n\n    def __repr__(self):\n        return \"<%s %r/%s>\" % (self.__class__.__name__, self.browser, self.version)\n", "path": "src/werkzeug/useragents.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\n    werkzeug.useragents\n    ~~~~~~~~~~~~~~~~~~~\n\n    This module provides a helper to inspect user agent strings.  This module\n    is far from complete but should work for most of the currently available\n    browsers.\n\n\n    :copyright: 2007 Pallets\n    :license: BSD-3-Clause\n\"\"\"\nimport re\n\n\nclass UserAgentParser(object):\n    \"\"\"A simple user agent parser.  Used by the `UserAgent`.\"\"\"\n\n    platforms = (\n        (\" cros \", \"chromeos\"),\n        (\"iphone|ios\", \"iphone\"),\n        (\"ipad\", \"ipad\"),\n        (r\"darwin|mac|os\\s*x\", \"macos\"),\n        (\"win\", \"windows\"),\n        (r\"android\", \"android\"),\n        (\"netbsd\", \"netbsd\"),\n        (\"openbsd\", \"openbsd\"),\n        (\"freebsd\", \"freebsd\"),\n        (\"dragonfly\", \"dragonflybsd\"),\n        (\"(sun|i86)os\", \"solaris\"),\n        (r\"x11|lin(\\b|ux)?\", \"linux\"),\n        (r\"nintendo\\s+wii\", \"wii\"),\n        (\"irix\", \"irix\"),\n        (\"hp-?ux\", \"hpux\"),\n        (\"aix\", \"aix\"),\n        (\"sco|unix_sv\", \"sco\"),\n        (\"bsd\", \"bsd\"),\n        (\"amiga\", \"amiga\"),\n        (\"blackberry|playbook\", \"blackberry\"),\n        (\"symbian\", \"symbian\"),\n    )\n    browsers = (\n        (\"googlebot\", \"google\"),\n        (\"msnbot\", \"msn\"),\n        (\"yahoo\", \"yahoo\"),\n        (\"ask jeeves\", \"ask\"),\n        (r\"aol|america\\s+online\\s+browser\", \"aol\"),\n        (r\"opera|opr\", \"opera\"),\n        (\"edge|edg\", \"edge\"),\n        (\"chrome|crios\", \"chrome\"),\n        (\"seamonkey\", \"seamonkey\"),\n        (\"firefox|firebird|phoenix|iceweasel\", \"firefox\"),\n        (\"galeon\", \"galeon\"),\n        (\"safari|version\", \"safari\"),\n        (\"webkit\", \"webkit\"),\n        (\"camino\", \"camino\"),\n        (\"konqueror\", \"konqueror\"),\n        (\"k-meleon\", \"kmeleon\"),\n        (\"netscape\", \"netscape\"),\n        (r\"msie|microsoft\\s+internet\\s+explorer|trident/.+? rv:\", \"msie\"),\n        (\"lynx\", \"lynx\"),\n        (\"links\", \"links\"),\n        (\"Baiduspider\", \"baidu\"),\n        (\"bingbot\", \"bing\"),\n        (\"mozilla\", \"mozilla\"),\n    )\n\n    _browser_version_re = r\"(?:%s)[/\\sa-z(]*(\\d+[.\\da-z]+)?\"\n    _language_re = re.compile(\n        r\"(?:;\\s*|\\s+)(\\b\\w{2}\\b(?:-\\b\\w{2}\\b)?)\\s*;|\"\n        r\"(?:\\(|\\[|;)\\s*(\\b\\w{2}\\b(?:-\\b\\w{2}\\b)?)\\s*(?:\\]|\\)|;)\"\n    )\n\n    def __init__(self):\n        self.platforms = [(b, re.compile(a, re.I)) for a, b in self.platforms]\n        self.browsers = [\n            (b, re.compile(self._browser_version_re % a, re.I))\n            for a, b in self.browsers\n        ]\n\n    def __call__(self, user_agent):\n        for platform, regex in self.platforms:  # noqa: B007\n            match = regex.search(user_agent)\n            if match is not None:\n                break\n        else:\n            platform = None\n        for browser, regex in self.browsers:  # noqa: B007\n            match = regex.search(user_agent)\n            if match is not None:\n                version = match.group(1)\n                break\n        else:\n            browser = version = None\n        match = self._language_re.search(user_agent)\n        if match is not None:\n            language = match.group(1) or match.group(2)\n        else:\n            language = None\n        return platform, browser, version, language\n\n\nclass UserAgent(object):\n    \"\"\"Represents a user agent.  Pass it a WSGI environment or a user agent\n    string and you can inspect some of the details from the user agent\n    string via the attributes.  The following attributes exist:\n\n    .. attribute:: string\n\n       the raw user agent string\n\n    .. attribute:: platform\n\n       the browser platform. ``None`` if not recognized.\n       The following platforms are currently recognized:\n\n       -   `aix`\n       -   `amiga`\n       -   `android`\n       -   `blackberry`\n       -   `bsd`\n       -   `chromeos`\n       -   `dragonflybsd`\n       -   `freebsd`\n       -   `hpux`\n       -   `ipad`\n       -   `iphone`\n       -   `irix`\n       -   `linux`\n       -   `macos`\n       -   `netbsd`\n       -   `openbsd`\n       -   `sco`\n       -   `solaris`\n       -   `symbian`\n       -   `wii`\n       -   `windows`\n\n    .. attribute:: browser\n\n        the name of the browser. ``None`` if not recognized.\n        The following browsers are currently recognized:\n\n        -   `aol` *\n        -   `ask` *\n        -   `baidu` *\n        -   `bing` *\n        -   `camino`\n        -   `chrome`\n        -   `edge`\n        -   `firefox`\n        -   `galeon`\n        -   `google` *\n        -   `kmeleon`\n        -   `konqueror`\n        -   `links`\n        -   `lynx`\n        -   `mozilla`\n        -   `msie`\n        -   `msn`\n        -   `netscape`\n        -   `opera`\n        -   `safari`\n        -   `seamonkey`\n        -   `webkit`\n        -   `yahoo` *\n\n        (Browsers marked with a star (``*``) are crawlers.)\n\n    .. attribute:: version\n\n        the version of the browser. ``None`` if not recognized.\n\n    .. attribute:: language\n\n        the language of the browser. ``None`` if not recognized.\n    \"\"\"\n\n    _parser = UserAgentParser()\n\n    def __init__(self, environ_or_string):\n        if isinstance(environ_or_string, dict):\n            environ_or_string = environ_or_string.get(\"HTTP_USER_AGENT\", \"\")\n        self.string = environ_or_string\n        self.platform, self.browser, self.version, self.language = self._parser(\n            environ_or_string\n        )\n\n    def to_header(self):\n        return self.string\n\n    def __str__(self):\n        return self.string\n\n    def __nonzero__(self):\n        return bool(self.browser)\n\n    __bool__ = __nonzero__\n\n    def __repr__(self):\n        return \"<%s %r/%s>\" % (self.__class__.__name__, self.browser, self.version)\n", "path": "src/werkzeug/useragents.py"}]}