prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Dashboards fail with 500 status code when using `bokeh<3.3.0`
  When using the latest `main` with `bokeh<3.3.0`, the dashboards fail with a 500 status code.
  
  Scheduler traceback:
  ```
  2023-11-30 18:00:07,300 - tornado.application - ERROR - Uncaught exception GET /status (192.168.178.45)
  HTTPServerRequest(protocol='http', host='192.168.178.45:8787', method='GET', uri='/status', version='HTTP/1.1', remote_ip='192.168.178.45')
  Traceback (most recent call last):
    File "/opt/homebrew/Caskroom/mambaforge/base/envs/dask-distributed/lib/python3.11/site-packages/tornado/web.py", line 1786, in _execute
      result = await result
               ^^^^^^^^^^^^
    File "/opt/homebrew/Caskroom/mambaforge/base/envs/dask-distributed/lib/python3.11/site-packages/bokeh/server/views/doc_handler.py", line 57, in get
      resources=self.application.resources(),
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/Users/hendrikmakait/projects/dask/distributed/distributed/dashboard/core.py", line 37, in resources
      return super().resources(absolute_url)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/opt/homebrew/Caskroom/mambaforge/base/envs/dask-distributed/lib/python3.11/site-packages/bokeh/server/tornado.py", line 621, in resources
      return Resources(mode="server", root_url=root_url, path_versioner=StaticHandler.append_version)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/opt/homebrew/Caskroom/mambaforge/base/envs/dask-distributed/lib/python3.11/site-packages/bokeh/resources.py", line 377, in __init__
      if root_url and not root_url.endswith("/"):
                          ^^^^^^^^^^^^^^^^^
  AttributeError: 'bool' object has no attribute 'endswith'
  ```
  
  git bisect blames #8347
  
  </issue>
  <code>
  [start of distributed/dashboard/core.py]
  1 from __future__ import annotations
  2 
  3 import functools
  4 import warnings
  5 
  6 from bokeh.application import Application
  7 from bokeh.application.handlers.function import FunctionHandler
  8 from bokeh.resources import Resources
  9 from bokeh.server.server import BokehTornado
  10 from bokeh.server.util import create_hosts_allowlist
  11 
  12 import dask
  13 
  14 from distributed.dashboard.utils import BOKEH_VERSION
  15 from distributed.versions import BOKEH_REQUIREMENT
  16 
  17 # Set `prereleases=True` to allow for use with dev versions of `bokeh`
  18 if not BOKEH_REQUIREMENT.specifier.contains(BOKEH_VERSION, prereleases=True):
  19     warnings.warn(
  20         f"\nDask needs {BOKEH_REQUIREMENT} for the dashboard."
  21         f"\nYou have bokeh={BOKEH_VERSION}."
  22         "\nContinuing without the dashboard."
  23     )
  24     raise ImportError(
  25         f"Dask needs {BOKEH_REQUIREMENT} for the dashboard, not bokeh={BOKEH_VERSION}"
  26     )
  27 
  28 
  29 if BOKEH_VERSION.major < 3:
  30     from bokeh.models import Panel as TabPanel  # noqa: F401
  31 else:
  32     from bokeh.models import TabPanel  # noqa: F401
  33 
  34 
  35 class DaskBokehTornado(BokehTornado):
  36     def resources(self, absolute_url: str | bool | None = True) -> Resources:
  37         return super().resources(absolute_url)
  38 
  39 
  40 def BokehApplication(applications, server, prefix="/", template_variables=None):
  41     template_variables = template_variables or {}
  42     prefix = "/" + prefix.strip("/") + "/" if prefix else "/"
  43 
  44     extra = {"prefix": prefix, **template_variables}
  45 
  46     funcs = {k: functools.partial(v, server, extra) for k, v in applications.items()}
  47     apps = {k: Application(FunctionHandler(v)) for k, v in funcs.items()}
  48 
  49     kwargs = dask.config.get("distributed.scheduler.dashboard.bokeh-application").copy()
  50     extra_websocket_origins = create_hosts_allowlist(
  51         kwargs.pop("allow_websocket_origin"), server.http_server.port
  52     )
  53 
  54     return DaskBokehTornado(
  55         apps,
  56         prefix=prefix,
  57         use_index=False,
  58         extra_websocket_origins=extra_websocket_origins,
  59         absolute_url="",
  60         **kwargs,
  61     )
  62
  [end of distributed/dashboard/core.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/distributed/dashboard/core.py b/distributed/dashboard/core.py
  --- a/distributed/dashboard/core.py
  +++ b/distributed/dashboard/core.py
  @@ -6,8 +6,8 @@
   from bokeh.application import Application
   from bokeh.application.handlers.function import FunctionHandler
   from bokeh.resources import Resources
  -from bokeh.server.server import BokehTornado
   from bokeh.server.util import create_hosts_allowlist
  +from packaging.version import parse as parse_version
   
   import dask
   
  @@ -32,9 +32,14 @@
       from bokeh.models import TabPanel  # noqa: F401
   
   
  -class DaskBokehTornado(BokehTornado):
  -    def resources(self, absolute_url: str | bool | None = True) -> Resources:
  -        return super().resources(absolute_url)
  +if BOKEH_VERSION < parse_version("3.3.0"):
  +    from bokeh.server.server import BokehTornado as DaskBokehTornado
  +else:
  +    from bokeh.server.server import BokehTornado
  +
  +    class DaskBokehTornado(BokehTornado):  # type: ignore[no-redef]
  +        def resources(self, absolute_url: str | bool | None = True) -> Resources:
  +            return super().resources(absolute_url)
   
   
   def BokehApplication(applications, server, prefix="/", template_variables=None):
  
verification_info: {"golden_diff": "diff --git a/distributed/dashboard/core.py b/distributed/dashboard/core.py\n--- a/distributed/dashboard/core.py\n+++ b/distributed/dashboard/core.py\n@@ -6,8 +6,8 @@\n from bokeh.application import Application\n from bokeh.application.handlers.function import FunctionHandler\n from bokeh.resources import Resources\n-from bokeh.server.server import BokehTornado\n from bokeh.server.util import create_hosts_allowlist\n+from packaging.version import parse as parse_version\n \n import dask\n \n@@ -32,9 +32,14 @@\n     from bokeh.models import TabPanel  # noqa: F401\n \n \n-class DaskBokehTornado(BokehTornado):\n-    def resources(self, absolute_url: str | bool | None = True) -> Resources:\n-        return super().resources(absolute_url)\n+if BOKEH_VERSION < parse_version(\"3.3.0\"):\n+    from bokeh.server.server import BokehTornado as DaskBokehTornado\n+else:\n+    from bokeh.server.server import BokehTornado\n+\n+    class DaskBokehTornado(BokehTornado):  # type: ignore[no-redef]\n+        def resources(self, absolute_url: str | bool | None = True) -> Resources:\n+            return super().resources(absolute_url)\n \n \n def BokehApplication(applications, server, prefix=\"/\", template_variables=None):\n", "issue": "Dashboards fail with 500 status code when using `bokeh<3.3.0`\nWhen using the latest `main` with `bokeh<3.3.0`, the dashboards fail with a 500 status code.\r\n\r\nScheduler traceback:\r\n```\r\n2023-11-30 18:00:07,300 - tornado.application - ERROR - Uncaught exception GET /status (192.168.178.45)\r\nHTTPServerRequest(protocol='http', host='192.168.178.45:8787', method='GET', uri='/status', version='HTTP/1.1', remote_ip='192.168.178.45')\r\nTraceback (most recent call last):\r\n  File \"/opt/homebrew/Caskroom/mambaforge/base/envs/dask-distributed/lib/python3.11/site-packages/tornado/web.py\", line 1786, in _execute\r\n    result = await result\r\n             ^^^^^^^^^^^^\r\n  File \"/opt/homebrew/Caskroom/mambaforge/base/envs/dask-distributed/lib/python3.11/site-packages/bokeh/server/views/doc_handler.py\", line 57, in get\r\n    resources=self.application.resources(),\r\n              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/Users/hendrikmakait/projects/dask/distributed/distributed/dashboard/core.py\", line 37, in resources\r\n    return super().resources(absolute_url)\r\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/opt/homebrew/Caskroom/mambaforge/base/envs/dask-distributed/lib/python3.11/site-packages/bokeh/server/tornado.py\", line 621, in resources\r\n    return Resources(mode=\"server\", root_url=root_url, path_versioner=StaticHandler.append_version)\r\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/opt/homebrew/Caskroom/mambaforge/base/envs/dask-distributed/lib/python3.11/site-packages/bokeh/resources.py\", line 377, in __init__\r\n    if root_url and not root_url.endswith(\"/\"):\r\n                        ^^^^^^^^^^^^^^^^^\r\nAttributeError: 'bool' object has no attribute 'endswith'\r\n```\r\n\r\ngit bisect blames #8347\n", "before_files": [{"content": "from __future__ import annotations\n\nimport functools\nimport warnings\n\nfrom bokeh.application import Application\nfrom bokeh.application.handlers.function import FunctionHandler\nfrom bokeh.resources import Resources\nfrom bokeh.server.server import BokehTornado\nfrom bokeh.server.util import create_hosts_allowlist\n\nimport dask\n\nfrom distributed.dashboard.utils import BOKEH_VERSION\nfrom distributed.versions import BOKEH_REQUIREMENT\n\n# Set `prereleases=True` to allow for use with dev versions of `bokeh`\nif not BOKEH_REQUIREMENT.specifier.contains(BOKEH_VERSION, prereleases=True):\n    warnings.warn(\n        f\"\\nDask needs {BOKEH_REQUIREMENT} for the dashboard.\"\n        f\"\\nYou have bokeh={BOKEH_VERSION}.\"\n        \"\\nContinuing without the dashboard.\"\n    )\n    raise ImportError(\n        f\"Dask needs {BOKEH_REQUIREMENT} for the dashboard, not bokeh={BOKEH_VERSION}\"\n    )\n\n\nif BOKEH_VERSION.major < 3:\n    from bokeh.models import Panel as TabPanel  # noqa: F401\nelse:\n    from bokeh.models import TabPanel  # noqa: F401\n\n\nclass DaskBokehTornado(BokehTornado):\n    def resources(self, absolute_url: str | bool | None = True) -> Resources:\n        return super().resources(absolute_url)\n\n\ndef BokehApplication(applications, server, prefix=\"/\", template_variables=None):\n    template_variables = template_variables or {}\n    prefix = \"/\" + prefix.strip(\"/\") + \"/\" if prefix else \"/\"\n\n    extra = {\"prefix\": prefix, **template_variables}\n\n    funcs = {k: functools.partial(v, server, extra) for k, v in applications.items()}\n    apps = {k: Application(FunctionHandler(v)) for k, v in funcs.items()}\n\n    kwargs = dask.config.get(\"distributed.scheduler.dashboard.bokeh-application\").copy()\n    extra_websocket_origins = create_hosts_allowlist(\n        kwargs.pop(\"allow_websocket_origin\"), server.http_server.port\n    )\n\n    return DaskBokehTornado(\n        apps,\n        prefix=prefix,\n        use_index=False,\n        extra_websocket_origins=extra_websocket_origins,\n        absolute_url=\"\",\n        **kwargs,\n    )\n", "path": "distributed/dashboard/core.py"}]}