We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Tiled cubing doesn't convert last slice

Tiled cubing doesn't convert last slice


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wkcuber/utils.py`
Content:
```
1 import time
2 import wkw
3 import numpy as np
4 import logging
5 from glob import iglob
6 from collections import namedtuple
7 from multiprocessing import cpu_count, Lock
8 from concurrent.futures import ProcessPoolExecutor
9 from os import path
10 from platform import python_version
11 from math import floor, ceil
12 
13 
14 from .knossos import KnossosDataset, CUBE_EDGE_LEN
15 
16 
17 WkwDatasetInfo = namedtuple(
18     "WkwDatasetInfo", ("dataset_path", "layer_name", "dtype", "mag")
19 )
20 KnossosDatasetInfo = namedtuple("KnossosDatasetInfo", ("dataset_path", "dtype"))
21 
22 
23 def _open_wkw(info, **kwargs):
24     header = wkw.Header(np.dtype(info.dtype), **kwargs)
25     ds = wkw.Dataset.open(
26         path.join(info.dataset_path, info.layer_name, str(info.mag)), header
27     )
28     return ds
29 
30 
31 def open_wkw(info, lock=None, **kwargs):
32     if lock is None:
33         # Create dummy lock
34         lock = Lock()
35 
36     with lock:
37         return _open_wkw(info, **kwargs)
38 
39 
40 def open_knossos(info):
41     return KnossosDataset.open(info.dataset_path, np.dtype(info.dtype))
42 
43 
44 def add_verbose_flag(parser):
45     parser.add_argument(
46         "--verbose", "-v", help="Verbose output", dest="verbose", action="store_true"
47     )
48 
49     parser.set_defaults(verbose=False)
50 
51 
52 def find_files(source_path, extensions):
53     # Find all files with a matching file extension
54     return (
55         f
56         for f in iglob(source_path, recursive=True)
57         if any([f.endswith(suffix) for suffix in extensions])
58     )
59 
60 
61 def get_chunks(arr, chunk_size):
62     for i in range(0, len(arr), chunk_size):
63         yield arr[i : i + chunk_size]
64 
65 
66 def get_regular_chunks(min_z, max_z, chunk_size):
67     i = floor(min_z / chunk_size) * chunk_size
68     while i < ceil(max_z / chunk_size) * chunk_size:
69         yield range(i, i + chunk_size)
70         i += chunk_size
71 
72 
73 def add_jobs_flag(parser):
74     parser.add_argument(
75         "--jobs", "-j", help="Parallel jobs", type=int, default=cpu_count()
76     )
77 
78 
79 def pool_init(lock):
80     global process_pool_lock
81     process_pool_lock = lock
82 
83 
84 def pool_get_lock():
85     global process_pool_lock
86     try:
87         return process_pool_lock
88     except NameError:
89         return None
90 
91 
92 class ParallelExecutor:
93     def __init__(self, jobs):
94         self.lock = Lock()
95         if python_version() >= "3.7.0":
96             self.exec = ProcessPoolExecutor(
97                 jobs, initializer=pool_init, initargs=(self.lock,)
98             )
99         else:
100             self.exec = ProcessPoolExecutor(jobs)
101         self.futures = []
102 
103     def submit(self, fn, *args):
104         future = self.exec.submit(fn, *args)
105         self.futures.append(future)
106         return future
107 
108     def __enter__(self):
109         self.exec.__enter__()
110         return self
111 
112     def __exit__(self, type, value, tb):
113         [f.result() for f in self.futures]
114         self.exec.__exit__(type, value, tb)
115 
116 
117 times = {}
118 
119 
120 def time_start(identifier):
121     times[identifier] = time.time()
122 
123 
124 def time_stop(identifier):
125     _time = times.pop(identifier)
126     logging.debug("{} took {:.8f}s".format(identifier, time.time() - _time))
127
```
--- 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/wkcuber/utils.py b/wkcuber/utils.py
--- a/wkcuber/utils.py
+++ b/wkcuber/utils.py
@@ -63,9 +63,10 @@
         yield arr[i : i + chunk_size]
 
 
+# min_z and max_z are both inclusive
 def get_regular_chunks(min_z, max_z, chunk_size):
     i = floor(min_z / chunk_size) * chunk_size
-    while i < ceil(max_z / chunk_size) * chunk_size:
+    while i < ceil((max_z + 1) / chunk_size) * chunk_size:
         yield range(i, i + chunk_size)
         i += chunk_size

{"golden_diff": "diff --git a/wkcuber/utils.py b/wkcuber/utils.py\n--- a/wkcuber/utils.py\n+++ b/wkcuber/utils.py\n@@ -63,9 +63,10 @@\n         yield arr[i : i + chunk_size]\n \n \n+# min_z and max_z are both inclusive\n def get_regular_chunks(min_z, max_z, chunk_size):\n     i = floor(min_z / chunk_size) * chunk_size\n-    while i < ceil(max_z / chunk_size) * chunk_size:\n+    while i < ceil((max_z + 1) / chunk_size) * chunk_size:\n         yield range(i, i + chunk_size)\n         i += chunk_size\n", "issue": "Tiled cubing doesn't convert last slice\n\nTiled cubing doesn't convert last slice\n\n", "before_files": [{"content": "import time\nimport wkw\nimport numpy as np\nimport logging\nfrom glob import iglob\nfrom collections import namedtuple\nfrom multiprocessing import cpu_count, Lock\nfrom concurrent.futures import ProcessPoolExecutor\nfrom os import path\nfrom platform import python_version\nfrom math import floor, ceil\n\n\nfrom .knossos import KnossosDataset, CUBE_EDGE_LEN\n\n\nWkwDatasetInfo = namedtuple(\n    \"WkwDatasetInfo\", (\"dataset_path\", \"layer_name\", \"dtype\", \"mag\")\n)\nKnossosDatasetInfo = namedtuple(\"KnossosDatasetInfo\", (\"dataset_path\", \"dtype\"))\n\n\ndef _open_wkw(info, **kwargs):\n    header = wkw.Header(np.dtype(info.dtype), **kwargs)\n    ds = wkw.Dataset.open(\n        path.join(info.dataset_path, info.layer_name, str(info.mag)), header\n    )\n    return ds\n\n\ndef open_wkw(info, lock=None, **kwargs):\n    if lock is None:\n        # Create dummy lock\n        lock = Lock()\n\n    with lock:\n        return _open_wkw(info, **kwargs)\n\n\ndef open_knossos(info):\n    return KnossosDataset.open(info.dataset_path, np.dtype(info.dtype))\n\n\ndef add_verbose_flag(parser):\n    parser.add_argument(\n        \"--verbose\", \"-v\", help=\"Verbose output\", dest=\"verbose\", action=\"store_true\"\n    )\n\n    parser.set_defaults(verbose=False)\n\n\ndef find_files(source_path, extensions):\n    # Find all files with a matching file extension\n    return (\n        f\n        for f in iglob(source_path, recursive=True)\n        if any([f.endswith(suffix) for suffix in extensions])\n    )\n\n\ndef get_chunks(arr, chunk_size):\n    for i in range(0, len(arr), chunk_size):\n        yield arr[i : i + chunk_size]\n\n\ndef get_regular_chunks(min_z, max_z, chunk_size):\n    i = floor(min_z / chunk_size) * chunk_size\n    while i < ceil(max_z / chunk_size) * chunk_size:\n        yield range(i, i + chunk_size)\n        i += chunk_size\n\n\ndef add_jobs_flag(parser):\n    parser.add_argument(\n        \"--jobs\", \"-j\", help=\"Parallel jobs\", type=int, default=cpu_count()\n    )\n\n\ndef pool_init(lock):\n    global process_pool_lock\n    process_pool_lock = lock\n\n\ndef pool_get_lock():\n    global process_pool_lock\n    try:\n        return process_pool_lock\n    except NameError:\n        return None\n\n\nclass ParallelExecutor:\n    def __init__(self, jobs):\n        self.lock = Lock()\n        if python_version() >= \"3.7.0\":\n            self.exec = ProcessPoolExecutor(\n                jobs, initializer=pool_init, initargs=(self.lock,)\n            )\n        else:\n            self.exec = ProcessPoolExecutor(jobs)\n        self.futures = []\n\n    def submit(self, fn, *args):\n        future = self.exec.submit(fn, *args)\n        self.futures.append(future)\n        return future\n\n    def __enter__(self):\n        self.exec.__enter__()\n        return self\n\n    def __exit__(self, type, value, tb):\n        [f.result() for f in self.futures]\n        self.exec.__exit__(type, value, tb)\n\n\ntimes = {}\n\n\ndef time_start(identifier):\n    times[identifier] = time.time()\n\n\ndef time_stop(identifier):\n    _time = times.pop(identifier)\n    logging.debug(\"{} took {:.8f}s\".format(identifier, time.time() - _time))\n", "path": "wkcuber/utils.py"}], "after_files": [{"content": "import time\nimport wkw\nimport numpy as np\nimport logging\nfrom glob import iglob\nfrom collections import namedtuple\nfrom multiprocessing import cpu_count, Lock\nfrom concurrent.futures import ProcessPoolExecutor\nfrom os import path\nfrom platform import python_version\nfrom math import floor, ceil\n\n\nfrom .knossos import KnossosDataset, CUBE_EDGE_LEN\n\n\nWkwDatasetInfo = namedtuple(\n    \"WkwDatasetInfo\", (\"dataset_path\", \"layer_name\", \"dtype\", \"mag\")\n)\nKnossosDatasetInfo = namedtuple(\"KnossosDatasetInfo\", (\"dataset_path\", \"dtype\"))\n\n\ndef _open_wkw(info, **kwargs):\n    header = wkw.Header(np.dtype(info.dtype), **kwargs)\n    ds = wkw.Dataset.open(\n        path.join(info.dataset_path, info.layer_name, str(info.mag)), header\n    )\n    return ds\n\n\ndef open_wkw(info, lock=None, **kwargs):\n    if lock is None:\n        # Create dummy lock\n        lock = Lock()\n\n    with lock:\n        return _open_wkw(info, **kwargs)\n\n\ndef open_knossos(info):\n    return KnossosDataset.open(info.dataset_path, np.dtype(info.dtype))\n\n\ndef add_verbose_flag(parser):\n    parser.add_argument(\n        \"--verbose\", \"-v\", help=\"Verbose output\", dest=\"verbose\", action=\"store_true\"\n    )\n\n    parser.set_defaults(verbose=False)\n\n\ndef find_files(source_path, extensions):\n    # Find all files with a matching file extension\n    return (\n        f\n        for f in iglob(source_path, recursive=True)\n        if any([f.endswith(suffix) for suffix in extensions])\n    )\n\n\ndef get_chunks(arr, chunk_size):\n    for i in range(0, len(arr), chunk_size):\n        yield arr[i : i + chunk_size]\n\n\n# min_z and max_z are both inclusive\ndef get_regular_chunks(min_z, max_z, chunk_size):\n    i = floor(min_z / chunk_size) * chunk_size\n    while i < ceil((max_z + 1) / chunk_size) * chunk_size:\n        yield range(i, i + chunk_size)\n        i += chunk_size\n\n\ndef add_jobs_flag(parser):\n    parser.add_argument(\n        \"--jobs\", \"-j\", help=\"Parallel jobs\", type=int, default=cpu_count()\n    )\n\n\ndef pool_init(lock):\n    global process_pool_lock\n    process_pool_lock = lock\n\n\ndef pool_get_lock():\n    global process_pool_lock\n    try:\n        return process_pool_lock\n    except NameError:\n        return None\n\n\nclass ParallelExecutor:\n    def __init__(self, jobs):\n        self.lock = Lock()\n        if python_version() >= \"3.7.0\":\n            self.exec = ProcessPoolExecutor(\n                jobs, initializer=pool_init, initargs=(self.lock,)\n            )\n        else:\n            self.exec = ProcessPoolExecutor(jobs)\n        self.futures = []\n\n    def submit(self, fn, *args):\n        future = self.exec.submit(fn, *args)\n        self.futures.append(future)\n        return future\n\n    def __enter__(self):\n        self.exec.__enter__()\n        return self\n\n    def __exit__(self, type, value, tb):\n        [f.result() for f in self.futures]\n        self.exec.__exit__(type, value, tb)\n\n\ntimes = {}\n\n\ndef time_start(identifier):\n    times[identifier] = time.time()\n\n\ndef time_stop(identifier):\n    _time = times.pop(identifier)\n    logging.debug(\"{} took {:.8f}s\".format(identifier, time.time() - _time))\n", "path": "wkcuber/utils.py"}]}