prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Tiled cubing doesn't convert last slice
  
  Tiled cubing doesn't convert last slice
  
  
  </issue>
  <code>
  [start of wkcuber/utils.py]
  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 of wkcuber/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/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
  
verification_info: {"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"}]}