From eeca79e6815a41210a6190197e1a1ce8d3a84968 Mon Sep 17 00:00:00 2001 From: Ma Nan Date: Fri, 26 Apr 2024 18:14:34 +0800 Subject: [PATCH 1/4] chore: change import path --- bioxelnodes/__init__.py | 4 ++-- bioxelnodes/menu.py | 2 +- bioxelnodes/misc.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bioxelnodes/__init__.py b/bioxelnodes/__init__.py index aa34072..22a7897 100644 --- a/bioxelnodes/__init__.py +++ b/bioxelnodes/__init__.py @@ -1,9 +1,9 @@ +import bpy + from .nodes import custom_nodes from . import auto_load from . import menu -import bpy - bl_info = { "name": "Bioxel Nodes", diff --git a/bioxelnodes/menu.py b/bioxelnodes/menu.py index 930a53a..2bb5573 100644 --- a/bioxelnodes/menu.py +++ b/bioxelnodes/menu.py @@ -1,7 +1,7 @@ -from bioxelnodes.misc import SaveBioxels import bpy from .convert import ConvertToMesh from .io import ExportVDB, ImportDICOM +from .misc import SaveBioxels class ObjectMenu(bpy.types.Menu): diff --git a/bioxelnodes/misc.py b/bioxelnodes/misc.py index 56d3bfc..5ef4b00 100644 --- a/bioxelnodes/misc.py +++ b/bioxelnodes/misc.py @@ -1,7 +1,7 @@ +import bpy from pathlib import Path import shutil from bioxelnodes.utils import get_all_bioxels_objs, get_bioxels_obj -import bpy class SaveBioxels(bpy.types.Operator): From 1990a1697268d51c97db52ca82afddb6e45b64a0 Mon Sep 17 00:00:00 2001 From: Ma Nan Date: Sat, 11 May 2024 10:43:00 +0800 Subject: [PATCH 2/4] feat: add more format support --- .github/workflows/upload-assets.yml | 56 +-- bioxelnodes/__init__.py | 18 +- .../assets/Nodes/BioxelNodes_4.0.blend | 3 + ...ioxelNodes.blend => BioxelNodes_4.1.blend} | 0 bioxelnodes/auto_load.py | 2 +- bioxelnodes/convert.py | 2 +- bioxelnodes/customnodes/__init__.py | 2 +- bioxelnodes/customnodes/{menu.py => menus.py} | 13 +- bioxelnodes/externalpackage/__init__.py | 3 +- bioxelnodes/externalpackage/package.py | 8 +- bioxelnodes/externalpackage/preferences.py | 27 +- bioxelnodes/io.py | 445 ++++++++++++------ bioxelnodes/io_points.py | 221 +++++++++ bioxelnodes/{menu.py => menus.py} | 13 +- bioxelnodes/nodes.py | 70 +-- bioxelnodes/preferences.py | 20 +- bioxelnodes/props.py | 5 + bioxelnodes/utils.py | 15 +- 18 files changed, 678 insertions(+), 245 deletions(-) create mode 100644 bioxelnodes/assets/Nodes/BioxelNodes_4.0.blend rename bioxelnodes/assets/Nodes/{BioxelNodes.blend => BioxelNodes_4.1.blend} (100%) rename bioxelnodes/customnodes/{menu.py => menus.py} (96%) create mode 100644 bioxelnodes/io_points.py rename bioxelnodes/{menu.py => menus.py} (90%) create mode 100644 bioxelnodes/props.py diff --git a/.github/workflows/upload-assets.yml b/.github/workflows/upload-assets.yml index 7c6898b..0f7e9d8 100644 --- a/.github/workflows/upload-assets.yml +++ b/.github/workflows/upload-assets.yml @@ -6,31 +6,8 @@ on: - "release/*" jobs: - # draft_release: - # name: Draft Release - # runs-on: ubuntu-latest - # outputs: - # upload_url: ${{ steps.draft_release.outputs.upload_url }} - # version: ${{ steps.set_env.outputs.version }} - # steps: - # - name: Set Version Env - # id: set_env - # run: | - # ref_name=${{ github.ref_name }} - # echo "version=${ref_name#release/}" >> "$GITHUB_OUTPUT" - # - name: Get release - # id: draft_release - # uses: cardinalby/git-get-release-action@1.2.4 - # with: - # releaseName: Draft - # env: - # GITHUB_TOKEN: ${{ github.token }} - draft_release: name: Draft Release - permissions: - contents: write - pull-requests: write runs-on: ubuntu-latest outputs: upload_url: ${{ steps.draft_release.outputs.upload_url }} @@ -41,14 +18,37 @@ jobs: run: | ref_name=${{ github.ref_name }} echo "version=${ref_name#release/}" >> "$GITHUB_OUTPUT" - - name: Draft Release ${{ steps.set_env.outputs.version }} - uses: release-drafter/release-drafter@v5 + - name: Get release id: draft_release + uses: cardinalby/git-get-release-action@1.2.4 with: - name: ${{ steps.set_env.outputs.version }} - tag: ${{ steps.set_env.outputs.version }} + releaseName: Draft env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ github.token }} + + # draft_release: + # name: Draft Release + # permissions: + # contents: write + # pull-requests: write + # runs-on: ubuntu-latest + # outputs: + # upload_url: ${{ steps.draft_release.outputs.upload_url }} + # version: ${{ steps.set_env.outputs.version }} + # steps: + # - name: Set Version Env + # id: set_env + # run: | + # ref_name=${{ github.ref_name }} + # echo "version=${ref_name#release/}" >> "$GITHUB_OUTPUT" + # - name: Draft Release ${{ steps.set_env.outputs.version }} + # uses: release-drafter/release-drafter@v5 + # id: draft_release + # with: + # name: ${{ steps.set_env.outputs.version }} + # tag: ${{ steps.set_env.outputs.version }} + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} upload_blender_addon: name: Upload Blender Add-on diff --git a/bioxelnodes/__init__.py b/bioxelnodes/__init__.py index 22a7897..103e259 100644 --- a/bioxelnodes/__init__.py +++ b/bioxelnodes/__init__.py @@ -2,14 +2,13 @@ from .nodes import custom_nodes from . import auto_load -from . import menu bl_info = { "name": "Bioxel Nodes", "author": "Ma Nan", "description": "", - "blender": (4, 1, 0), + "blender": (4, 0, 0), "version": (0, 1, 0), "location": "File -> Import", "warning": "", @@ -18,23 +17,18 @@ auto_load.init() -bpy.types.Scene.bioxels_dir = bpy.props.StringProperty( - name="Bioxels Directory", - subtype='DIR_PATH', - default="//" -) - def register(): auto_load.register() - custom_nodes.register() - menu.create_menu() + bpy.types.Scene.bioxels_dir = bpy.props.StringProperty( + name="Bioxels Directory", + subtype='DIR_PATH', + default="//" + ) def unregister(): try: - menu.remove_menu() - custom_nodes.unregister() auto_load.unregister() except RuntimeError: pass diff --git a/bioxelnodes/assets/Nodes/BioxelNodes_4.0.blend b/bioxelnodes/assets/Nodes/BioxelNodes_4.0.blend new file mode 100644 index 0000000..b938d23 --- /dev/null +++ b/bioxelnodes/assets/Nodes/BioxelNodes_4.0.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62d5d5bc44343f9bca7d73c6b447661720a5b2de0be4cd5fafeeb204dc32e886 +size 1635596 diff --git a/bioxelnodes/assets/Nodes/BioxelNodes.blend b/bioxelnodes/assets/Nodes/BioxelNodes_4.1.blend similarity index 100% rename from bioxelnodes/assets/Nodes/BioxelNodes.blend rename to bioxelnodes/assets/Nodes/BioxelNodes_4.1.blend diff --git a/bioxelnodes/auto_load.py b/bioxelnodes/auto_load.py index ba6d428..d4006c8 100644 --- a/bioxelnodes/auto_load.py +++ b/bioxelnodes/auto_load.py @@ -134,7 +134,7 @@ def get_register_base_types(): "Node", "NodeSocket", "NodeTree", "UIList", "RenderEngine", "Gizmo", "GizmoGroup", - ]) + ] if hasattr(bpy.types, name)) # Find order to register to solve dependencies diff --git a/bioxelnodes/convert.py b/bioxelnodes/convert.py index d083800..42b3162 100644 --- a/bioxelnodes/convert.py +++ b/bioxelnodes/convert.py @@ -5,7 +5,7 @@ class ConvertToMesh(bpy.types.Operator): bl_idname = "bioxelnodes.convert_to_mesh" bl_label = "Bioxels To Mesh" - bl_description = "Convert Bioxels To Mesh." + bl_description = "Convert Bioxels To Mesh" bl_options = {'UNDO'} @classmethod diff --git a/bioxelnodes/customnodes/__init__.py b/bioxelnodes/customnodes/__init__.py index f809877..bfad98c 100644 --- a/bioxelnodes/customnodes/__init__.py +++ b/bioxelnodes/customnodes/__init__.py @@ -1 +1 @@ -from .menu import CustomNodes \ No newline at end of file +from .menus import CustomNodes \ No newline at end of file diff --git a/bioxelnodes/customnodes/menu.py b/bioxelnodes/customnodes/menus.py similarity index 96% rename from bioxelnodes/customnodes/menu.py rename to bioxelnodes/customnodes/menus.py index 78c0fac..eac702f 100644 --- a/bioxelnodes/customnodes/menu.py +++ b/bioxelnodes/customnodes/menus.py @@ -3,12 +3,6 @@ from pathlib import Path from .nodes import AddCustomNode -bpy.types.Scene.custom_nodes_dir = bpy.props.StringProperty( - name="Nodes Directory", - subtype='DIR_PATH', - default="//" -) - class SaveAllNodes(bpy.types.Operator): bl_idname = "customnodes.save_all_nodes" @@ -182,12 +176,17 @@ def register(self): bpy.utils.register_class(cls) bpy.types.NODE_MT_add.append(self.add_node_menu) + bpy.types.Scene.custom_nodes_dir = bpy.props.StringProperty( + name="Nodes Directory", + subtype='DIR_PATH', + default="//" + ) def unregister(self): + bpy.types.NODE_MT_add.remove(self.add_node_menu) try: for cls in reversed(self.menu_classes): bpy.utils.unregister_class(cls) - bpy.types.NODE_MT_add.remove(self.add_node_menu) except RuntimeError: pass diff --git a/bioxelnodes/externalpackage/__init__.py b/bioxelnodes/externalpackage/__init__.py index c00e7fb..a46ad0f 100644 --- a/bioxelnodes/externalpackage/__init__.py +++ b/bioxelnodes/externalpackage/__init__.py @@ -1 +1,2 @@ -from .preferences import ExternalPackagePreferences \ No newline at end of file +from .preferences import ExternalPackagePreferences +from .package import PackageInstaller diff --git a/bioxelnodes/externalpackage/package.py b/bioxelnodes/externalpackage/package.py index c55ba62..368a32c 100644 --- a/bioxelnodes/externalpackage/package.py +++ b/bioxelnodes/externalpackage/package.py @@ -42,12 +42,13 @@ def __init__(self, package_name, error_message): class PackageInstaller(): def __init__( self, - log_dir: str, requirements_dir: str, + log_dir: str = None, pypi_mirror_provider='Default', ) -> None: self.pypi_mirror_provider = pypi_mirror_provider - self.log_path: Path = Path(log_dir) + self.log_path: Path = Path(log_dir) if log_dir \ + else Path.home() / '.externalpackage' / 'logs' self.requirements_path: Path = Path(requirements_dir) def start_logging(self, logfile_name: str = 'side-packages-install') -> logging.Logger: @@ -250,7 +251,7 @@ def run_python(self, cmd_list: list = None, timeout: int = 600): if result.returncode != 0: log.error('Command failed: %s', cmd_list) log.error('stdout: %s', result.stdout.decode()) - log.error('stderr: %s', result.stderr.decode()) + log.error('stderr: %s', result.stderr.decode(errors='ignore')) else: log.info('Command succeeded: %s', cmd_list) log.info('stdout: %s', result.stdout.decode()) @@ -350,6 +351,7 @@ class EXTERNALPACKAGE_OT_Install_Package(bpy.types.Operator): name='Python Package', description='Python Package to Install' ) # type: ignore + version: bpy.props.StringProperty( name='Python Package', description='Python Package to Install' diff --git a/bioxelnodes/externalpackage/preferences.py b/bioxelnodes/externalpackage/preferences.py index 3c99fed..f15aff8 100644 --- a/bioxelnodes/externalpackage/preferences.py +++ b/bioxelnodes/externalpackage/preferences.py @@ -1,4 +1,5 @@ import bpy +import subprocess from pathlib import Path from .package import PackageInstaller, PYPI_MIRROR @@ -10,6 +11,25 @@ def get_pypi_mirrors(self, context, edit_text): return PYPI_MIRROR.keys() +class RebootBlender(bpy.types.Operator): + bl_idname = "externalpackage.reboot_blender" + bl_label = "Reboot Blender" + bl_description = "Reboot Blender" + bl_options = {'UNDO'} + + def invoke(self, context, event): + context.window_manager.invoke_confirm(self, event) + return {'RUNNING_MODAL'} + + def execute(self, context): + blender_launcher = Path( + bpy.app.binary_path).parent / "blender-launcher.exe" + subprocess.run([str(blender_launcher), "-con", "--python-expr", + "import bpy; bpy.ops.wm.recover_last_session()"]) + bpy.ops.wm.quit_blender() + return {'FINISHED'} + + class ExternalPackagePreferences(): requirements_dir: bpy.props.StringProperty( name="requirements.txt Directory", @@ -34,11 +54,12 @@ class ExternalPackagePreferences(): def draw(self, context): layout = self.layout - layout.label(text="Install the required packages.") + layout.label( + text='**Install the required packages, then hit "Reboot Blender"**') col_main = layout.column(heading='', align=False) row_import = col_main.row() - row_import.prop(self, 'pypi_mirror_provider', text='Set PyPI Mirror') + row_import.prop(self, 'pypi_mirror_provider', text='PyPI Mirror') installer = PackageInstaller( pypi_mirror_provider=self.pypi_mirror_provider, @@ -70,3 +91,5 @@ def draw(self, context): op.package = name op.version = version op.description = f'Install required python package: {name}' + + layout.operator(RebootBlender.bl_idname) diff --git a/bioxelnodes/io.py b/bioxelnodes/io.py index e93a7de..7aeadcc 100644 --- a/bioxelnodes/io.py +++ b/bioxelnodes/io.py @@ -6,71 +6,114 @@ from pathlib import Path from uuid import uuid4 import mathutils -from .utils import calc_bbox_verts, extract_last_number, get_bioxels_obj, get_node_by_type, show_message +import math +from .utils import calc_bbox_verts, get_text_index, get_bioxels_obj, get_node_by_type, show_message from .nodes import custom_nodes - -SUPPORT_EXTS = ['.dcm', '.tif', '.tiff', '.png', '.bmp', '', '.jpg'] - - -def get_data_files(filepath: str): +from .props import BIOXELNODES_Series +try: + import SimpleITK as sitk +except: + ... + +SUPPORT_EXTS = ['.dcm', '.DICOM', + '.bmp', '.BMP', + '.PIC', '.pic', + '.gipl', '.gipl.gz', + '.jpg', '.JPG', '.jpeg', '.JPEG', + '.lsm', '.LSM', + '.tif', '.TIF', '.tiff', '.TIFF', + '.mnc', '.MNC', + '.mrc', '.rec', + '.mha', '.mhd', + '.hdf', '.h4', '.hdf4', '.he2', '.h5', '.hdf5', '.he5', + '.nia', '.nii', '.nii.gz', '.hdr', '.img', '.img.gz', + '.nrrd', '.nhdr', + '.png', '.PNG', + '.vtk'] + +SEQUENCE_EXTS = ['.dcm', '.DICOM', + '.bmp', '.BMP', + '.jpg', '.JPG', '.jpeg', '.JPEG', + '.tif', '.TIF', '.tiff', '.TIFF', + '.png', '.PNG'] + +DICOM_EXTS = ['.dcm', '.DICOM'] + +FH_EXTS = ['.dcm', '.DICOM', + '.gipl', '.gipl.gz', + '.mnc', '.MNC', + '.mrc', '.rec', + '.mha', '.mhd', + '.nia', '.nii', '.nii.gz', '.hdr', '.img', '.img.gz', + '.hdf', '.h4', '.hdf4', '.he2', '.h5', '.hdf5', '.he5', + '.nrrd', '.nhdr', + '.vtk', + '.gz'] + + +def get_bioxels_shape(bioxel_size: float, orig_shape: tuple, orig_spacing: tuple): + return ( + math.ceil(orig_shape[0] / bioxel_size * orig_spacing[0]), + math.ceil(orig_shape[1] / bioxel_size * orig_spacing[1]), + math.ceil(orig_shape[2] / bioxel_size * orig_spacing[2]), + ) + + +def collect_image_sequence(filepath: str): file_path = Path(filepath).resolve() - suffix = file_path.suffix files = list(file_path.parent.iterdir()) - files = [f for f in files if f.is_file() and f.suffix == suffix] - - def last_number(file: Path): - return extract_last_number(file.stem) - - files.sort(key=last_number) - files = [str(f) for f in files] - return files - - -def on_orig_spacing_changed(self, context): - if self.auto: - self.auto = False - new_orig_spacing = tuple(self.orig_spacing) - - orig_shape = tuple(self.orig_shape) - bioxel_size = float(self.bioxel_size) - - self.bioxels_shape = ( - int(orig_shape[0] / bioxel_size * new_orig_spacing[0]), - int(orig_shape[1] / bioxel_size * new_orig_spacing[1]), - int(orig_shape[2] / bioxel_size * new_orig_spacing[2]), - ) + files = [f for f in files if f.is_file() + and get_ext(file_path) == get_ext(f) + and get_text_index(f.stem)] + + def get_index(f: Path): + return get_text_index(f.stem) + + files.sort(key=get_index) + sequence = [str(f) for f in files] + return sequence + + +def get_ext(filepath: str): + file_path = Path(filepath) + if file_path.name.endswith(".nii.gz"): + return ".nii.gz" + elif file_path.name.endswith(".img.gz"): + return ".img.gz" + elif file_path.name.endswith(".gipl.gz"): + return ".gipl.gz" else: - self.auto = True - - -def on_bioxel_size_changed(self, context): - if self.auto: - self.auto = False - new_bioxel_size = float(self.bioxel_size) - - orig_shape = tuple(self.orig_shape) - orig_spacing = tuple(self.orig_spacing) - - self.bioxels_shape = ( - int(orig_shape[0] / new_bioxel_size * orig_spacing[0]), - int(orig_shape[1] / new_bioxel_size * orig_spacing[1]), - int(orig_shape[2] / new_bioxel_size * orig_spacing[2]), - ) + return file_path.suffix + + +def read_image(filepath: str, series_id=""): + ext = get_ext(filepath) + dir_path = Path(filepath).resolve().parent + filename = Path(filepath).resolve().stem + if ext in DICOM_EXTS: + reader = sitk.ImageSeriesReader() + reader.MetaDataDictionaryArrayUpdateOn() + reader.LoadPrivateTagsOn() + series_files = reader.GetGDCMSeriesFileNames( + str(dir_path), series_id) + reader.SetFileNames(series_files) + image = reader.Execute() + elif ext in SEQUENCE_EXTS and get_text_index(filename): + sequence = collect_image_sequence(filepath) + image = sitk.ReadImage(sequence) else: - self.auto = True - + image = sitk.ReadImage(filepath) + if image.GetDimension() == 2: + image = sitk.ReadImage([filepath]) -def on_info_changed(self, context): - for region in context.area.regions: - if region.type == "UI": - region.tag_redraw() + return image -class ImportDICOMDialog(bpy.types.Operator): - bl_idname = "bioxelnodes.import_dicom_dialog" +class ImportImageDialog(bpy.types.Operator): + bl_idname = "bioxelnodes.import_image_dialog" bl_label = "Volume Data as Bioxels" - bl_description = "Import Volume Data as Bioxels (VDB)." + bl_description = "Import Volume Data as Bioxels (VDB)" bl_options = {'UNDO'} filepath: bpy.props.StringProperty( @@ -78,64 +121,62 @@ class ImportDICOMDialog(bpy.types.Operator): options={'HIDDEN'} ) # type: ignore - bioxels_shape: bpy.props.IntVectorProperty( - name="Bioxels Shape (ReadOnly)", - min=0, - default=(100, 100, 100) + series_id: bpy.props.StringProperty() # type: ignore + + read_as: bpy.props.EnumProperty( + name="Read as", + default="scalar", + items=[("scalar", "Scalar", ""), ("labels", "Labels", "")] + ) # type: ignore + + label_index: bpy.props.IntProperty( + name="Label Index", + default=1 ) # type: ignore bioxel_size: bpy.props.FloatProperty( - name="Bioxel Size", + name="Bioxel Size (Larger size means small resolution)", soft_min=0.1, soft_max=10.0, min=1e-2, max=1e2, default=1, - update=on_bioxel_size_changed ) # type: ignore orig_spacing: bpy.props.FloatVectorProperty( name="Original Spacing", default=(1, 1, 1), - update=on_orig_spacing_changed ) # type: ignore orig_shape: bpy.props.IntVectorProperty( name="Original Shape", - default=(100, 100, 100), - options={'HIDDEN'} - ) # type: ignore - - auto: bpy.props.BoolProperty( - name="Auto Setting", - default=False, - options={'HIDDEN'} + default=(100, 100, 100) ) # type: ignore scene_scale: bpy.props.FloatProperty( - name="Scene Scale", + name="Scene Scale (Bioxels Unit pre Blender Unit)", soft_min=0.001, soft_max=100.0, min=1e-6, max=1e6, default=0.01, ) # type: ignore - do_add_segmentnode: bpy.props.BoolProperty( - name="Add Segment Node", + do_orient: bpy.props.BoolProperty( + name="Orient to RAS", default=True, ) # type: ignore - do_change_render_setting: bpy.props.BoolProperty( - name="Change Render Setting", - default=True, + invert_scalar: bpy.props.BoolProperty( + name="Invert Scalar (Background value maybe higher than object)", + default=False, ) # type: ignore def execute(self, context): - files = get_data_files(self.filepath) - name = Path(self.filepath).parent.name + bioxels_name = Path(self.filepath).parent.name \ + if get_ext(self.filepath) in SEQUENCE_EXTS \ + else Path(self.filepath).name.removesuffix(get_ext(self.filepath)) - import SimpleITK as sitk - image = sitk.ReadImage(files) + image = read_image(self.filepath, self.series_id) - bioxel_size = float(self.bioxel_size) - orig_spacing = tuple(self.orig_spacing) + bioxel_size = self.bioxel_size + orig_spacing = self.orig_spacing image_spacing = image.GetSpacing() image_shape = image.GetSize() @@ -145,11 +186,8 @@ def execute(self, context): image_spacing[2] / orig_spacing[2] * bioxel_size ) - bioxels_shape = ( - int(image_shape[0] / bioxel_size * orig_spacing[0]), - int(image_shape[1] / bioxel_size * orig_spacing[1]), - int(image_shape[2] / bioxel_size * orig_spacing[2]), - ) + bioxels_shape = get_bioxels_shape( + bioxel_size, image_shape, orig_spacing) print("Resampling...") image = sitk.Resample( @@ -164,13 +202,14 @@ def execute(self, context): outputPixelType=image.GetPixelID(), ) - print("Orienting to RAS...") - image = sitk.DICOMOrient(image, 'RAS') + if self.do_orient: + print("Orienting to RAS...") + image = sitk.DICOMOrient(image, 'RAS') - array = sitk.GetArrayFromImage(image) - orig_dtype = str(array.dtype) - print(f"Coverting Dtype from {orig_dtype} to float...") - array = array.astype(float) + print("Oriented Origin:", image.GetOrigin()) + print("Oriented Direction:", image.GetDirection()) + + # return {'FINISHED'} # ITK indices, by convention, are [i,j,k] while NumPy indices are [k,j,i] # https://www.slicer.org/wiki/Coordinate_systems @@ -179,27 +218,62 @@ def execute(self, context): # R (ight) i -> k -> x # A (nterior) j -> j -> y # S (uperior) k -> i -> z - + array = sitk.GetArrayFromImage(image) array = np.transpose(array) - bioxels_max = float(np.max(array)) - bioxels_min = float(np.min(array)) - bioxels_shape = array.shape - print("Bioxel Size:", bioxel_size) - print("Bioxels Shape:", bioxels_shape) + orig_dtype = str(array.dtype) + # print(f"Coverting Dtype from {orig_dtype} to float...") + # array = array.astype(float) + if array.ndim == 4: + if array.shape[3] == 3 and self.read_as == "scalar": + # RGB -> Grayscale + array = np.dot(array[..., :3], [0.2989, 0.5870, 0.1140]) + else: + array = array[:, :, :, 0] + bioxels_shape = array.shape bioxels_offset = 0.0 - if bioxels_min < 0 and orig_dtype[0] != "u": - bioxels_offset = -bioxels_min - array = array + np.full_like(array, bioxels_offset) + + if self.read_as == "labels": + array = array == np.full_like(array, self.label_index) + bioxels_default_threshold = 1.0 + bioxels_max = 1.0 + bioxels_min = 0.0 + bioxels_name = f"{bioxels_name}_{self.label_index}" + else: + if self.invert_scalar: + array = -array + + orig_max = float(np.max(array)) + orig_min = float(np.min(array)) + orig_median = float(np.median(array)) + orig_percentile80 = float(np.percentile(array, 80)) \ + if self.invert_scalar else float(np.percentile(array, 80)) + + # if (orig_dtype[0] != "u" and orig_min < 0) \ + # or (orig_dtype[0] == "u" and self.invert_scalar): + if orig_min < 0: + bioxels_offset = -orig_min + array = array + np.full_like(array, bioxels_offset) + + bioxels_default_threshold = orig_percentile80 bioxels_max = float(np.max(array)) bioxels_min = float(np.min(array)) - print("Offseted Max:", bioxels_max) - print("Offseted Min:", bioxels_min) - # Build VDB - grid = vdb.FloatGrid() - grid.copyFromArray(array.copy()) + stat_table = [("Max", orig_max), + ("Min", orig_min), + ("Median", orig_median), + ("Percentile 80%", orig_percentile80), + ("Max (Offset)", bioxels_max), + ("Min (Offset)", bioxels_min)] + + print("Bioxels Value Stat: Max:") + for stat in stat_table: + print("| {: >20} | {: >20} |".format(*stat)) + + # # Build VDB + grid = vdb.BoolGrid() if self.read_as == "labels" else vdb.FloatGrid() + grid.copyFromArray(array.copy().astype(float)) # After sitk.DICOMOrient(), origin and direction will also orient base on LPS # so we need to convert them into RAS @@ -210,22 +284,26 @@ def execute(self, context): to_up='Y' ).to_4x4() + origin = image.GetOrigin() + direction = image.GetDirection() + mat_location = mathutils.Matrix.Translation( - mathutils.Vector(image.GetOrigin()) + mathutils.Vector(origin) ) mat_rotation = mathutils.Matrix( - np.array(image.GetDirection()).reshape((3, 3)) + np.array(direction).reshape((3, 3)) ).to_4x4() mat_scale = mathutils.Matrix.Scale( bioxel_size, 4 ) - transfrom = mat_lps2ras @ mat_location @ mat_rotation @ mat_scale + transfrom = mat_lps2ras @ mat_location @ mat_rotation @ mat_scale \ + if self.do_orient else mat_location @ mat_rotation @ mat_scale grid.transform = vdb.createLinearTransform(transfrom.transposed()) - grid.name = "value" + grid.name = "scalar" preferences = context.preferences.addons[__package__].preferences vdb_dirpath = Path(preferences.cache_dir, 'VDBs') @@ -243,8 +321,8 @@ def execute(self, context): bioxels_obj = bpy.context.active_object # Set props to VDB object - bioxels_obj.name = f"{name}_Bioxels" - bioxels_obj.data.name = f"{name}_Bioxels" + bioxels_obj.name = f"{bioxels_name}_Bioxels" + bioxels_obj.data.name = f"{bioxels_name}_Bioxels" # Make transformation scene_scale = float(self.scene_scale) @@ -289,8 +367,8 @@ def execute(self, context): vert.co = bbox_transform @ mathutils.Vector(bbox_verts[index]) bioxels_obj.parent = container_obj - container_obj.name = name - container_obj.data.name = name + container_obj.name = bioxels_name + container_obj.data.name = bioxels_name container_obj.visible_camera = False container_obj.visible_diffuse = False container_obj.visible_glossy = False @@ -315,7 +393,7 @@ def execute(self, context): # Create BioxelNodes to VDB object print(f"Creating BioxelNodes to the VDB...") - if self.do_add_segmentnode: + if preferences.do_add_segmentnode: nodes = node_tree.nodes links = node_tree.links @@ -324,11 +402,14 @@ def execute(self, context): segment_node = custom_nodes.add_node( nodes, 'BioxelNodes_Segment') + + segment_node.inputs['Threshold'].default_value = bioxels_default_threshold + links.new(input_node.outputs[0], segment_node.inputs[0]) links.new(segment_node.outputs[0], output_node.inputs[0]) # Change render setting for better result - if self.do_change_render_setting: + if preferences.do_change_render_setting: bpy.context.scene.render.engine = 'CYCLES' bpy.context.scene.cycles.volume_bounces = 12 bpy.context.scene.cycles.transparent_max_bounces = 64 @@ -338,37 +419,78 @@ def execute(self, context): return {'FINISHED'} def invoke(self, context, event): - # print(tuple(self.orig_shape)) - self.auto = True - self.bioxel_size = 1 - context.window_manager.invoke_props_dialog(self) + min_size = min( + self.orig_spacing[0], self.orig_spacing[1], self.orig_spacing[2]) + default_size = 1.0 + self.bioxel_size = min_size if min_size > default_size else default_size + context.window_manager.invoke_props_dialog(self, width=400) return {'RUNNING_MODAL'} + def draw(self, context): + layout = self.layout + bioxels_shape = get_bioxels_shape( + self.bioxel_size, self.orig_shape, self.orig_spacing) + bioxel_count = bioxels_shape[0] * bioxels_shape[1] * bioxels_shape[2] + text = f"Shape will be: {str(bioxels_shape)} {bioxel_count:,} " + if bioxel_count > 100000000: + text += "**TOO LARGE!**" + + panel = layout.box() + panel.prop(self, "bioxel_size") + row = panel.row() + row.prop(self, "orig_spacing") + panel.label(text=text) + + panel = layout.box() + panel.prop(self, "read_as") + if self.read_as == "labels": + panel.prop(self, "label_index") + else: + panel.prop(self, "invert_scalar") + + panel = layout.box() + panel.prop(self, "scene_scale") + panel.prop(self, "do_orient") + + +def get_series_ids(self, context): + items = [] + for index, series_id in enumerate(self.series_ids): + items.append(( + series_id.id, + series_id.label, + "", + index + )) + + return items + class ReadDICOM(bpy.types.Operator): bl_idname = "bioxelnodes.read_dicom" bl_label = "Volume Data as Bioxels" - bl_description = "Import Volume Data as Bioxels (VDB)." + bl_description = "Import Volume Data as Bioxels (VDB)" bl_options = {'UNDO'} filepath: bpy.props.StringProperty( subtype="FILE_PATH" ) # type: ignore - ok: bpy.props.BoolProperty( - default=True + series_id: bpy.props.EnumProperty( + name="Select Series", + items=get_series_ids ) # type: ignore + series_ids: bpy.props.CollectionProperty( + type=BIOXELNODES_Series) # type: ignore + def execute(self, context): - if Path(self.filepath).suffix not in SUPPORT_EXTS: - self.report({"WARNING"}, "Not Supported extension.") + ext = get_ext(self.filepath) + if ext not in SUPPORT_EXTS: + self.report({"WARNING"}, "Not supported extension.") return {'CANCELLED'} - files = get_data_files(self.filepath) - - import SimpleITK as sitk - - image = sitk.ReadImage(files) + image = read_image(self.filepath, self.series_id) print("Collecting Meta Data...") print("Original Shape:", image.GetSize()) @@ -376,11 +498,12 @@ def execute(self, context): print("Original Origin:", image.GetOrigin()) print("Original Direction:", image.GetDirection()) - bpy.ops.bioxelnodes.import_dicom_dialog( + bpy.ops.bioxelnodes.import_image_dialog( 'INVOKE_DEFAULT', filepath=self.filepath, orig_shape=image.GetSize(), - orig_spacing=image.GetSpacing() + orig_spacing=image.GetSpacing(), + series_id=self.series_id or "" ) self.report({"INFO"}, "Successfully Readed.") @@ -395,16 +518,43 @@ def invoke(self, context, event): if not self.filepath: return {'CANCELLED'} - show_message('Reading image data, it may take a while', + show_message('Reading image data, it may take a while...', 'Please be patient...') + + if get_ext(self.filepath) == '.dcm': + dir_path = Path(self.filepath).parent + reader = sitk.ImageSeriesReader() + reader.MetaDataDictionaryArrayUpdateOn() + reader.LoadPrivateTagsOn() + series_ids = reader.GetGDCMSeriesIDs(str(dir_path)) + + for _id in series_ids: + series_id = self.series_ids.add() + series_id.id = _id + series_id.label = _id + + if len(series_ids) > 1: + context.window_manager.invoke_props_dialog(self, width=400) + return {'RUNNING_MODAL'} + else: + self.series_id = series_ids[0] + context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} + def draw(self, context): + layout = self.layout + layout.prop(self, "series_id") + layout.label( + text="Reading image data, it may take a while...") + layout.label( + text="Please be patient...") + -class ImportDICOM(bpy.types.Operator): - bl_idname = "bioxelnodes.import_dicom" +class ImportImage(bpy.types.Operator): + bl_idname = "bioxelnodes.import_image" bl_label = "Volume Data as Bioxels" - bl_description = "Import Volume Data as Bioxels (VDB)." + bl_description = "Import Volume Data as Bioxels (VDB)" bl_options = {'UNDO'} filepath: bpy.props.StringProperty( @@ -423,21 +573,24 @@ def invoke(self, context, event): return {'RUNNING_MODAL'} -class BIOXELNODES_FH_ImportDicom(bpy.types.FileHandler): - bl_idname = "BIOXELNODES_FH_ImportDicom" - bl_label = "File handler for dicom import" - bl_import_operator = "bioxelnodes.read_dicom" - bl_file_extensions = ".dcm" +try: + class BIOXELNODES_FH_ImportImage(bpy.types.FileHandler): + bl_idname = "BIOXELNODES_FH_ImportImage" + bl_label = "File handler for dicom import" + bl_import_operator = "bioxelnodes.read_dicom" + bl_file_extensions = ";".join(FH_EXTS) - @classmethod - def poll_drop(cls, context): - return (context.area and context.area.type == 'VIEW_3D') + @classmethod + def poll_drop(cls, context): + return (context.area and context.area.type == 'VIEW_3D') +except: + ... class ExportVDB(bpy.types.Operator): bl_idname = "bioxelnodes.export_vdb" bl_label = "Bioxels as VDB" - bl_description = "Export Bioxels original VDB data." + bl_description = "Export Bioxels original VDB data" bl_options = {'UNDO'} filepath: bpy.props.StringProperty( diff --git a/bioxelnodes/io_points.py b/bioxelnodes/io_points.py new file mode 100644 index 0000000..083fdf8 --- /dev/null +++ b/bioxelnodes/io_points.py @@ -0,0 +1,221 @@ +# TODO: WIP +import bpy +import bmesh + + +def create_points_obj(points, name="points"): + bpy.ops.mesh.primitive_cube_add( + enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1) + ) + obj = bpy.context.active_object + mesh = obj.data + + bm = bmesh.new() + value_layer = bm.verts.layers.float.new('value') + + for point in points: + pos = point['pos'] + value = point['value'] + vert = bm.verts.new(pos) # add a new vert + vert[value_layer] = value + + # make the bmesh the object's mesh + bm.to_mesh(mesh) + bm.free() # always do this when finished + return obj + + +# class ImportDICOMPointsDialog(bpy.types.Operator): +# bl_idname = "bioxelnodes.import_dicom_points_dialog" +# bl_label = "Volume Data as Bioxels" +# bl_description = "Import Volume Data as Bioxels (VDB)" +# bl_options = {'UNDO'} + +# filepath: bpy.props.StringProperty( +# subtype="FILE_PATH", +# options={'HIDDEN'} +# ) # type: ignore + +# bioxels_shape: bpy.props.IntVectorProperty( +# name="Bioxels Shape (ReadOnly)", +# min=0, +# default=(100, 100, 100) +# ) # type: ignore + +# bioxel_size: bpy.props.FloatProperty( +# name="Bioxel Size", +# soft_min=0.1, soft_max=10.0, +# min=1e-2, max=1e2, +# default=1, +# update=on_bioxel_size_changed +# ) # type: ignore + +# orig_spacing: bpy.props.FloatVectorProperty( +# name="Original Spacing", +# default=(1, 1, 1), +# update=on_orig_spacing_changed +# ) # type: ignore + +# orig_shape: bpy.props.IntVectorProperty( +# name="Original Shape", +# default=(100, 100, 100), +# options={'HIDDEN'} +# ) # type: ignore + +# auto: bpy.props.BoolProperty( +# name="Auto Setting", +# default=False, +# options={'HIDDEN'} +# ) # type: ignore + +# scene_scale: bpy.props.FloatProperty( +# name="Scene Scale", +# soft_min=0.001, soft_max=100.0, +# min=1e-6, max=1e6, +# default=0.01, +# ) # type: ignore + +# do_add_segmentnode: bpy.props.BoolProperty( +# name="Add Segment Node", +# default=True, +# ) # type: ignore + +# do_change_render_setting: bpy.props.BoolProperty( +# name="Change Render Setting", +# default=True, +# ) # type: ignore + +# def execute(self, context): +# files = get_data_files(self.filepath) +# name = Path(self.filepath).parent.name + +# image = sitk.ReadImage(files) + +# bioxel_size = float(self.bioxel_size) +# orig_spacing = tuple(self.orig_spacing) +# image_spacing = image.GetSpacing() +# image_shape = image.GetSize() + +# bioxels_spacing = ( +# image_spacing[0] / orig_spacing[0] * bioxel_size, +# image_spacing[1] / orig_spacing[1] * bioxel_size, +# image_spacing[2] / orig_spacing[2] * bioxel_size +# ) + +# bioxels_shape = ( +# int(image_shape[0] / bioxel_size * orig_spacing[0]), +# int(image_shape[1] / bioxel_size * orig_spacing[1]), +# int(image_shape[2] / bioxel_size * orig_spacing[2]), +# ) + +# print("Resampling...") +# image = sitk.Resample( +# image1=image, +# size=bioxels_shape, +# transform=sitk.Transform(), +# interpolator=sitk.sitkLinear, +# outputOrigin=image.GetOrigin(), +# outputSpacing=bioxels_spacing, +# outputDirection=image.GetDirection(), +# defaultPixelValue=0, +# outputPixelType=image.GetPixelID(), +# ) + +# print("Orienting to RAS...") +# image = sitk.DICOMOrient(image, 'RAS') + +# array = sitk.GetArrayFromImage(image) +# orig_dtype = str(array.dtype) +# print(f"Coverting Dtype from {orig_dtype} to float...") +# array = array.astype(float) + +# # ITK indices, by convention, are [i,j,k] while NumPy indices are [k,j,i] +# # https://www.slicer.org/wiki/Coordinate_systems + +# # ITK Numpy 3D +# # R (ight) i -> k -> x +# # A (nterior) j -> j -> y +# # S (uperior) k -> i -> z + +# array = np.transpose(array) +# bioxels_max = float(np.max(array)) +# bioxels_min = float(np.min(array)) +# bioxels_shape = array.shape + +# print("Bioxel Size:", bioxel_size) +# print("Bioxels Shape:", bioxels_shape) + +# bioxels_offset = 0.0 +# if bioxels_min < 0 and orig_dtype[0] != "u": +# bioxels_offset = -bioxels_min +# array = array + np.full_like(array, bioxels_offset) +# bioxels_max = float(np.max(array)) +# bioxels_min = float(np.min(array)) +# print("Offseted Max:", bioxels_max) +# print("Offseted Min:", bioxels_min) + +# points = [] +# for x in range(array.shape[0]): +# for y in range(array.shape[1]): +# for z in range(array.shape[2]): +# points.append({ +# "pos": (x, y, z), +# "value": array[x, y, z], +# }) + +# # # Build VDB +# # grid = vdb.FloatGrid() +# # grid.copyFromArray(array.copy()) + +# # # After sitk.DICOMOrient(), origin and direction will also orient base on LPS +# # # so we need to convert them into RAS +# # mat_lps2ras = axis_conversion( +# # from_forward='-Z', +# # from_up='-Y', +# # to_forward='-Z', +# # to_up='Y' +# # ).to_4x4() + +# # mat_location = mathutils.Matrix.Translation( +# # mathutils.Vector(image.GetOrigin()) +# # ) + +# # mat_rotation = mathutils.Matrix( +# # np.array(image.GetDirection()).reshape((3, 3)) +# # ).to_4x4() + +# # mat_scale = mathutils.Matrix.Scale( +# # bioxel_size, 4 +# # ) + +# # transfrom = mat_lps2ras @ mat_location @ mat_rotation @ mat_scale + +# obj = create_points_obj(points) + +# # Make transformation +# scene_scale = float(self.scene_scale) +# # (S)uperior -Z -> Y +# # (A)osterior Y -> Z +# mat_ras2blender = axis_conversion( +# from_forward='-Z', +# from_up='Y', +# to_forward='Y', +# to_up='Z' +# ).to_4x4() + +# mat_scene_scale = mathutils.Matrix.Scale( +# scene_scale, 4 +# ) + +# obj.matrix_world = mat_ras2blender @ mat_scene_scale + +# self.report({"INFO"}, "Successfully Imported") + +# return {'FINISHED'} + +# def invoke(self, context, event): +# # print(tuple(self.orig_shape)) +# self.auto = True +# self.bioxel_size = 1 +# context.window_manager.invoke_props_dialog(self) +# return {'RUNNING_MODAL'} diff --git a/bioxelnodes/menu.py b/bioxelnodes/menus.py similarity index 90% rename from bioxelnodes/menu.py rename to bioxelnodes/menus.py index 2bb5573..87fb317 100644 --- a/bioxelnodes/menu.py +++ b/bioxelnodes/menus.py @@ -1,6 +1,6 @@ import bpy from .convert import ConvertToMesh -from .io import ExportVDB, ImportDICOM +from .io import ExportVDB, ImportImage from .misc import SaveBioxels @@ -10,15 +10,15 @@ class ObjectMenu(bpy.types.Menu): def draw(self, context): layout = self.layout - layout.operator(SaveBioxels.bl_idname) - layout.separator() layout.operator(ConvertToMesh.bl_idname) + layout.separator() + layout.operator(SaveBioxels.bl_idname) def TOPBAR_FILE_IMPORT(self, context): layout = self.layout layout.separator() - layout.operator(ImportDICOM.bl_idname) + layout.operator(ImportImage.bl_idname) def TOPBAR_FILE_EXPORT(self, context): @@ -30,17 +30,16 @@ def TOPBAR_FILE_EXPORT(self, context): def VIEW3D_OBJECT(self, context): layout = self.layout layout.menu(ObjectMenu.bl_idname) - layout.separator() -def create_menu(): +def register(): bpy.types.TOPBAR_MT_file_import.append(TOPBAR_FILE_IMPORT) bpy.types.TOPBAR_MT_file_export.append(TOPBAR_FILE_EXPORT) bpy.types.VIEW3D_MT_object_context_menu.prepend(VIEW3D_OBJECT) -def remove_menu(): +def unregister(): bpy.types.TOPBAR_MT_file_import.remove(TOPBAR_FILE_IMPORT) bpy.types.TOPBAR_MT_file_export.remove(TOPBAR_FILE_EXPORT) bpy.types.VIEW3D_MT_object_context_menu.remove(VIEW3D_OBJECT) diff --git a/bioxelnodes/nodes.py b/bioxelnodes/nodes.py index 51edcca..74729f2 100644 --- a/bioxelnodes/nodes.py +++ b/bioxelnodes/nodes.py @@ -40,7 +40,7 @@ def set_prop_to_node_factory(source_prop, target_prop): MENU_ITEMS = [ { - 'label': 'Present', + 'label': 'Presets', 'icon': 'MESH_MONKEY', 'items': [ { @@ -52,17 +52,17 @@ def set_prop_to_node_factory(source_prop, target_prop): set_prop_to_node_factory("bioxel_size", "Detail Size"), set_prop_to_node_factory("bioxels_offset", "Offset"), ]) - }, - { - 'label': 'Anatomy', - 'icon': 'CONSTRAINT_BONE', - 'node_type': 'BioxelNodes_Anatomy', - 'node_description': '', - 'node_callback': "\n".join([ - set_prop_to_node_factory("bioxel_size", "Detail Size"), - set_prop_to_node_factory("bioxels_offset", "Offset"), - ]) } + # { + # 'label': 'Anatomy', + # 'icon': 'CONSTRAINT_BONE', + # 'node_type': 'BioxelNodes_Anatomy', + # 'node_description': '', + # 'node_callback': "\n".join([ + # set_prop_to_node_factory("bioxel_size", "Detail Size"), + # set_prop_to_node_factory("bioxels_offset", "Offset"), + # ]) + # } ] }, { @@ -71,7 +71,7 @@ def set_prop_to_node_factory(source_prop, target_prop): 'items': [ { 'label': 'Segment by Level', - 'icon': 'AREA_JOIN', + 'icon': 'EMPTY_SINGLE_ARROW', 'node_type': 'BioxelNodes_SegmentByLevel', 'node_description': '', 'node_callback': "\n".join([ @@ -81,24 +81,24 @@ def set_prop_to_node_factory(source_prop, target_prop): }, { 'label': 'Segment by Range', - 'icon': 'AREA_SWAP', + 'icon': 'IPO_CONSTANT', 'node_type': 'BioxelNodes_SegmentByRange', 'node_description': '', 'node_callback': "\n".join([ set_prop_to_node_factory("bioxel_size", "Detail Size"), set_prop_to_node_factory("bioxels_offset", "Offset"), ]) - }, - { - 'label': 'Segment by Layers', - 'icon': 'OUTLINER_OB_FORCE_FIELD', - 'node_type': 'BioxelNodes_SegmentsByLayers', - 'node_description': '', - 'node_callback': "\n".join([ - set_prop_to_node_factory("bioxel_size", "Detail Size"), - set_prop_to_node_factory("bioxels_offset", "Offset"), - ]) } + # { + # 'label': 'Segment by Layers', + # 'icon': 'ALIGN_JUSTIFY', + # 'node_type': 'BioxelNodes_SegmentsByLayers', + # 'node_description': '', + # 'node_callback': "\n".join([ + # set_prop_to_node_factory("bioxel_size", "Detail Size"), + # set_prop_to_node_factory("bioxels_offset", "Offset"), + # ]) + # } ] }, { @@ -112,8 +112,13 @@ def set_prop_to_node_factory(source_prop, target_prop): 'node_description': '' } ] - }, - { + } +] + +NODE_FILE = "BioxelNodes_4.0" + +if bpy.app.version >= (4, 1, 0): + MENU_ITEMS.append({ 'label': 'Slicer', 'icon': 'CLIPUV_DEHLT', 'items': [ @@ -136,12 +141,21 @@ def set_prop_to_node_factory(source_prop, target_prop): 'node_description': '', } ] - }, -] + }) + NODE_FILE = "BioxelNodes_4.1" + custom_nodes = CustomNodes( menu_items=MENU_ITEMS, - nodes_file=Path(__file__).parent/"assets/Nodes/BioxelNodes.blend", + nodes_file=Path(__file__).parent / f"assets/Nodes/{NODE_FILE}.blend", root_label='Bioxel Nodes', root_icon="FILE_VOLUME", ) + + +def register(): + custom_nodes.register() + + +def unregister(): + custom_nodes.unregister() diff --git a/bioxelnodes/preferences.py b/bioxelnodes/preferences.py index bb1036d..7972589 100644 --- a/bioxelnodes/preferences.py +++ b/bioxelnodes/preferences.py @@ -7,16 +7,30 @@ class BioxelNodesPreferences(bpy.types.AddonPreferences, ExternalPackagePreferen bl_idname = __package__ cache_dir: bpy.props.StringProperty( - name="VDB Cache Directory", + name="Set Cache Directory", subtype='DIR_PATH', default=str(Path(Path.home(), '.bioxelnodes')) ) # type: ignore + do_add_segmentnode: bpy.props.BoolProperty( + name="Add Segment Node", + default=True, + ) # type: ignore + + do_change_render_setting: bpy.props.BoolProperty( + name="Change Render Setting", + default=True, + ) # type: ignore + def draw(self, context): layout = self.layout - layout.label(text="Configuration") - layout.prop(self, 'cache_dir', text='Set Cache Directory') # ExternalPackagePreferences Config self.requirements_dir = str(Path(__file__).parent) super().draw(context) + + layout.label(text="Configuration") + layout.prop(self, 'cache_dir') + + layout.prop(self, "do_change_render_setting") + layout.prop(self, "do_add_segmentnode") diff --git a/bioxelnodes/props.py b/bioxelnodes/props.py new file mode 100644 index 0000000..d46bfd6 --- /dev/null +++ b/bioxelnodes/props.py @@ -0,0 +1,5 @@ +import bpy + +class BIOXELNODES_Series(bpy.types.PropertyGroup): + id: bpy.props.StringProperty() # type: ignore + label: bpy.props.StringProperty() # type: ignore diff --git a/bioxelnodes/utils.py b/bioxelnodes/utils.py index b00b070..8b797b0 100644 --- a/bioxelnodes/utils.py +++ b/bioxelnodes/utils.py @@ -2,9 +2,12 @@ import mathutils -def get_node_by_type(nodes, type_name: str): - return [node for node in nodes if type(node).__name__ == type_name] +def get_type(cls): + return type(cls).__name__ + +def get_node_by_type(nodes, type_name: str): + return [node for node in nodes if get_type(node) == type_name] def show_message(message="", title="Message Box", icon='INFO'): @@ -81,6 +84,7 @@ def get_bioxels_obj(current_obj): return bioxels_obj + def get_all_bioxels_objs(): bioxels_objs = [] @@ -88,10 +92,11 @@ def get_all_bioxels_objs(): if obj.parent: if obj.parent.get('bioxels_container') and obj.get('bioxels'): bioxels_objs.append(obj) - + return list(set(bioxels_objs)) -def extract_last_number(text): + +def get_text_index(text): # Initialize an empty string to store the digits digits = "" @@ -110,7 +115,7 @@ def extract_last_number(text): # Reverse the digits string to get the correct order last_number = digits[::-1] - return int(last_number) + return int(last_number) if last_number else None def add_driver(target_prop, var_sources, expression): From 5e8d12c564c6f4a5704e00ba5f4a57db9f8bd972 Mon Sep 17 00:00:00 2001 From: Ma Nan Date: Mon, 13 May 2024 12:09:11 +0800 Subject: [PATCH 3/4] fix: io --- bioxelnodes/__init__.py | 11 +- bioxelnodes/auto_load.py | 39 +++++-- bioxelnodes/io.py | 216 +++++++++++++++++++++++++-------------- bioxelnodes/menus.py | 8 +- bioxelnodes/utils.py | 4 +- 5 files changed, 182 insertions(+), 96 deletions(-) diff --git a/bioxelnodes/__init__.py b/bioxelnodes/__init__.py index 103e259..999d860 100644 --- a/bioxelnodes/__init__.py +++ b/bioxelnodes/__init__.py @@ -1,7 +1,7 @@ import bpy -from .nodes import custom_nodes from . import auto_load +from . import menus bl_info = { @@ -9,7 +9,7 @@ "author": "Ma Nan", "description": "", "blender": (4, 0, 0), - "version": (0, 1, 0), + "version": (0, 1, 1), "location": "File -> Import", "warning": "", "category": "Node" @@ -20,6 +20,7 @@ def register(): auto_load.register() + menus.add() bpy.types.Scene.bioxels_dir = bpy.props.StringProperty( name="Bioxels Directory", subtype='DIR_PATH', @@ -28,7 +29,5 @@ def register(): def unregister(): - try: - auto_load.unregister() - except RuntimeError: - pass + menus.remove() + auto_load.unregister() diff --git a/bioxelnodes/auto_load.py b/bioxelnodes/auto_load.py index d4006c8..6b4eede 100644 --- a/bioxelnodes/auto_load.py +++ b/bioxelnodes/auto_load.py @@ -16,6 +16,7 @@ modules = None ordered_classes = None + def init(): global modules global ordered_classes @@ -23,6 +24,7 @@ def init(): modules = get_all_submodules(Path(__file__).parent) ordered_classes = get_ordered_classes_to_register(modules) + def register(): for cls in ordered_classes: bpy.utils.register_class(cls) @@ -33,15 +35,22 @@ def register(): if hasattr(module, "register"): module.register() + def unregister(): for cls in reversed(ordered_classes): - bpy.utils.unregister_class(cls) + try: + bpy.utils.unregister_class(cls) + except Exception as e: + print(f"Fail to unregister {cls}, skiped") for module in modules: - if module.__name__ == __name__: - continue - if hasattr(module, "unregister"): - module.unregister() + try: + if module.__name__ == __name__: + continue + if hasattr(module, "unregister"): + module.unregister() + except Exception as e: + print(f"Fail to unregister {module}, skiped") # Import modules @@ -50,10 +59,12 @@ def unregister(): def get_all_submodules(directory): return list(iter_submodules(directory, directory.name)) + def iter_submodules(path, package_name): for name in sorted(iter_submodule_names(path)): yield importlib.import_module("." + name, package_name) + def iter_submodule_names(path, root=""): for _, module_name, is_package in pkgutil.iter_modules([str(path)]): if is_package: @@ -70,19 +81,24 @@ def iter_submodule_names(path, root=""): def get_ordered_classes_to_register(modules): return toposort(get_register_deps_dict(modules)) + def get_register_deps_dict(modules): my_classes = set(iter_my_classes(modules)) - my_classes_by_idname = {cls.bl_idname : cls for cls in my_classes if hasattr(cls, "bl_idname")} + my_classes_by_idname = { + cls.bl_idname: cls for cls in my_classes if hasattr(cls, "bl_idname")} deps_dict = {} for cls in my_classes: - deps_dict[cls] = set(iter_my_register_deps(cls, my_classes, my_classes_by_idname)) + deps_dict[cls] = set(iter_my_register_deps( + cls, my_classes, my_classes_by_idname)) return deps_dict + def iter_my_register_deps(cls, my_classes, my_classes_by_idname): yield from iter_my_deps_from_annotations(cls, my_classes) yield from iter_my_deps_from_parent_id(cls, my_classes_by_idname) + def iter_my_deps_from_annotations(cls, my_classes): for value in typing.get_type_hints(cls, {}, {}).values(): dependency = get_dependency_from_annotation(value) @@ -90,6 +106,7 @@ def iter_my_deps_from_annotations(cls, my_classes): if dependency in my_classes: yield dependency + def get_dependency_from_annotation(value): if blender_version >= (2, 93): if isinstance(value, bpy.props._PropertyDeferred): @@ -100,6 +117,7 @@ def get_dependency_from_annotation(value): return value[1]["type"] return None + def iter_my_deps_from_parent_id(cls, my_classes_by_idname): if bpy.types.Panel in cls.__bases__: parent_idname = getattr(cls, "bl_parent_id", None) @@ -108,6 +126,7 @@ def iter_my_deps_from_parent_id(cls, my_classes_by_idname): if parent_cls is not None: yield parent_cls + def iter_my_classes(modules): base_types = get_register_base_types() for cls in get_classes_in_modules(modules): @@ -115,6 +134,7 @@ def iter_my_classes(modules): if not getattr(cls, "is_registered", False): yield cls + def get_classes_in_modules(modules): classes = set() for module in modules: @@ -122,11 +142,13 @@ def get_classes_in_modules(modules): classes.add(cls) return classes + def iter_classes_in_module(module): for value in module.__dict__.values(): if inspect.isclass(value): yield value + def get_register_base_types(): return set(getattr(bpy.types, name) for name in [ "Panel", "Operator", "PropertyGroup", "FileHandler", @@ -151,5 +173,6 @@ def toposort(deps_dict): sorted_values.add(value) else: unsorted.append(value) - deps_dict = {value : deps_dict[value] - sorted_values for value in unsorted} + deps_dict = {value: deps_dict[value] - + sorted_values for value in unsorted} return sorted_list diff --git a/bioxelnodes/io.py b/bioxelnodes/io.py index 7aeadcc..3285caa 100644 --- a/bioxelnodes/io.py +++ b/bioxelnodes/io.py @@ -7,7 +7,7 @@ from uuid import uuid4 import mathutils import math -from .utils import calc_bbox_verts, get_text_index, get_bioxels_obj, get_node_by_type, show_message +from .utils import calc_bbox_verts, get_text_index_str, get_bioxels_obj, get_node_by_type, show_message from .nodes import custom_nodes from .props import BIOXELNODES_Series try: @@ -52,30 +52,16 @@ def get_bioxels_shape(bioxel_size: float, orig_shape: tuple, orig_spacing: tuple): - return ( - math.ceil(orig_shape[0] / bioxel_size * orig_spacing[0]), - math.ceil(orig_shape[1] / bioxel_size * orig_spacing[1]), - math.ceil(orig_shape[2] / bioxel_size * orig_spacing[2]), - ) + shape = (int(orig_shape[0] / bioxel_size * orig_spacing[0]), + int(orig_shape[1] / bioxel_size * orig_spacing[1]), + int(orig_shape[2] / bioxel_size * orig_spacing[2])) + return (shape[0] if shape[0] > 0 else 1, + shape[1] if shape[1] > 0 else 1, + shape[2] if shape[2] > 0 else 1) -def collect_image_sequence(filepath: str): - file_path = Path(filepath).resolve() - - files = list(file_path.parent.iterdir()) - files = [f for f in files if f.is_file() - and get_ext(file_path) == get_ext(f) - and get_text_index(f.stem)] - def get_index(f: Path): - return get_text_index(f.stem) - - files.sort(key=get_index) - sequence = [str(f) for f in files] - return sequence - - -def get_ext(filepath: str): +def get_ext(filepath: str) -> str: file_path = Path(filepath) if file_path.name.endswith(".nii.gz"): return ".nii.gz" @@ -87,11 +73,38 @@ def get_ext(filepath: str): return file_path.suffix +def get_sequence_name(filepath: str) -> str: + ext = get_ext(filepath) + filename = Path(filepath).name.removesuffix(ext) + index: str = get_text_index_str(filename) + return filename.removesuffix(index) + + +def get_sequence_index(filepath: str) -> int: + ext = get_ext(filepath) + filename = Path(filepath).name.removesuffix(ext) + index: str = get_text_index_str(filename) + return int(index) if index else 0 + + +def collect_image_sequence(filepath: str): + file_path = Path(filepath).resolve() + + files = list(file_path.parent.iterdir()) + files = [f for f in files if f.is_file() + and get_ext(file_path) == get_ext(f) + and get_sequence_name(file_path) == get_sequence_name(f)] + + files.sort(key=get_sequence_index) + sequence = [str(f) for f in files] + return sequence + + def read_image(filepath: str, series_id=""): ext = get_ext(filepath) - dir_path = Path(filepath).resolve().parent - filename = Path(filepath).resolve().stem + if ext in DICOM_EXTS: + dir_path = Path(filepath).resolve().parent reader = sitk.ImageSeriesReader() reader.MetaDataDictionaryArrayUpdateOn() reader.LoadPrivateTagsOn() @@ -99,19 +112,36 @@ def read_image(filepath: str, series_id=""): str(dir_path), series_id) reader.SetFileNames(series_files) image = reader.Execute() - elif ext in SEQUENCE_EXTS and get_text_index(filename): - sequence = collect_image_sequence(filepath) - image = sitk.ReadImage(sequence) - else: + name = dir_path.name + + elif ext in SEQUENCE_EXTS: image = sitk.ReadImage(filepath) if image.GetDimension() == 2: - image = sitk.ReadImage([filepath]) + sequence = collect_image_sequence(filepath) + image = sitk.ReadImage(sequence) + name = get_sequence_name(filepath) + else: + image = sitk.ReadImage(filepath) + name = Path(filepath).name.removesuffix(ext) + else: + image = sitk.ReadImage(filepath) + name = Path(filepath).name.removesuffix(ext) - return image + return image, name -class ImportImageDialog(bpy.types.Operator): - bl_idname = "bioxelnodes.import_image_dialog" +def rgb2gray(image): + # Convert sRGB image to gray scale and rescale results to [0,255] + channels = [sitk.VectorIndexSelectionCast( + image, i, sitk.sitkFloat32) for i in range(image.GetNumberOfComponentsPerPixel())] + # linear mapping + I = (0.2126*channels[0] + 0.7152*channels[1] + 0.0722*channels[2]) + + return sitk.Cast(I, sitk.sitkFloat32) + + +class ImportVolumeDataDialog(bpy.types.Operator): + bl_idname = "bioxelnodes.import_volume_data_dialog" bl_label = "Volume Data as Bioxels" bl_description = "Import Volume Data as Bioxels (VDB)" bl_options = {'UNDO'} @@ -123,10 +153,19 @@ class ImportImageDialog(bpy.types.Operator): series_id: bpy.props.StringProperty() # type: ignore + resample_method: bpy.props.EnumProperty( + name="Resample Method", + default="linear", + items=[("linear", "Linear", ""), + ("nearest_neighbor", "Nearest Neighbor", ""), + ("gaussian", "Gaussian", "")] + ) # type: ignore + read_as: bpy.props.EnumProperty( name="Read as", default="scalar", - items=[("scalar", "Scalar", ""), ("labels", "Labels", "")] + items=[("scalar", "Scalar", ""), + ("labels", "Labels", "")] ) # type: ignore label_index: bpy.props.IntProperty( @@ -169,11 +208,7 @@ class ImportImageDialog(bpy.types.Operator): ) # type: ignore def execute(self, context): - bioxels_name = Path(self.filepath).parent.name \ - if get_ext(self.filepath) in SEQUENCE_EXTS \ - else Path(self.filepath).name.removesuffix(get_ext(self.filepath)) - - image = read_image(self.filepath, self.series_id) + image, bioxels_name = read_image(self.filepath, self.series_id) bioxel_size = self.bioxel_size orig_spacing = self.orig_spacing @@ -189,16 +224,37 @@ def execute(self, context): bioxels_shape = get_bioxels_shape( bioxel_size, image_shape, orig_spacing) - print("Resampling...") + if self.read_as == "labels": + image = sitk.Cast(image, sitk.sitkUInt16) + default_value = 0 + elif self.read_as == "scalar": + if "vector" in image.GetPixelIDTypeAsString(): + print("Convet to Grayscale...") + image = rgb2gray(image) + else: + image = sitk.Cast(image, sitk.sitkFloat32) + + stats = sitk.StatisticsImageFilter() + stats.Execute(image) + default_value = stats.GetMaximum() if self.invert_scalar else stats.GetMinimum() + + if self.resample_method == "linear": + interpolator = sitk.sitkLinear + elif self.resample_method == "nearest_neighbor": + interpolator = sitk.sitkNearestNeighbor + elif self.resample_method == "gaussian": + interpolator = sitk.sitkGaussian + + print(f"Resampling...") image = sitk.Resample( image1=image, size=bioxels_shape, transform=sitk.Transform(), - interpolator=sitk.sitkLinear, + interpolator=interpolator, outputOrigin=image.GetOrigin(), outputSpacing=bioxels_spacing, outputDirection=image.GetDirection(), - defaultPixelValue=0, + defaultPixelValue=default_value, outputPixelType=image.GetPixelID(), ) @@ -219,17 +275,20 @@ def execute(self, context): # A (nterior) j -> j -> y # S (uperior) k -> i -> z array = sitk.GetArrayFromImage(image) - array = np.transpose(array) orig_dtype = str(array.dtype) # print(f"Coverting Dtype from {orig_dtype} to float...") # array = array.astype(float) + if array.ndim == 4: - if array.shape[3] == 3 and self.read_as == "scalar": - # RGB -> Grayscale - array = np.dot(array[..., :3], [0.2989, 0.5870, 0.1140]) - else: - array = array[:, :, :, 0] + # if array.shape[0] == 3 and self.read_as == "scalar": + # # RGB -> Grayscale + # array = np.dot(array[..., :3], [0.2989, 0.5870, 0.1140]) + # else: + # array = array[:, :, :, 0] + array = array[:, :, :, 0] + + array = np.transpose(array) bioxels_shape = array.shape bioxels_offset = 0.0 @@ -260,16 +319,14 @@ def execute(self, context): bioxels_max = float(np.max(array)) bioxels_min = float(np.min(array)) - stat_table = [("Max", orig_max), - ("Min", orig_min), - ("Median", orig_median), - ("Percentile 80%", orig_percentile80), - ("Max (Offset)", bioxels_max), - ("Min (Offset)", bioxels_min)] + stats_table = [("Max", orig_max), + ("Min", orig_min), + ("Median", orig_median), + ("80%", orig_percentile80)] - print("Bioxels Value Stat: Max:") - for stat in stat_table: - print("| {: >20} | {: >20} |".format(*stat)) + print("Bioxels Value Stats:") + for stats in stats_table: + print("| {: >10} | {: >40} |".format(*stats)) # # Build VDB grid = vdb.BoolGrid() if self.read_as == "labels" else vdb.FloatGrid() @@ -436,6 +493,7 @@ def draw(self, context): text += "**TOO LARGE!**" panel = layout.box() + panel.prop(self, "resample_method") panel.prop(self, "bioxel_size") row = panel.row() row.prop(self, "orig_spacing") @@ -472,9 +530,8 @@ class ReadDICOM(bpy.types.Operator): bl_description = "Import Volume Data as Bioxels (VDB)" bl_options = {'UNDO'} - filepath: bpy.props.StringProperty( - subtype="FILE_PATH" - ) # type: ignore + filepath: bpy.props.StringProperty(subtype="FILE_PATH") # type: ignore + directory: bpy.props.StringProperty(subtype='DIR_PATH') # type: ignore series_id: bpy.props.EnumProperty( name="Select Series", @@ -490,20 +547,27 @@ def execute(self, context): self.report({"WARNING"}, "Not supported extension.") return {'CANCELLED'} - image = read_image(self.filepath, self.series_id) - print("Collecting Meta Data...") - print("Original Shape:", image.GetSize()) - print("Original Spacing:", image.GetSpacing()) - print("Original Origin:", image.GetOrigin()) - print("Original Direction:", image.GetDirection()) + image, name = read_image(self.filepath, self.series_id) + stats_table = [("Shape", str(image.GetSize())), + ("Spacing", str(image.GetSpacing())), + ("Origin", str(image.GetOrigin())), + ("Direction", str(image.GetDirection())), + ("Data Type", image.GetPixelIDTypeAsString())] + + print("Meta Data:") + for stats in stats_table: + print("| {: >10} | {: >40} |".format(*stats)) - bpy.ops.bioxelnodes.import_image_dialog( + do_orient = ext not in SEQUENCE_EXTS or ext in DICOM_EXTS + + bpy.ops.bioxelnodes.import_volume_data_dialog( 'INVOKE_DEFAULT', filepath=self.filepath, orig_shape=image.GetSize(), orig_spacing=image.GetSpacing(), - series_id=self.series_id or "" + series_id=self.series_id or "", + do_orient=do_orient ) self.report({"INFO"}, "Successfully Readed.") @@ -515,7 +579,7 @@ def modal(self, context, event): return {'FINISHED'} def invoke(self, context, event): - if not self.filepath: + if not self.filepath and not self.directory: return {'CANCELLED'} show_message('Reading image data, it may take a while...', @@ -551,20 +615,20 @@ def draw(self, context): text="Please be patient...") -class ImportImage(bpy.types.Operator): - bl_idname = "bioxelnodes.import_image" +class ImportVolumeData(bpy.types.Operator): + bl_idname = "bioxelnodes.import_volume_data" bl_label = "Volume Data as Bioxels" bl_description = "Import Volume Data as Bioxels (VDB)" bl_options = {'UNDO'} - filepath: bpy.props.StringProperty( - subtype="FILE_PATH" - ) # type: ignore + filepath: bpy.props.StringProperty(subtype="FILE_PATH") # type: ignore + directory: bpy.props.StringProperty(subtype='DIR_PATH') # type: ignore def execute(self, context): bpy.ops.bioxelnodes.read_dicom( 'INVOKE_DEFAULT', - filepath=self.filepath + filepath=self.filepath, + directory=self.directory ) return {'FINISHED'} @@ -574,8 +638,8 @@ def invoke(self, context, event): try: - class BIOXELNODES_FH_ImportImage(bpy.types.FileHandler): - bl_idname = "BIOXELNODES_FH_ImportImage" + class BIOXELNODES_FH_ImportVolumeData(bpy.types.FileHandler): + bl_idname = "BIOXELNODES_FH_ImportVolumeData" bl_label = "File handler for dicom import" bl_import_operator = "bioxelnodes.read_dicom" bl_file_extensions = ";".join(FH_EXTS) diff --git a/bioxelnodes/menus.py b/bioxelnodes/menus.py index 87fb317..82d3c65 100644 --- a/bioxelnodes/menus.py +++ b/bioxelnodes/menus.py @@ -1,6 +1,6 @@ import bpy from .convert import ConvertToMesh -from .io import ExportVDB, ImportImage +from .io import ExportVDB, ImportVolumeData from .misc import SaveBioxels @@ -18,7 +18,7 @@ def draw(self, context): def TOPBAR_FILE_IMPORT(self, context): layout = self.layout layout.separator() - layout.operator(ImportImage.bl_idname) + layout.operator(ImportVolumeData.bl_idname) def TOPBAR_FILE_EXPORT(self, context): @@ -33,13 +33,13 @@ def VIEW3D_OBJECT(self, context): layout.separator() -def register(): +def add(): bpy.types.TOPBAR_MT_file_import.append(TOPBAR_FILE_IMPORT) bpy.types.TOPBAR_MT_file_export.append(TOPBAR_FILE_EXPORT) bpy.types.VIEW3D_MT_object_context_menu.prepend(VIEW3D_OBJECT) -def unregister(): +def remove(): bpy.types.TOPBAR_MT_file_import.remove(TOPBAR_FILE_IMPORT) bpy.types.TOPBAR_MT_file_export.remove(TOPBAR_FILE_EXPORT) bpy.types.VIEW3D_MT_object_context_menu.remove(VIEW3D_OBJECT) diff --git a/bioxelnodes/utils.py b/bioxelnodes/utils.py index 8b797b0..cbd5d0d 100644 --- a/bioxelnodes/utils.py +++ b/bioxelnodes/utils.py @@ -96,7 +96,7 @@ def get_all_bioxels_objs(): return list(set(bioxels_objs)) -def get_text_index(text): +def get_text_index_str(text): # Initialize an empty string to store the digits digits = "" @@ -115,7 +115,7 @@ def get_text_index(text): # Reverse the digits string to get the correct order last_number = digits[::-1] - return int(last_number) if last_number else None + return last_number def add_driver(target_prop, var_sources, expression): From c1886f95f83f7e9739822f9a64537e3ea1397c35 Mon Sep 17 00:00:00 2001 From: Ma Nan Date: Tue, 14 May 2024 09:39:43 +0800 Subject: [PATCH 4/4] docs: mkdocs --- .github/workflows/upload-assets.yml | 56 +- .prettierrc | 11 + README.md | 117 +- docs/{images => assets}/bake_node.png | Bin docs/{images => assets}/dependency.png | Bin docs/{images => assets}/gallery.png | Bin docs/{images => assets}/general_graph.png | Bin .../general_graph_example.png | Bin docs/{images => assets}/import_dialog.png | Bin docs/{images => assets}/importing.png | Bin docs/assets/logo.png | Bin 0 -> 32184 bytes docs/{images => assets}/result.png | Bin docs/{images => assets}/segment_node.png | Bin docs/features.md | 5 + docs/getting-started.md | 60 + docs/index.md | 45 + docs/misc.md | 20 + docs/nodes.md | 0 docs/stylesheets/extra.css | 20 + mkdocs.yml | 82 + poetry.lock | 1966 +++++++++++++++++ pyproject.toml | 29 + tests/__init__.py | 0 23 files changed, 2292 insertions(+), 119 deletions(-) create mode 100644 .prettierrc rename docs/{images => assets}/bake_node.png (100%) rename docs/{images => assets}/dependency.png (100%) rename docs/{images => assets}/gallery.png (100%) rename docs/{images => assets}/general_graph.png (100%) rename docs/{images => assets}/general_graph_example.png (100%) rename docs/{images => assets}/import_dialog.png (100%) rename docs/{images => assets}/importing.png (100%) create mode 100644 docs/assets/logo.png rename docs/{images => assets}/result.png (100%) rename docs/{images => assets}/segment_node.png (100%) create mode 100644 docs/features.md create mode 100644 docs/getting-started.md create mode 100644 docs/index.md create mode 100644 docs/misc.md create mode 100644 docs/nodes.md create mode 100644 docs/stylesheets/extra.css create mode 100644 mkdocs.yml create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 tests/__init__.py diff --git a/.github/workflows/upload-assets.yml b/.github/workflows/upload-assets.yml index 0f7e9d8..7c6898b 100644 --- a/.github/workflows/upload-assets.yml +++ b/.github/workflows/upload-assets.yml @@ -6,31 +6,8 @@ on: - "release/*" jobs: - draft_release: - name: Draft Release - runs-on: ubuntu-latest - outputs: - upload_url: ${{ steps.draft_release.outputs.upload_url }} - version: ${{ steps.set_env.outputs.version }} - steps: - - name: Set Version Env - id: set_env - run: | - ref_name=${{ github.ref_name }} - echo "version=${ref_name#release/}" >> "$GITHUB_OUTPUT" - - name: Get release - id: draft_release - uses: cardinalby/git-get-release-action@1.2.4 - with: - releaseName: Draft - env: - GITHUB_TOKEN: ${{ github.token }} - # draft_release: # name: Draft Release - # permissions: - # contents: write - # pull-requests: write # runs-on: ubuntu-latest # outputs: # upload_url: ${{ steps.draft_release.outputs.upload_url }} @@ -41,14 +18,37 @@ jobs: # run: | # ref_name=${{ github.ref_name }} # echo "version=${ref_name#release/}" >> "$GITHUB_OUTPUT" - # - name: Draft Release ${{ steps.set_env.outputs.version }} - # uses: release-drafter/release-drafter@v5 + # - name: Get release # id: draft_release + # uses: cardinalby/git-get-release-action@1.2.4 # with: - # name: ${{ steps.set_env.outputs.version }} - # tag: ${{ steps.set_env.outputs.version }} + # releaseName: Draft # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # GITHUB_TOKEN: ${{ github.token }} + + draft_release: + name: Draft Release + permissions: + contents: write + pull-requests: write + runs-on: ubuntu-latest + outputs: + upload_url: ${{ steps.draft_release.outputs.upload_url }} + version: ${{ steps.set_env.outputs.version }} + steps: + - name: Set Version Env + id: set_env + run: | + ref_name=${{ github.ref_name }} + echo "version=${ref_name#release/}" >> "$GITHUB_OUTPUT" + - name: Draft Release ${{ steps.set_env.outputs.version }} + uses: release-drafter/release-drafter@v5 + id: draft_release + with: + name: ${{ steps.set_env.outputs.version }} + tag: ${{ steps.set_env.outputs.version }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} upload_blender_addon: name: Upload Blender Add-on diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..ab27099 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,11 @@ +{ + "tabWidth": 2, + "overrides": [ + { + "files": "*.md", + "options": { + "tabWidth": 4 + } + } + ] +} diff --git a/README.md b/README.md index 909cbc5..2c01e8c 100644 --- a/README.md +++ b/README.md @@ -15,96 +15,31 @@ Before us, there have been many tutorials and add-ons for importing volumetric d Below are some examples with Bioxel Nodes. Thanks to Cycles Render, the volumetric data can be rendered with great detail: -![gallery](docs/images/gallery.png) +![gallery](assets/gallery.png) + +The "Bioxel" in "BioxelNodes", is a combination of the words "Bio-" and "Voxel". Bioxel is a voxel that stores biological data. The volumetric data made up of Bioxel is called Bioxels. We are developing a toolkit around Bioxels for better biological data visualization. but before its release, we made this Blender version of bioxels toolkit first, in order to let more people to have fun with volumetric data. [Getting Started](https://omoolab.github.io/BioxelNodes/latest/getting-started) + +# Supported Format + +| Format | EXT | Test | +| ------ | ---------------------------------------- | ------- | +| DICOM | .dcm, .DICOM | ✅ pass | +| BMP | .bmp, .BMP | ✅ pass | +| JPEG | .jpg, .JPG, .jpeg, .JPEG | ✅ pass | +| PNG | .png, .PNG | ✅ pass | +| TIFF | .tif, .TIF, .tiff, .TIFF | ✅ pass | +| Nifti | .nia, .nii, .nii.gz, .hdr, .img, .img.gz | ✅ pass | +| Nrrd | .nrrd, .nhdr | ✅ pass | +| Meta | .mha, .mhd | yet | +| HDF5 | .hdf, .h4, .hdf4, .he2, .h5, .hdf5, .he5 | ✅ pass | +| VTK | .vtk | yet | +| BioRad | .PIC, .pic | yet | +| Gipl | .gipl, .gipl.gz | yet | +| LSM | .lsm, .LSM | yet | +| MINC | .mnc, .MNC | yet | +| MRC | .mrc, .rec | yet | + +# Known limitations -### Known limitations - -- Cannot read DICOM with multiple series. - Sections cannot be generated -- Only sequence files are supported, packed volume data formats are not supported yet (will be supported soon) - -# Getting Started - -Currently only support Blender 4.1 or above, make sure you have the correct version of Blender. - -### Add-on Installation - -Download the latest version https://github.com/OmooLab/BioxelNodes/releases/latest -In Blender, `Edit - Preferences - Add-ons - Install`, select the `BioxelNodes_{version}.zip` you just downloaded. - -### Dependency Installation - -The add-on requires a third-party python dependency called SimpleITK, click the Install SimpleITK button below to install the dependency. After clicking, blender may get stuck, it is downloading and installing, just wait for a moment. After the Installation, **restart blender once**. - -![dependency](docs/images/dependency.png) - -This step may have failed due to network factors, just click "Set PyPI Mirror" to change the mirror. - -### Basic Usage - -First you need to have your volumetric data ready. If not, you can access open research data from [Dryad](https://datadryad.org) (Dryad publishes data exclusively under a [Creative Commons Public Domain License](https://creativecommons.org/public-domain/cc0/)) - -Note: Make sure one folder contains only one sequence, multiple sequences need to be manually split into different folders first. - -In Blender, `File - Import - Volume Data as Bioxels`, select **one** of the .dcm files and click on "Volume Data as Bioxels" (you can also drag one of the .dcm files directly into the 3D viewport to trigger the import, but this is limited to .dcm format files) - -![importing](docs/images/importing.png) - -It may take a while to read data. After finishing reading, it will pop up a dialog box - -![import dialog](docs/images/import_dialog.png) - -Ignore the options, just click OK! - -After importing, the necessary nodes are automatically added, the reconstruction and shader are created, and then turned on the cycles rendering to directly see the result. - -![result](docs/images/result.png) - -Click select Bioxels Object, and open the Geometry Nodes panel to see the following node graph: - -![segment node](docs/images/segment_node.png) - -You can change the "Threshold" to modify the reconstruction model, or change the "Color", "Density" to modify the shader effect. All the parameters are straightforward, you can understand them by changing the values. - -The node, that named "Segment", is a preset node that combines the steps of 3D reconstruction process and shading process. In general, you need to add one of the segmentation node to reconstruction first, and followed by one of the shader node to set the shader. As you can see in the following figure: - -![general graph](docs/images/general_graph.png) - -Currently there are 3 types of nodes - -- Segmentation nodes, responsible for splitting the volume into a reconstructed model (we call them "Segment"). -- Shader nodes, responsible for giving shader to the Segment. -- Slicer nodes, responsible for partially cutting the Segment. - -For example: - -![general graph example](docs/images/general_graph_example.png) - -You can add a "Bake" node between segmentation node and shader node, if the reconstruction process consumes too much computing time. But be sure, you are selecting the volume object, not the container object. - -![bake node](docs/images/bake_node.png) - -# Future Features - -- Support more volumetric data formats (.nii, .map, .txm...) -- Generate sections -- More segmentation methods, e.g. AI segmentation. -- Even better shader for volumetric rendering - -# Technical Notes - -The "Bioxel" in "BioxelNodes", is a combination of the words "Bio-" and "Voxel". Bioxel is a voxel that stores biological data, so maybe its chinese name should be "生素" 😂? The volumetric data made up of Bioxel is called Bioxels. We are developing a toolkit around Bioxels for better biological data visualization. but before its release, we made this Blender version of bioxels toolkit first, in order to let more people to have fun with volumetric data. - -### Bioxels - -Bioxels is based on the RAS coordinate system, Right Aanterior Superior, which was chosen over LPS because it is more compatible with most 3D CG software coordinate systems, and is in line with the 3D artist's understanding of space. - -All distances within Bioxels are in Units, and are specified in Meter pre unit. However, when Bioxels is imported into 3D CG software, its size in the software is not scaled by reading the Meter pre unit directly. The reason for this is that many 3D operations in software require that the primtives not be too large or too small. - -### Based on OpenVDB - -Bioxels is based entirely on OpenVDB for storage and rendering. The main reason for choosing OpenVDB is that as a volumetric data format, it is the fastest way to work with most CG renderers. - -### Based on Geometry Nodes - -Bioxel Nodes relies on Blender Geometry Nodes to reconstruct and render volumetric data. Node-based operations ensure that the original data is not permanently altered during reconstruction and rendering operations. The fact that the processing is based on Geometry Nodes without any additional dependencies also ensures that Blender can open files without this plugin installed. Look for more support for OpenVDB in GeometryNodes so that Bioxel Nodes can do more in the future. +- Time sequence volume not supported (will be supported soon) diff --git a/docs/images/bake_node.png b/docs/assets/bake_node.png similarity index 100% rename from docs/images/bake_node.png rename to docs/assets/bake_node.png diff --git a/docs/images/dependency.png b/docs/assets/dependency.png similarity index 100% rename from docs/images/dependency.png rename to docs/assets/dependency.png diff --git a/docs/images/gallery.png b/docs/assets/gallery.png similarity index 100% rename from docs/images/gallery.png rename to docs/assets/gallery.png diff --git a/docs/images/general_graph.png b/docs/assets/general_graph.png similarity index 100% rename from docs/images/general_graph.png rename to docs/assets/general_graph.png diff --git a/docs/images/general_graph_example.png b/docs/assets/general_graph_example.png similarity index 100% rename from docs/images/general_graph_example.png rename to docs/assets/general_graph_example.png diff --git a/docs/images/import_dialog.png b/docs/assets/import_dialog.png similarity index 100% rename from docs/images/import_dialog.png rename to docs/assets/import_dialog.png diff --git a/docs/images/importing.png b/docs/assets/importing.png similarity index 100% rename from docs/images/importing.png rename to docs/assets/importing.png diff --git a/docs/assets/logo.png b/docs/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..73e77b4ea5f0cde2839aa432f847c50696772c5d GIT binary patch literal 32184 zcmeFY_dnHd{6GFg5gBzV*(xitR~)30%_$DDx9sedj3Safk4@p&duNX*$I9M9hwSX^ z?{&Q1@9+2X{Rh53eY@Sd;rYCtkL$V~*JD5KSI`TDEEx$62?Rl8@^a5qA?VT^1mQHFUCxjQ?DnLQ+c~S1^TsAS|E{wCMj?L2%7kkSXIy|4#)%`Tp7r zJ~`js=?4UNeucP_`r0fh@Izn7)|rUzO!Plm_vV-GxJdNx-{lY57sY~6BKRlG=D=0TvlQf&k}?)2 z>A7$Idy_%p&2FGbO_I5Z0drMs8)Mjwqiwgw)!&tLJl-28(!ON!q>5|WCuaJ*R#)vFp5uZTfcuqr_{v#yCtgMUe4XVULUuw@4dM9eHPDmM8360mj=0Pfxf;! zVO^Zk-IvTW`JLt|yg19Niiv($Hl-MDSs&X(SQ67-?Vb@Gw)7*K?Z&?A{LB*qViWm5 zVb~7rY`~+ZR^-YW>w0Z_MSIm|=k>7D{>FTX-fv$DQ48(0+bTRIxsgs^}}`wAf86`dYL@A}L;{y=Ge$;?;_>zY!TQ zu9Koxi#5lDmQ81VrffQ%-rSJyYI(~U^?Io{#q$CEfCeG$NUUZ&RXpCO_I77O3?p9b z&nlfB<7@jf4W4O=U3k3eQTDeKmjqPTUH8|IDbpcNA>3`oV`*Bj*ZI*ylb>>mY`Z%M z59*wDL{*_l^JgEo&6(4;D$-xtNKP?Fwo8o%asNh&3kwT*Zp?l?pT02*`RZ}WNZZZS zd#oneHIAP#HFOE}RwAOx-(G6I0y}uLA?|(hPu@eEdhE8r+tS#)HfG|kPJEl@dyNwA ze}5TyOi^hTod(ixkwIgTgcEzKqjqxjq2`eh7;}|JlTX(Sw1S1hO*%NLP{34N7Mt(Q`if`E-wLgU76GFoB-Xv8C_H(-m_8WR=+5Jp! zJE2NWcgdSsd@$@FUl12g1I0(Z4VpAH@(zh>ogsx+F!|k(?+6O4c>315^Il_YI0KZU z6=f$QyVPgFej>M2p@(+lb2}{RbMvmnTFTAqG){tI~Lr_fkf+ddV}w&f@EmwRH!?X z%_f#ZX&*jfuNGTVG>>KfS!8kxor~Z6c>6 zs$o!xJjY|rKvOy-iag*qZD4F~-ZWvZd}GoMz20jT&7^;X5G@+tzl~S5>t+_5`QUYJ zs1cL126a-G{?YcY7QaA3eY{`SoS%+oPAM+IvHR~ivIvZYFp zQBg(S{1e1sfEmQ025UKzF< zk`w=367^juMg8=Wp98n^xrK1a#%*(-eRCge{Q&vz62~u7m}JB1k0?^M z`RVTen5;|5kPS~9>9+ap?R_xqHhY|w;M^>o65=4VuL-F;Mxw*7&{b^Rvx8$< z;wuZ>+_!)KFgWvp2ialGpd8ds)kW?D_u6SASwe<_bD8|tzz950PschKvTo~{OBiUI z5nh6#BVZfb)0fL%eZ{}J>Ef(rsRu8RmqB&DCsv$qDeApbgx5XJiOzUMpGhHxz4?l3 z@RrTkLED`_`9tMD8uoY|k4Jx+h^yubF#8g%y!n9aBeElhm7&~}#>h`1zRS6dFm5s|5e0*IjISRy z_hV93y9BYwpYXhzvs`b#v)qpa@u_(a<|ye^h($D&QxnA8Hl}(6)bx$-Q93;Dymgep zQ6!l+Ybe4o523Rs6h!D%M8xaRh~OHcHsq~p(c5Au9)m{Xzc&M7Kh=yH_?)VVUQRbw zXPt9?X5_>?kG`8R7UW4i%*}&G0DCZs%FUKZzFmBV%&vbXJrJb4P@9a;q`-dy{F0rE z!_FTR(DOdI?RB43+&F_XiXRViI*Yyc@|#X9W!La?UaHI2I6v!4lRVcDy)66(h+^OQ zVW~-{w?i?IUVKKkuZ?Tx<;nQBzBfywH5-pN>Nd?rTVzwVWqUk}qkm88q(~l@OCAqy z^S=mcFWQ8k53%#$y@<4mvWI`^Z&Guox?3nq$#-6d5WUP1ZK@lk9OW>}He0sp>b>|i z2KA2QRDH?2lLiIth$HrVgDcdPQBHj^O*s={PiFsA;%mp&) zS7`7kVfOd;tH=4&?~$i-XRzT;fG!(u;L^oTP(~oAGc|h zXiQNbv_~yOoXteC@ROHT7G4eH#Qpw8i}=)6m(}vwlf{Q=y+$vXtmRp@;?kn*cqw#r zbPUi9FA;cD<2mv*o#BjCS5 zyilri24Sl|2Jl*)6h{)ld$%0NBahBbj}K?>t2^epij9hTZ2#tozOS}Lxc)p)fMk>hWW~y$F>&-;q3Dk~|*oJKJRheg`7#_k?X2F99EPGu~It&TI5A8=TiI z(<85u_YblmX!vj#=nv{Z?3E-$nmxLllMoiGhqpd*dC)|A<&BcmWeDB6@egVPmT~P{ zPtrp>V9*4y<2?ep2(1Au230KAj0YhjgcT>afnKNX3DXM=mh#`KOvb-qs=Z=$L7<~T z&3A5>pMKbxGd^5NQNm%q-C^+N{(%+S;N~|8$k2+POK82pk>v67H@W`h5AJl!x+7Lp{1^L$U9pj}-(oV*= z;GT|W&Y1&#r=3Y<*AG>k7e>4AVsMj>XW|Bd{oEI=z`AGeNqge9TGZ_g{ppk$@vnP( zSmyF2{q92$`>T^Dv25T$PO(-sI4|x?ChE+hOSv(%5`#>?ZZ2lv+GUAUYXJjLR{z=R z)pABic)35;KJQ7oGMD5r5E)*#+Od%g+hns7Km2GX?fk?-H081b1@uc6XB8U{7n97v zi9OK#3fpK13%g&E77~VbEJ#M^=lOsm^JPqt@D%Q87_T^h0xFzguX}@w2$BS{l}X#d zOO)5&79wE_NV83KP{sB;R4{L0zH)W{lP3h#l|Lb9eiN7HFED^tU`$Rc82<_nDiNa< zgbK`a6-2H^6XeIY5t0FJG|$-dLnU7c9?YqdePJRgFkYb*{0Jx<<0!0D@H)1ma_^q)o_@7 zGaM%7JrunlE-O!5^tXYSS8n&YZY)3o>*$3WG4? zPVl^Gym!j+12=I@HgtKODt-u8jEF%(`z6*ax?Mpo&%oQRn;(>tZXH0721WJhW#9bE zN;4d1qW^?fQ8r_k=X_g+OLXG?Z+Z<;z4lcR+)Gdct>@$$95n-zYCvuG({&Or)_yizLeBeGS*;Z>gG%5!D{j`lX13-XebEv2PRNh? zf1W*uk^k}#tINPAUH=}*L}La)0ktDv6%ODSo~?YkroChWgY0L4E9_H-#Bj3mUkTP6XwB}sV^ z-=$oC0#Fw9O>HoC#u+)y2&Hx?o4>I53L3Eyts0q3L=A4UT4+D+&}eP9_fTf56hK+2bzwjAhT#!C=ti>0Wfv(xy4uSwTq ziv*4;F3x5-XBL=muy|_RK&C;JcPb&{_b=vTBPRM=|FUr<#>BTJL@V^a6I&y=V42Kk zuy?~5+!5HZ5mz@f6iShhvhtaCKa0n4wzzcC6B2sEa?U1#FO_GcHuRkndhAnC3F%iw z1AhkN&7`3*qX~eZ)1M>w?&Am;!uL{unp8LNJ$;d9~FjoGL5?sZ$HedT+U9>d8TSEZaYRaWDI4u{q<@B9Cjqoo=-r@B> zKG^ipB9~>u*%WFjsiRVrdc~TKFDtzC={03anvEmqqtI7FRgn&W30& zN()vt5m>jbO$`Jdq=_s9%hwi1`3LujVXqmQSm`tV#sDJ*87fbxLC2o##0Pr`3epPeRLCteo6yz7i`1Xh_{?Ut_qdU0e{P&bcy_Ln{wXH363nYx*-+O}F zXq&uF-r_#PV={e()(`x~hSBJfM;~#Ed}Pb+>$e_@lY|mJp<<%yJAkPL#nzkCz|XAB zWeLqu;=+P;P)usnM&ONr!cBBBE?TKi*1%aO&FPp4Psn7V62|>#Ge*j{QrR;9s1J_4 z2Kllm=K{}+mWZ}*I$gK3L*ZT;ajdj%dLM`l-Ulwt`FP)!AOTVwbAqqrr{FR%KB23c zqqrOpSpL57xWSbm;A8U>v^^;dl{__C%{(oUs=!felj4p=BV+wiNj)HMq`+ZMg-rbP z6}NUyyH9|lrE8+}LP|aOBSP3*VpsXgkVw3q3Z6!}9g8md)i~ER&CZx?R-6MTDu2My zY_+f4`e7RXor{tOiWA88FGE-9%bGongDSTH4Gq4)T;haJJ}3XS41nu~QjIt`KrB+= zAN*YMbT``Ziha81T9ldTZOG8>WwHKg4IO?-W){a>*^@Tc>}344RrjS;glGygAZ%#o zWU+}yYMZN2W7A(!S!woD`Pbv1TTT`cxQ*7;ffHVW*+cm{9K^Rri}dQW$?^6Dvn`Wx zhl}By#4Ab7LT7M~rQ?nD(cS)2`Gf#!4!8LZl{98Om}?~@YxZ8GVhY*Chfcl+kV30E zxiIdlvDqBYgy>3=M7jGP0QS7K^YlEP#FaT>_I^Pl<*FdO<~Xkhvg>WXI#SrTICe*I z3VE3n`Wu~=$#Wl%sH8ELV{SgQR|B_|_#NTBra$5!y@h;PdvJl5KkhB2cVuJ)g}rIG zKRLA20JicNvj|_sGn9Mqvh{h{5hpWcw*=m8 zu)BT^b$ckOR0GBhcI{e8hfij0nS}Fd7C+Y~t0jRf(zR-X<7oUhA6y6m^hOoLyN(N6 zeuE7`$CIsm4TQ>ZrmW4Nb>LBzjBkI%8cdyc&0_My)!Q=<0(&mr*Povq-v%Z&&^d=W zStu%9udv|q!9Cn8A1Z%A!mBR^RocSd^`pg)xmf3(0_oN^lvVTXfvd6T=8(MGH&v?` zzNE{%fu+Iie_Z7i#e&DeATr43`TOS{a{}3*A0FqN*vT->U-TDa+AaFO-@A4X4 zgpE2ww6{)Efy#C(Pk0tLogL+pio~Iyu?VSR;_8Syr_0%C-l~Xq)LjDHcn2Bn4dIWD z{-}byI=(*tWwCd%FvzhD{e(5Z*u02^&hYau$@l`1DnI{YpZG#BPvaQebHBhc7i!M5 z+{D|pHi@;ry4iGo_QCN=_xCJC6nC7IemV^~6z|6=rb>?Yr$t8imAeKyk6z4m?e;~v zz=Jrx#-`)%fzSEDxu+=h@_B}d6Afh8^?Isi>xa)eVA`9Kt>qk}Qpb3TBtA|yhs_p0 zA`0bBA_(2_iWF)a`{z6)_qWk?ePY;=L`jo!Db`m^b3S$XAJlwvJOs~>szI%lOS6Cu zZ3~iCMQgu;#a>Ve_@5FNl%pL-&lhopH$)#8oIj>-;w*D{B_<~)XJ2W*=cpNu52JvT zKA6cu0mB&Qp%0gw233s`m8A5-aXVJSX{Gf-T}I=dG&l%YJ=%=1yz~hHN7X*Z)#pXY zWna$iI$!5Pk9+vZ)LSk!m%K>{`)a7op%iFIoMcq32Bm8NE4c8-1-|n1eciGaFBzJ} zCIC==TsY%>yuJfowyk=>SKcpcy=bC+`1^~FPKCq_}zKv z@?d$oenMQt^b2H*y1ud0{|dfBJ06tr=HK7BmzJBL7DXs*0pl*9Ale%T0kbd}{~+w> zF3@t5a&o%ne}q~$HnfP3T<6|>)g&r1sIAiS%mV2w=|<~^tDE4AL##`L=2G{b)33HY zp)Vs(Zg)SY4Aoz4!-J$SaQkXp{vApBh~DMyYMWU~CNdjwT2_CFlyeYE{Th-8^vadN73ft&k&`P2eY0bi z@4%BP6@rSpw6n}39XN+{R90@_XgfI2tI)d9ogiTMdkoRjPfkz-DuNQkw{MF*1lsgR zE43B`k1^LxZEFgF61*~wbglzST{;jG<@Qkv75MSpWm`&>d=caO;IUVpT#PNm$=3w@}r-3MdPI9EUaz~O>!FPOAuf5gL&?0;LZIw zLanMSlyA~)2MS@}^mNj^c7MvEm}ier|6Fz!dvtK!jEwqAbWwn0g?b%d+v{z!Xr7d} zhcPJM-Y-vB@g7RfGuU((4}Lh9^*MikX^NL}3$sX8LJfTP;6vctFUQ{f%S2WtTt6W{ zCFZg+gtPcC{yo9fMza-5kD%+!0bXN=HAsDYjlVbv7?=_G2=UrR=lSc%l|3=LBG+8W z9J=v#1gBB;U>(0YLTS^0&dt|cn)(N8D{>8Ui&DDJL!kIw@C{&+N4zPFJIdMpbZ_*z z<@cX?Q^y{J%)cfgJKRQ26^%dFUs}6Ia5LeJ)q3?2=Y$5plc#OX?AfltX}-_is0U$}qTp{v_+bKbTkq9o3jS$6`jK-3(31F2 z7O>oan6O8Ww{5`s&Q6obr+uUT;4C)t=YY19B*Bdj0v^MDtbeF-D&Dc$N8q+ktRdzKAXkeB%0^?0fSsE_U zdCHqeTuqrQd8c8TH*$zD&gfmK|Gm>4R;Bd@a8g-w&6fj>$E$_w@v3mt8AUl#n14dl zX3afDJMp>A8;en@J76;c$N94ue8<1T9kh7RZ#!FUkRq^#?5JaJ5!x>`h4a@kEOLph`cIPQIgw1OS1CK-bPj?Fu zwaP{rs!#51@UftOm#3*wXdR%~`A={9vSvwHeKxR)^yE7*t(ExvP}tUxr2Sc3>~T9p zfHcyUfO^U;2~1R%Td4Sj)U#u0u#FX4_^Z5_cZor^(BF`dFL|F#EI1^nqH}eJSk)6b zo{5CK&7P=vH<9B_;448TZFVJZHb)*_IL~0hf2RctC!c>1bU>oW0|IE_Nfpod!%ja2D#e=85&dv8Xe7XJ5kMg<^yIM) z>p#ac&7vH{6~#@t9T}|$w>Wk=g`IURH|KSk%Kmf z%EAIAGz%F%rA!&vmgptTa#A7vh;_gfxo}X0-q;BZCk^BeI>fl}g{Y>8M38C+IP7 zv9hM=#c5rmn3MHjXs=qvETQuB0aoJ`XUf3aIa>L`@VtkA!ry(g{9zue@Otaoe%z9j zO%ekbL1V`3@>b@FktX#=xuwp>&%Cx1Oz+H_X1~>Kj)F}_MPMq{x8+nKrQb%o6F{z} z^d!W!M!#v6wAr@Me1r=>HvBmJIxGLg(|q*p(IOSjiJ(ROBYa%wt?jKE#QYm>*YFe9 zB%fXqHpHbjePY#ivuA56AQwMmO2?P~&SgBCi_G@c(nk~F3f(hxZajClcCtYWwcn5V z_dx3LUa^lCw`4ejgw@|-*&w@v&DnGQuW1Ju4D{j_KsTA~a;FRkPB|;R%(zQ9m^t`W z>mnv6t_GUp+yyN-1xvwpiH@ z#Oamev)dcm>!sJCV`^$dm}=3E z42|7Sg(c^oSAv}d2d_js`w27uVVU7FHoy$--&Vh4;MV>$zR`R^C-1!uqrDy}hpBI6 z#Ub-F6fZ7cLoMI7u4(>LG&GlOF;%%H>-xy4T{erx8I{GlADu%3dG`YNi9gyQwdJi2;+Kl{_GM`h<)4 zt1~ZCN|#_gC0Pmclwh;3OH91m+PATn)>vJ5day`*T999`(+}Za(!o@ynm9($=Se(E zmE_HjXqPDYxPz)U;UEkH5~K_(G79dPh(vhH=o>g|x}B+-J0v&xylCSlD{%Z5EtsPp zs$O5k2{ATaBn!tlJn*3vvlwAkFy%aG3x9zyA+7(7bq3 zadHWQUac(lBvpI=WY1Rqce?50bG`sVb3%I@CZcIAW{~ym@ZtY-+aXAM&uS^0?5G6E zjmH~-bN_YX?|bCtOY6Nv`X6A~Ac$A0P(6z?6P`tfPaszydJ#@kP~&vCjIQ+^uJmiz z(d*o0g!~$|b?SJ9G=13rJOd%>PoQ<9$S5K48gbmAM}gDt?~y5^`f6v9X>^j_Z)Yo? zRaI9vh0^&-s z(=$j46s8E=^+znMY(I_R07#`T;H0a#Z25T#d{|9r>i>xBMIxA|LNcSNm!0Fn=#@zh^p0?>ycDe2w9v^PN=8BoUz_ zK$q2FuiMB>=!4IZF`RGU&vR|QU(xrd63tZW=ggDt$|B^ryRj!VML?;bY0(vn@HlRM ztespLQKbQXQ~Tpf{$NzI^JWLj2ASfNpDW8q+>8DgrxZtGU%X7)mkdql`bl;al%q!@ zogkb^08f?f6ikyo)bwQt@?5xakj^z?fgb=OgzbMqEJ^;ciqOz~viAipnFQKtG0)jV z{{|xtYkbMB9jvfyw47Ad$RLe%a0}qST#pmg$*Ov zPK+?S2tp+DMHwX87XPg(%z!sStVi)cB$0WihC=U;*o}M zlF=iJ7kQ9$+ghk_`b5@^$|qBPmR1g-Xt~RVwE$P4Jss2Xm?h*HTZQsrw~K;hY|SXE z0|h$kn@Eb#-!8DcD9Z$J0s&-(hL_-6TmeHqe`CSt4{faXGQ7i8MP>^T z5DXBTJ*;JOR!Df@5I+6U^F^`7s6`n@fVB9(#gN`{YIJ!j`td_|!VQOTGcX_x3{coE z#VwgS=yM0BtjSwJO*dO#rsi*Rc-A7jD zMApcrwM$Ux=O^*YowSt<1aSVhR@$g#0kq-IYPG;CQ$tUuOs>o`kme5yB{H8FX(mXk z0Pz}w2+7$E#$3-$ENYhoDXD{NI;j99nc(3bVKd)3z2z9$5^7_zq`wM>H z%gtx+^R(OnxYrqsgr@%cCm%gSq^JChDm1gUa7_*ZQKv;EC)*#zpxCbYf#aIh7r6i3 zkDf!%ra<2NRR+o7*aa{z1M^X=!oEf~67vB#B!k31@wdKG;83FcuJlxf@I1qA#&G2) zwbqsrm~|L~#F3S#ZO7^H!8aQ6!USer8A3Z;y2RDu`Fl=1cLkQx*!-KzE_mwvC&M^7ct08HAF0pu4z_52dp z$dFqSe={ECV2Q#!4eO8jv;x3s@^%T$=XvrNlc5+2F)R!sUCzM7yAdtTaG50hC6_BAlP$jH{`X|KSh8 z!l}VR;Udxan$D?@o+V#FIPtKSz3mjY5c@JDdD6X+683V1Rx_@IK>F1?xTMa>Zi#`1 zr-j@hycTv~D8$8DSPi@ZXJGT=-el21&;%N#Q@PyP(alPH;IJf;lvk4&rjK%kQj)*e&a> zI$*$l^|R^`qwf60!KxWZw4*;@oHm!J@ALe;;t;M8zpcKQb)~)@0RKtr{V-$asJf`QyDJv3~NQ-l&NukPl*0jfD0OI^zKNBB|xEOZKdc9 zay~<>Zj=7j>c5*J=|IuQw$XyoENS75*ml_ zxJvigBnHB^8`g#bd5G5KkF9UEy8+&E>2>PoZP<;w05uD!#T++$W4X#1L*6Flxo_j7 zUX3FrOpKC|hJP7(`hM^C_z!^?^W6Gp*memKI*0I)3e5yq9@0?Ln9K$dD-YnOW2E#0 z%hwJJ1pu`Hu(qunB>6kMWB~R+kHx%uq=xzrY>-s`Ct`7&gGYrLD4OC_#w{+5Y#dDS z!PTs`5=5%_xNgDt#03AXSbgxt;PnqZI?i$!_E;b*JAiP%F|2o&mnv10APK1s+qkG8 z!Cmrx94_`(i|bre6%e`pHAJV^58}(6Kj}=hcRpR_El`WC9@DsG{YOzqz9wAkHjn;E zNix1fjs0A!r^iSaI}>n*z@0k{8=EO;QjiA>TNQXrum_f?r~`Nd;?K7SAfVX2->02g z>)0g+3|v@ECmj%uHe62+{jsG4;o4;+&`xtC_y)$Euty6~E9CAqm0By0=R#egQ_-ImF1Fi}j?CNH$GI zxpn;dwT@_W9{K^n-xx*G$DjlWR9-qbWxk&;z{u=Z-Z$4(REpyj+K1Zz@#N3P)*Aj# z-iO;}t5IaYbZ!NCc0UQW7W|-0ZKzqudh!jdRRP8w%;dIq<;txZ=jDN30xiVyk6vlY zgLIO41|&|nwCtsxAokk9mpP)$`TNi=QNqus{NO>JO6pOaT->&Q|NLYE#;;i$ z0H8dh8p#s<>m0FNog-53;n;Dt!b%U|85O5YK54Jr3{()I(lAyI_WSN?gtqfznVVVF zq#$02bBUS(AUbmSDZe8?HdL9~_ijbv-`m!ICP7FV(?e?+U|Hj_vsfrzj*SrlAqQ}_ z$boq@DWyW-+;|M$5g$NihUyHK8q%n`rkYnJm*K(#sVNf$U;=Q_>GOhj-n*&(bz`D9 ztzdHHHS>72vlfTc0G@RhnDZy_Z(Kz`O+PzRX$W({0nlEVI-RJ2bxx`C{c=~i^_vk8 zr^a(TgillgbpewaRnk~*xOLs#MUOJ;qFpOQw27Py-;4kaycpF0?tLl0?n*ZyZL@M9 zxIlBToKQctldoALv4B%5B`s^^15G$;m$2H$IS~_UYYb2a&0yMQxn{l?{V031Nz2>c zTD@PdVPhmdf)Hz-p%TPHtn?;S`oV)Lo6~g%9-{vGdr|(13&Taeyc7wkE*FsP{~ax4 zRZ7CWfwOC|@354U6|gf>vjus8GrP^L>s}1HYZ2yOhda*s!GamVwkkkWD83#eWe5R> z?`2($ z=QZCRv;crDipn<*7VjSHjixy7r#|vZY%6vOHz!d$FrPdW^HdImkNoJHy81tT7_#vK zo;XR9M6j?3^09jimA@ByhY_HsSIe_45uMwWV!++IN6dzJS(r~@hzl}?2zi;l9Rd=ZV$ z9eJ2pFRp&oD$%0wI^LSIJb7_8D0ol)izBTdlWp7f{zHzwRnHXhVy~*x?M=j_aOvlh zY|AJ3&b36ogcdPDp2)}mb(q1j5@+6sRfNoInpcO@+hTDBs82zjA?$-+Fok0=&c+xP z3vKx5vT691SET7|9X($OnPpN;cq6qu998XO5u}y-tEZ{_WR<8=?z@NnYE|TN&SCmG z>6P{G^I0HUT^x6uV0I|hPk8iCYYBJV?m(i_5UI*Oy652Px**t4ivSx_2;2abBV~0_ z(+PF-d(_}!ra+pDx#YiJeiYUTH14>@JgzS;G&t9#=-1_D+Q@@hwwc-paZxrHGCmgW z8wZKp*SM)99I#v!naptPktJI@r!arZLN4_bMwrO7F>J1~B^=n{F(XCOf-O{uj9Xw> zuqrhc=4+@wMKkw?s7sd@lycY}CBGL#t97EPMZVVRFPzdX9%Vb0?3>B((`%Sbbq}4f z;O&}3XH6mjK_;>^r9p*nj}P5nF_EF!1vj(@9H&ggm+!>sl(1{br0c$CWnO%q>lL|) zRzh+$d2cQr(J{B^&&>ZBh~sF|5O8EfRX0U3W3q=H(H`N}d)T!^B6y!K-QVxkM^6_y zSu=8VJB$K9V!N80t3#q=Pa}KETiKGOgKf)Up(FHp*JNt)=e+qv?YsJezYxK;Q&TUo z>pW&wKelg=TUZf>^h!-yS&5KJPtm@#{!x7!+o0GHn*Xh)vu41OquKx&mCS)Mtco&B zX;WLM2vyD1n9<-_oH)y4XOCJL+_n}niCrlvpnr&3a{1UUDq+EgB(LWzP51vWe&e8H z@XhwRbS)*Ub-|K-gRhbD#-lN=ALp7PBoZi_#*( zj#_niW0I9T%41yQ+SR#3Pqwx2P7Hf-TjMPovxO&P%gR~R9oiC{rZUL6$RTW9I$)I? z?LF(M*y_<3HCQaBq)L>6dw6KkvT(iRPUzfA-5?V9=g0hOyS_^MR@{>`$|k2g6h#)Z0$yr#Ko9>c`zDHcs{&Bl1G1fYwO0Aaj zL4qfXh4L(8;dDL^>%_KJg?8ytf!dW3XM^5h0MMomy&nkmU6iPtk`?Z6>^(rL1E5BR zBF;YB$Q4-@*~Xy8N@_bKRw9@YqBdP18#Bmzk&w8ids-4rrJ`@8QPcvjn`U)zJ3BcX zuWI=^xsb0t@hC_LObEaue*;NsG#+TA#dZyfZX)!8W25XD-~N3Uz*>@B#PjA)rKA

JD+u2j-@iUiw-+1M)R*KX-c|9@)E7OD7>SaDuoh_arOCP00wd#cpc$8sW&pJ$1*N(u;*@__fOpG$Qem| zK3Q$&qe1TG`oz|Stmd@fsJ<*QE83otkuZ)gTPC`u+9Sbx>u9w&Ezyz9I?u7kX?=$p z@a$Srb$=jbcE(1P=8>9Q^SWKEWiItt{P7(NL=XAX+8X#=4oS7Ay_=qI*b1|!%sW~OVHL7<-^*L>?Pz!M$F^DW z#56rp9KZCrewZW1AfI^r?cGgL>qjWmSfFL@sb(ImH&L#cW3l8#ZB4aS_3P=QwbO&y zrWcrd?OYi1h)#vw1ygz9ew>c0-YpyaGiV6l&r+K z1x;3VI9m{3ZKs+C7h7Ncla3w$3Nv?mYu7GFckGC|Q*_sHP`TYAS=Fu<&OE zZ>2KzK*DqUqRJE&3Z^8%wQ9nbSLHt^M%lB8VM~b5aZTFn)Nw2pPHj3>PY`WS>`%!` zq!H;Wft87=sTPIVyF`DSOwR3;SczH=1<|)wv7^H9KrXqwxxS~73%IJdksAA&tDsbC z5KUTW3pr&hBOJACUQJN_GpnCz08{v-fU)0X4h(ls~QOmtK4wd z{F@4DsCzhUm#cz0Sz(uXOdm&@mPe3~vgn3NxW)qx>pXI}oU6LH&slv{>)kbtt&!F@ z^@l};EOW`5`8Xr+(gm}k2G-e#yA{`iA{>bv`r7AZP|7)MpHyiF>#ZR9#fugxL{5p-&q0+hHkgFOSI_r9T3dzvxZ<9a~{KVTf>kl>v=U=^7SC{ zBjmNRVyaC1Yc3Jwb-ZrVy}b_-^y|xtgd!pB5$v&F0VOA#hkOJ8DXc5eh({R5u1{#n zgB(Rz4T!t+%g)_J7th6mRw zmUV>6{gt{WSeq4CTWw7Sq!R%@1?W}^t-zQ z3@SJ;snw$|(K+BEM!}uI7nr*Odlz>=0}BjEz-CO}XabKp{FOmh_=nsrUC|Fx`RsF3 zT{2X=Qd_Na^)dd|E-zWrB@e$mw_(p7zJ4%bLSsd{O}$jkoz0oMUnA?KU8s~>3ESw3 zec&o(W@44c@$hfAQ9{%k5gwK~@tDVqy)IowF6|A&2>}yv&&6C7_4IlG18@~TW#lfU zYOMR#{5J{=JDs-jkHu(^>RR)$?AZg@FFTj%-K*GF57u$`vjL%J+^?#u1r_GAdA?g` z!#${W+;;jjWj~q^*N;`yRDT7a!MqSFIdJ>zzdlUd(EPpQf?{B>m=A6kbXf|4jM*01l}1J@`3T%W_u?Ujo1LyJ zNFBEa-RQ)C`zZ~>Lnm4T#XODwj4^P2%uYecr;83xrO@2}akEh4?qI=daL2>u*(ecQ z9|L2UXs~%o^16VmA$2LrUaQU&V6QFP%Y&+qQ??y>D2YYIlq+*rb?FLi+jXXN^k6Gq zog^zUeT~-6wz0^#7ba5~k82%zj6BQj>N0Owvf%%EPMYG^D0m$ZeaH!XX>DC>+U5L9jQ`n(xuUqHZ6F~PM2YBf;ji%tTU3oxf%h&PI6I17Pyl;+;=*SJwNu_FgQYM284$d4Eyd|V=Kk@+0Bc%TJ2w@z} zxmupe7-jEqC-kfvIijbyr(=6{c4ILb;r-J3TMyFKnh21>2zcPmQCDW~+cH*D;DcYq z8=t8rpQgl>bhVaPsj(d3A#PY#c#bn$TNEt?g8H;?*Ij|KcyDc!y-EG;x)r;4}h3BekV2U{P`d9Hl?7Rs4lx#5qEz`VsC*#Eheom?=-w zVUJy&fprC;F`1`4Ea#h$i{t;ej9^(F;rM@P0gwcZ4 zN*&ezRn?h>L)rduzum1Yr6{tb1`VcA2+<;GFt)J{ku7G%zGiQiWNGYs!Y~-J3}cI| zAz8)}O+>~TvS)wJOaJG1j_1|=;yya(a$V>0TfX1V$@2bka3&){2)LK7M=eEsUEG|n z2~11+s@eCd`0ViYp5t!dRmVAgzNG}-=c?fNheXiI$+18m!GG#1OCY{anTk^Wb`eSK z1p{DyL}N8|gC%-VXJVq)V%D;!EjMuAR8;9EVWe!{F)skFsdoLW^qarQ5u@>y$S1oh zpFVXJb1dv*ul7RugVuBYI#V?j$uQIYOHtKHR7loLudAE#4hKs4#C9Jqa!#7yxj8;@ zJ|VP@+$%V#t!uxfED&I?J6M|bUG7FA05m9st_KJ*Jddy`p(OUXK0FsD(dN24+%|hULL=f z#ana;e6hG+cUhQP2E9Zt6LVj7U2~a#ur~K&vx>LwBQC)eoy#-I?}1%OIir9rIO^zx zH5rDy>1*;%9z&C36OCc}|Md2h@F&fu_KK%GqpyWboKu=JO7-*F(8vEBPjo8X{R{&g zqVPgF?|Fulgk-QB!-_YQ>Ln2h=4+E-xx+VQR&esrtGt&C$`uo&#!G|>abCe%SVMv3 zfw2vW&v3qIf3az47sCr)!?n3r8j2aHty}RM0R6A);uk)Znkop7g9fhFqK%PK>-gAE z^u73ezW_!$uj$TrM*jo$;L8lxPr41io`rI+Wp{urom_vfhDvPp``LCh+ znend>{m|-f8>c4!E9{)EmKgU^&-n@HR*uK>?{Of4pSxBRZ50pj<|i$_fq5FB>{o>j zcFb-5V7U1}ZT)+#GCA zjlq$9M%SP|1@}@VBiU<6@_x=W`vZ=GiS^tpfyOBRtIuv!s+-F*Q|n>sOL7y#XiW=j z0oazTgkfkM@EZYZmBYYJW}3-m6t196wTTZa}kt3R+f%#WMF1y8B}fEn09mAA?LdiK+2T(`N7+@e%f+*9|TZ z?+#24U8FDb%DLWAxtF}Vq{k+Z}Vj(5?Cavmjwxa7qiYq~(949!3O>trOC4r?PiAH|?{kc*O3%i{8~qyE)ycWJ z`RE8_(n?HgQqxdPK8MyZj|oe~YSZ3d!4v=qhgw}B*V@;e21TfGQ1SOq2`}69Gj^rF zA9!WNIBzCmm>gvZ$8Y3dC31j7#F6lPPR!Uoh9?&&B;pe88sZ2=qaW|CO$L3ntG=$D zhtJbo)qCZ8Cxq`8OH|m~q|X#3k7>Q7;8)PjWXk5NgC51&Tj~4FH4#~cXB3!|1G3=* zd3EkR!3#oVvgyZZQV(tQ=-*ReyfbRbVCO%Ey!O5kMmL%@)OWtI-U3NHYJR}8s_#{P zdJ{F@d-Y7OW!?a)?}=DYb(g9wr|5_*$Ttdz2GUCzZSQbB0? zEidoIH9ZcD)pizySB|G!I7}KD+6XhJFa`0y4n<6 zioPr*(E6sK3r~7&m>qj75YJr5gQNy`$qglb71*a;%++tlV?}&Q`Kk9QbOiLK!}3?A zvi;}(+j`%(nMQEVeGAN?k5ecKXLzh$o6Vqgg7Tk+^c_3QujKbv9})aY?`dh())Ucd zIN-VjZcMyKC^1cJgz)$pXl&4;ogryq9=&F*-USCVD6`5C*eM1 zEfo}J=b5t>CHX`Yw`N#Z0$iBq4m z^IDV9rt@WlVO{xd`~l>(hrd9@{Se!&qEruVmM1?lL!lM{@jaV5XXhhaj*`7JWcJ)9 zi*~y7T;=mUYKHu9safM@+l8}CZ=WZ|`02#de+u@kJp-1`o7~>j@15vnOzP_mARS9zP``E`Lv@D%*++b7z z7dUEGxu>LhX~v$vLdu2$5+y{?GrYG1U9U$T#Hq75IqL_5vfv#j##uFoP5u1+iSndf zf{*h-F@_!`7@evtEJ8Sh^A^SR4d=qSdkAS_N^7)fB1`$M{-;po=-p|vx0IxqzP8_M zw8hUIr$X0N;B&JDj4pdNRU!J0`|-hE%d<9<&$VY9#Iuar%;u6@+dSxD>ULwDMH6TMrZ*yGtj`4RZ|X(Xp)`10$YIXERbQOTJ-)Wuzi1~D^lRuzEJgl9 z*GjNMt3-r7i-e~twHIcJV5Ztp!uP86O&@nn_@DReJ;x!6Qg>Nm-|5lh_mVZ@jn&)8 z<>E{FQJZHgBWtfgbLKOO8*FL;TaSttCRS&^r$*Oz-IEC~=tWIK36!@SZ~NN|stL&? zqC>GflFIB;fM$bZ__vdC_I5OVwev4LkU!^~zEGPVVf-#hsW^QOGtRB-xYQ%TSazwi}fEPbb)}d$rr}#)A&M(8WnQ}vVzLZF+);k<%jkeT*_*L|Q$-WYx6z?b z6#?lv!Uo-o?jLNh*`-;%6PDoRV^a8Z>-BoSNZj zi#??Yie{Lt(Kg?Y-S8|84OZwI#Nn>R^jiK3)aS{W#jcc}aeZyprtds(>Rk-A+tM7y znaXf>2W4Ya&=M5t|fH9>% z8pZHcvKy$|#*es5E`vs8Ys7E?qB*4l1S9SU1HZl^e&dq3KLs}6TgdY%ENArrya7!j zsnotLpb!l)RaUmvmqgu#^B~*-UmoM=L4#jra&d9A6ayxymr3vYEf+1)VqkZ2Q$K-@ zcn(sj3Uqqg^(|SsZP~hAd3`pPNu}*Po&@K>zx4t~zJGcZu$Q_X%lzpb?p*+4$sEDG zmzhZ(JId6e*gbeP&chCT>c%i*sBJpL*eC_HnZCF@A?B`WA0y?teSQ&rgShzD_tA$9 z+VFLx=O*E5)cAW$laM7c!R`2G-!|W#fy9qI2TG}ByfhZMSNC&b)6)iHV6QOt1uWjF z6Fjl?<2|ReFsAHc$j$_%XMMzjAOpUJNeZj}15L&Q_`3FccMr}(6%#0R`dGX>3jtunTX!Pv`@^?LiNe!)LCVXZQ-Rqp*d#3Ur_AhbZ)QGW2cYob%xeot8qDsAm{58x>T!4ru|H#U*RWiC^8B>ZfnaMbTQ? zd;$1wGzh%ZTzDTCb{!NPt_S{Z)$3urlAgs%-nt4Fw&}0|(>|ODdu}7?k+Ojwe+EUZ z0TzJ6=n@-YlTSZ2t^mn+PxMz_(NPeJuIXyVKS{6*rIsb>DYSc6Bl{w|hM}dNUv;RE zs2Crw&6X%R=09Xfa7!aT>Yko>$AQ02Av1X`jv)(QMehLser{!)zl3i<6)q(W%Oy%= zKTb?dxXa#H&9GLR4g!i21ws-ci1!_ls=ABumw8#$VUj#|wy&PYQ1k?z)Swnf0uPul zw`+%B-Vm?+SfC|D|6;>Of%tMsx{p84Ck&T2>Wp!*l$(9I1(MrpKt>ZydGr+kp7i0D zNqeIvr(7NL!sT)r>7Y6L@CDU<^lCHo_rk`Bcf`#bm?3To(bfW&qF!g5;g?eM@Gb#! zT7i*?V|aa;$ED4C^SD;W0U;WwcaRo?U;IuG)4ZHj3Oy_xA@y>ax6Ej}Sli?}R+3o{ zZR2(tpOEukyN|OpS-H=rl3MzFGHNU0`LWQ3^;Y+yv&kA-DV98lhVRCPoVAdoh?yqsSgQ7TIAS{>iJkVh+Fr+X*@ZbTNheoL| zQ!6P&3jU&EOIW(}p|Cd($Gs%COIW3w&bT;vd*9Wsf9rd*$}Hs!Eyf_X1bU&lJKlZJ z>I@bk3oGMucCfQovPnlJp&9?q!R^}rLnVAM_2fk{28>#$DvPsw31($>0AAU_JVkJh zd{>%x?n!UYnYBr++~8or`K1`I3wb0^*RZxj(F9N8F*7$jT!=X`zPSrZuo1S2a+s-u zP|C8{%sOm;Oe+--xQ2M%*9q;0&h!@yNBH5<|94o^?~4PuPfbvvF5x>Rm`rKwpgcyH z6H4C*0iIS3EWLE>Jus3|S|K3`ANAQNm-o3o(J9j0xCS z?VdYlfq<~$;(A{SPtA2u=}T72_GE0P@fJPD{NmrnQq=I-W7-_-WXGdu=+klg)VyyU zhg5^ne+uCHc@XSJ?l`12_xz9Z5OE~aqWIqD?ZQZSF7loKH>4C|zirvu*eWh3k3~?2 zwN5UBt-yv}B|M{0%M#vfF^n%~U9Aht&ZXUR&>B<&of&1}Ak5rfHp)Vyl+@>;(ZL{T z{qv=(;yqFOLSw9SdX~k%+~yfTe%xmd6t2uyK$+Pf_K+{n2!o^hvEMl3mn~AdSyATl zv$u?Nr`8D0BIDMKE!)J%TXU}5cVn&H)+q^ZxfL0+hG|=v_H4vdG}SPGGM>>%G(FOn z0iYar+GoxO`{t^v=%M%yY($5;>wO~Uk5ik+DHv`^>lbQmiBdg!#^0gGy1&~e>R1L8 zh2*IXRq!2gIjzY#u>@zh$nfA`k+$3iNlHNo43y%7FroI@H zbgac^EE3`6hgX}1dbZ`*ercg6kcjLgPQ8{Q&*z(VY+c`{ar;*;W~Lo*&sXP*Y`yt3**C4#L$d1<)n%F)4rJJ_=TOonAP?X zfWWxof8ZZu^J1Yf=X7kYM&+$an3020wB?A~!DbUFHDZV%qOD+4@1{50Da<{97 z#I$@T(70&FN*`g1e~x!JI#gWYtczkGL)LsOeGtK&Tv@l-xNT#)a8=>gkHrjLtGW+B z7iq2!P7>&%LA@u}`XWy(K>8R|{fDZC21fB!Ru6ylYhU}jxyeO>k;+i?Q7T$Sgxv|z zzX`qqmlet(+7Mx&co|F%je!&-b$DmBtgKD2c93{gNSzLth~mWa`AJePhWVzFtSiSg zR2;%l+#CJ4_g8Rgw@YL=rEocS>>X?e2W8}N;6JB(|2K}c9IE{Q+XcytnKwgXS>Vao zCcpt=%>Q-6`DEFWpjp*l3ppDVbO?B~5a##v8D-5byfky{jHx=udHrt0+|l?|3sBC+ zgE=F``Y4S8n+(DEa1rf0V5U#2NyY%dg?RbOH^?iUhEv6|Ee6gC~pSPi$ za9kh4NSZAiYiyVC!8SU(R}BE@^HQq5(v_K7zOQ<}_=9NE`N_(TH!W>@Z&Bb^s2hqu4Jy7Zw4w9K_+-U`h*-0izp z5wKmc(kQxy%xYZ8+mK*Tn>R2T8Z3$`1&#PB?KU6l0nVaEk9A!6PS>DY#5FWqZl^2n z>x7gSBn1iPSY0=C@ne0^Z5^8dsk=PzAB>v<^=CD-*@|ZA3G1hVN*+8&Vujl5Bc+(v zDB7LoC2mj2k#~5D5goxKaU{){qlFCcGjDrc=T$AW+h#rq31Yr$QqZ0c03v34nWhEg z98bn2z?}Qe8%&i));fS-+W|+B8r`X-5isOFGJL-~WUmKGQC!6i>5h0%yYu#p4$W4Q zsZDqUq?`MgHrky6uB^ui&N=j*KhckqRz@vy->Y>P;vMDB#e<^ZnIh%B#Zw;=FuXb`RSdUshfbmY3)`>B+mEtiH+njl^LrGjf@Ub@P=S9 zrHq$IfZo4%yzVk2$VNC8-zYU*GWAWAuuoy-2DvMTZ*`FoaXmI(*s(~j)_}<45GhgMU=W6)GBzk$erU7 z82h(vnB;Bxj4I(4y8?(#gnS72Bs^k&KfC1n`^dWJdLo!Gm-R0)0L2IQ}w3doKcltXAw@W`jaJ0)??0}R&0SxS%Ci5aNX zF+ys&wrU-r5|lB*<`*z%tjt4!DfwiXF}HMwboE|j3dZe+#wBZVSGdtfJ;E@S>baG- z`v`|#bIICdtAOfG@e#X?+l(kyV>t6^s0K>*Jy2!+HSr9P61C~Ih$M$YDx#>VtiHgr zFWXH9qo-d%<$(*5U85DgI_k}3y7tI(q|YssR%yKd z4}u`&_}aJc0B~pD3ZR#OpS|~iFs32mP1%3x>bb#_JcM_ooA%z?#dw2&`?O*S5xmfd z-iv+5f)69!5MKELD{o`v#ev?s z-PQoo@S4KpEMdsCQ|{*cEyx3^cCwWtKcEW5fbKrT}tGxete z{$|eY$5%g_pn_0G}ej9l^zqNN|^2m3T>DA zt9$2p^_}m`RK6ej=)YO)dXJqg`uQ<^!A@dK{~eCC=|ZC`bI1wE45=$=uwz%W$PYEv zWn0SZsSn!Ae2k8T*-@;nFB4h1Tsh`|je{+paj4-8XR0q&dPKl#Xm{QNGsG#)a&2{{ z6L}2`n*u?p`&^y5)~2JdPf2Ig7jZb|@~wPmO)j*{4%<&CCfx|!A@`kqOu;J7Eu?cr zIz#Of+#3=SAu`gm{J)~u*E22S)j%LFVA8f0m=TVyZ#v_)N?TmgmSVlA{~sXemj6ob zdsa-9WrYws!q^19lm0-K8FQ1!iHz=M@9tBC+;2T&PKxJ$nW4KEM z{su;evC5f$ct`o{nD4SyW^1Q~_A8D@jY*d8Hb<+~eouB)V`sb1d>R`y1d`iG*P~yI zct+*lj}Ga<%A<3NG>lQra{8|E)9V%@Ed_!(;{Q_&>rG}3B3P@m%I}eL38<aWp{TpfnbS3afJ__Wr$cm0zp{U61*(!k5r46K zIxs$t3tq@4MYQ>Eg9|&h=BGya0~aPjq%0Fs%TK!|r8a+D3%UAkDPhxUut6~;8v6^% z5sV<0gz;(%7m;q{M}!zQZWQdR+1mQk)4glDC<*4{rd1O9hY)h;dH$r~}G zp@K@xN|HKkd{f@$SMBx8TiX0yM_t&*QS@KN5L3#?G4x@EPg&LWEt_-cTSwcG=iiyW zyd|_?9Pk3-gsMwc=*`BO=gL|A*d;v`tGQh~G#k}+D_lkj@Ov&WwV1{NBK4wuAo%T5 zqx@fDsm&o!rIUWDFiq?ym#(oX8~103VH{O2JP?)U0PXNg%ojmzys!&q`lirMth0tI zYginZC%rk=9vS4~4~IrS#}63cEh#?X%|;6Q=7l+f5n92#%K6@&0|3ZXBsT3Vlk&Xn zX^e3#bx#eyVV0G&cmVuKs`OtfkRlDfrur>Pup53UsGU3gsD#4#(xks6`1-q}j*k!` z?@l`oe}!yS z`HM~)wT%BrQu41zpiE)9Hns&2D3$h`sz-c)wU_Eu4I9yI&0RRU0w6b7Q z8w9?xE_9_8KS)^oJ?Q)ZShY03Cp44knoN100Qv_ozE;<7mGtjGvgzQXm?wVEoJ}?M zbt1^oWvZ`y*bFq<^FIOLnC9KNNZ1hJ&g`Jm_cHkb?c9Q#rY+xMZ`IS6O9>I`qpm-E zDL`+f#)Im3ik0HSEB^17z{xFmmOWbe$W?2OCX5mBec!{+o4cT`8Sj4ho3IArtH{EN zi%9SX*ih5G_rii}#v(L>e$x5h(#)q*-Elnk_p!y;t^$#ljS3hroZ1{<-&)%l2Bb_* zx+>j1oZ8=_(v+0xyT-3>M57ob#!zEHxNEg#B6{i_$*0Zru(aNrO9U6>f8%Rnmj$xd zV5V^?hiPvK*0e%4;FJMws%!VaCxmt~(L}ar^uv3c^tHW?zh0gHyj>RWsxULuaB5gj z5WVG9ob9LHYfMJcV84nA>l-z_vF6WUBT^LQUtGjb?s@INizMHmxEiVH!g^s&c}e3< z?!2`|&d&{u0#;4x0R|*4EiZwn5LxH3VRoPv<2<|x!rB|~ApO>fs4){nv=dW#7qad{ z(i}DdX6iRI6_Ay4!`kkCN*Dan7h^FO_Gythmk51g+?SSb=w*Q3={6l*GWH+xTKCF* zx@m^ezv(YxmNf>pqH42a`p&~5??Bxi>p}Q3IIZCTx~BEdI9!0S=X^-CZL2E4?-Oik zFApS&%-yPPP>kt6ocQ-x3^QAqA4t^|q?B*WW)(L$UvF<0e?aqdN0feOZi5|d%f4d^|Mqc@TUQiG4 z`b}S$E6n5SXDzB<`@3=Pc1B&p)vAf!l7r6X!CCOu4Rhp~SX!vg;f?Bszk`D}k+qoz z95qw5Vy?Grie}w7a~+yXd69=aJ{SK5vW@POU_h_|3{6ct++V(?RdDZu zV+Lq7rkn*wo(1}4Mds^C)2t+ZwVbzlJOP*6T%zhlArIml{YK*HleJ*v^XcqU5&yh! zIG+9Xz|Z>Y#F~-*-APcND8dF$WqaIfUjBgAjeM*gjg(_>O9L#5&A0n8;n(b?O+88W zE)E?(dJGQ7cB}yrOL4&g|3V(e9+)ZYFC;pBurEGb8(p6+4J^#y4d_q(rF6d{+O4*v;<3z5$}wd{}y` zLr)Zn{K?&DDkIuFSX0!eHFE$>a9Z~zdpP#%(7cpIpSBh>DnTGAm`j>zsiM%6T_{Im z2&5Z{yd8-3ivd;!wYhdz=IPNVPXfjUM8mm(nerVlh6TM^|}Rs>A<~n_<(CY!)+g@u4Ii zr2_0*Ke_~8)SI~9S<;A(&5i z!yxdV=*T1rrSA+5KaT>hFn8eHRk>T+o!uw+f&u<*DwPRX0l$@SDI9~&hn&)keu!tB zLwNc{8E9k;vOdykzOZQ@Hq4ribWT$~+GY&?<}XpPaTi_KW59-mWbHkjwzeIg^zaeW=nT??uKZc`$K)Ythr$p-tpF zktMAn8kIYhg7X+u*jC@1#APLg{ZD(Mt0ByMnmGY$KNC^6HhioK3`m({VJ9V9CFV-=$eAuA)C1z_td}E`8mgJ>()uaYO8`R{qx^ba9yq~OK1LK9=yLUoU%rKQ1y1wMYYxEA zFw>y8(FgLXaa{56?#@~-3>8>hA8{#)9E!CyAB`*0&XXsj~)0gKR|8 z-@V(%F5f!I@!93`xe6CO-5V&{XS1$2OP$F8m^z);x$oQtvrao}F_ey!h;<)!*a%?h^1q19ZYm12Htt zjNS2;5O0t^Z7ukypbQ*8J~R_W6U|MEvs*>oX9MnO?`xxIYIj%{guC_6-0g zOaU+=vv&ng{IGDV??o=wR-Kqdv|a+WgXhY~7q%#XV5K&Dm7QUUv*B;2X#NC0KNANyXm@5MYMmrjTXEjr@a z*euE^K(}nbF!G?~VYo;(S0wOjmOHb`^n(^}V{56Lv93 zXik!IlwTTDkQ~)I?gtp6b&WxUk3-g0559eDb#f1Y3H$`P!=z1b5`0NkuigkSp6 z?j!hwTE(LO`D)%0AML|8m`ivTqw(&s}wEm zl*xvBf5+9OwwFUtXF~->iM+A=J8(>1Vw=rlI^7P=amMed2uxLyB!Ww@jEzJ2_*(W8 zswx>oS>B~+iNmA>>31dEqzv!f?X}BWt7SFS_stT>U{T4~{FIO?7V2=2BkK}PW0haS zG}{EPh@!jQWj^zdFM^9^Q!Ym(5^Rfrhsiq~J#+vMs>2(hu5yXg6b9K~ z1TyPhs^Q8L@4$nsy7#t*ac^a^tGDM>W9GFy6^~cak!PL)vdFnPN${oyDVW2u6jJsv zV>(8fzOh&x2of;?Vo|$4>g(@&Mj+uZvLcK3MVIyzhiqP9#WD?p9x`9M$Osn~Uf9Or z`67qC-W(YM4wt1cgEH1+BDMKc5>yNT1V}pql4@sh)JA~txNU6*Ncqb}MsRAFFV#HP z*ZKh=dD;{}aJy5wV-kdC1TIgRPC(5>wUu+cYI8y%A9NL5!ckzB5ulC;qRbIZ1c-SB zymb7L^6$1O4chBs#ml2tKSM!hL5InnNbhN}M%J#zkR zEJ4fsPo9{$67XAlK1G7Og2g2qj*}c`7$ckli@?e&tLIo%zZ+d6r4Dw3i7I}lQ9JKM zh3*vbzy`sw3QhR_)86B)1;bT)74z5^`Y^Zn5X1Zn;zAehqmRXXI5$@a7$I=ADzP$W zG_e9+AHu?en0WW;?PCAKtWv1=_7GbJE0|bvcHLg&)4w!fU9wSKkq8e6&~G{1181BA z3>i%j=L^nB+BkW%lIc;lUd>5Tv=p{d4Ua|BNFnH{{0hc*;7&_&DIF_9Pm<=dT;U=@ z2a6aES5chwBQ~Lla1zSMNhELFu9qhV}U8C#Pn&)(soIijlvT*R9$bB z{mut;0C`}*DaS1r@5tX5(C>bfa7WxJ)A&fXZ$wxShl%@bY%o<7Y8n~g^4A%&T`jgrW2)uXnG$Bae8A3KE-Vy-JTs7C;q3;Lu5E1t zUltTfF;j6D%aU&-YyW*q?LPwOD>x6PvW8h#=7*UptsyVm_Zgy;+6(JV(W=*&yB6{7 zt)l%#z6%fBkYI#L!~Uo(r@NObUVNDlN*`O-@VIT^H9EBQ%D3cQujcJOBCrS>EZ*KMN3ac-{FjOh@MlVBiLwQhd6lau?p8KR~S+|VfI zXPLe?#*%MH^ouUFs6DIQK+-IxIeAm4vIuY@;XF1*>5;z?bB}!E4w-(DMC#GJ26?kA z^A$Y0H=J*@)=pTYd>?F=%>OMU`E8$P=3+#qMJLAK(NVp?n>QM&eS&>U#Mk`2PbCl< ztjZ4+_jPZegHW|9IZdrKjxx9n$F?;GF#QDAOug}VtfbD)`-ahar7{Yh;p=%)GVY1B zyD;tCI9F5_tY69efOKfor=&eR)=yuz`{`5Xf0?3Ur@jXGU}{M-=JhAZ36Fh3 zKOb6mNhZ6cTiD6J)0TB{0vwcY=IS)g)Mz%H@WEm+o z@nb0&Hj0T0sEC!*yb<#_vCuuml~$^)S%Zc9w_{YxUou<|oIE#224w~YC1LrpQw$F1cW*}$j>(Ho3Er__6}#v9(d(j+q!5U-AslDM>9CCI;in& z`w5KszT29v7Ts-WXiVH<`UOD&QZ53?i z9ZI3@dwlE4-Zcx}W{uyT39XJ7lQU5tQ$LP=fSJ~J>!2PhbhmVTo|!5c?>IjZ((e|~ zSx-23pDmD(xS|4X!23})WjB89R*u5%rDle}{z?5&Bg+IT)2y0D*D0Re#Hfbdj=-Iz zbVk(q!jGk4JJ7WV0>A~E>1Q4ld*m%H9CMP8J2_Op;5QLN)3H(f4ys6~j|qyL{$;=t ztxdXF0byOF*^*%S554;LE-&nJ?LetmIvr`ig~|ojL!tlQfUGKjPz0Vz<+z+o$t)64 zxnc^gC2`tYrbx!p+w^X)tBw)F4dce7OGfvVt+w^3qqD=K6&P zD#)R+0ibnQj?X(-MIzOBYhK~o0yh(yk7up;1Vyqwmp2|;5-xBVZ5`=2CVXa|#3M(Jno)6&2V}u{s6KC(c8BNgkmuX4pFDe}T rDllg$`5z$z$Kkl5$G=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] + +[[package]] +name = "autopep8" +version = "2.1.0" +description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" +optional = false +python-versions = ">=3.8" +files = [ + {file = "autopep8-2.1.0-py2.py3-none-any.whl", hash = "sha256:2bb76888c5edbcafe6aabab3c47ba534f5a2c2d245c2eddced4a30c4b4946357"}, + {file = "autopep8-2.1.0.tar.gz", hash = "sha256:1fa8964e4618929488f4ec36795c7ff12924a68b8bf01366c094fc52f770b6e7"}, +] + +[package.dependencies] +pycodestyle = ">=2.11.0" +tomli = {version = "*", markers = "python_version < \"3.11\""} + +[[package]] +name = "babel" +version = "2.15.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, +] + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + +[[package]] +name = "bpy" +version = "4.0.0" +description = "Blender as a Python module" +optional = false +python-versions = "==3.10.*" +files = [ + {file = "bpy-4.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:fb3f0d8c2ffb4dfa26d9cb31ccd59b9cc7336d5bc3b6b8f067642b191785cf10"}, + {file = "bpy-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:97dce1885b04296c3d27ddfde3e078acdc3ccf455983bbf46c681f966b61612a"}, + {file = "bpy-4.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:d6caceb7598232df42dcaa13433c6fee91ea811c67a3e32816643840f97c30cf"}, + {file = "bpy-4.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:57e66dcf1a99e0bdbb8fbaad52e6c922b9454e3b9a06ce698852ab66bc6a31b1"}, +] + +[package.dependencies] +cython = "*" +numpy = "*" +requests = "*" +zstandard = "*" + +[[package]] +name = "certifi" +version = "2024.2.2" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, +] + +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "comm" +version = "0.2.2" +description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." +optional = false +python-versions = ">=3.8" +files = [ + {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, + {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, +] + +[package.dependencies] +traitlets = ">=4" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "coverage" +version = "7.5.1" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0884920835a033b78d1c73b6d3bbcda8161a900f38a488829a83982925f6c2e"}, + {file = "coverage-7.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:39afcd3d4339329c5f58de48a52f6e4e50f6578dd6099961cf22228feb25f38f"}, + {file = "coverage-7.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b0ceee8147444347da6a66be737c9d78f3353b0681715b668b72e79203e4a"}, + {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a9ca3f2fae0088c3c71d743d85404cec8df9be818a005ea065495bedc33da35"}, + {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd215c0c7d7aab005221608a3c2b46f58c0285a819565887ee0b718c052aa4e"}, + {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4bf0655ab60d754491004a5efd7f9cccefcc1081a74c9ef2da4735d6ee4a6223"}, + {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61c4bf1ba021817de12b813338c9be9f0ad5b1e781b9b340a6d29fc13e7c1b5e"}, + {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db66fc317a046556a96b453a58eced5024af4582a8dbdc0c23ca4dbc0d5b3146"}, + {file = "coverage-7.5.1-cp310-cp310-win32.whl", hash = "sha256:b016ea6b959d3b9556cb401c55a37547135a587db0115635a443b2ce8f1c7228"}, + {file = "coverage-7.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:df4e745a81c110e7446b1cc8131bf986157770fa405fe90e15e850aaf7619bc8"}, + {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, + {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, + {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, + {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, + {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, + {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, + {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, + {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, + {file = "coverage-7.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2213def81a50519d7cc56ed643c9e93e0247f5bbe0d1247d15fa520814a7cd7"}, + {file = "coverage-7.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5037f8fcc2a95b1f0e80585bd9d1ec31068a9bcb157d9750a172836e98bc7a90"}, + {file = "coverage-7.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3721c2c9e4c4953a41a26c14f4cef64330392a6d2d675c8b1db3b645e31f0e"}, + {file = "coverage-7.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca498687ca46a62ae590253fba634a1fe9836bc56f626852fb2720f334c9e4e5"}, + {file = "coverage-7.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cdcbc320b14c3e5877ee79e649677cb7d89ef588852e9583e6b24c2e5072661"}, + {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:57e0204b5b745594e5bc14b9b50006da722827f0b8c776949f1135677e88d0b8"}, + {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fe7502616b67b234482c3ce276ff26f39ffe88adca2acf0261df4b8454668b4"}, + {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9e78295f4144f9dacfed4f92935fbe1780021247c2fabf73a819b17f0ccfff8d"}, + {file = "coverage-7.5.1-cp38-cp38-win32.whl", hash = "sha256:1434e088b41594baa71188a17533083eabf5609e8e72f16ce8c186001e6b8c41"}, + {file = "coverage-7.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:0646599e9b139988b63704d704af8e8df7fa4cbc4a1f33df69d97f36cb0a38de"}, + {file = "coverage-7.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4cc37def103a2725bc672f84bd939a6fe4522310503207aae4d56351644682f1"}, + {file = "coverage-7.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc0b4d8bfeabd25ea75e94632f5b6e047eef8adaed0c2161ada1e922e7f7cece"}, + {file = "coverage-7.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d0a0f5e06881ecedfe6f3dd2f56dcb057b6dbeb3327fd32d4b12854df36bf26"}, + {file = "coverage-7.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9735317685ba6ec7e3754798c8871c2f49aa5e687cc794a0b1d284b2389d1bd5"}, + {file = "coverage-7.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d21918e9ef11edf36764b93101e2ae8cc82aa5efdc7c5a4e9c6c35a48496d601"}, + {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c3e757949f268364b96ca894b4c342b41dc6f8f8b66c37878aacef5930db61be"}, + {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:79afb6197e2f7f60c4824dd4b2d4c2ec5801ceb6ba9ce5d2c3080e5660d51a4f"}, + {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1d0d98d95dd18fe29dc66808e1accf59f037d5716f86a501fc0256455219668"}, + {file = "coverage-7.5.1-cp39-cp39-win32.whl", hash = "sha256:1cc0fe9b0b3a8364093c53b0b4c0c2dd4bb23acbec4c9240b5f284095ccf7981"}, + {file = "coverage-7.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:dde0070c40ea8bb3641e811c1cfbf18e265d024deff6de52c5950677a8fb1e0f"}, + {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, + {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "cython" +version = "3.0.10" +description = "The Cython compiler for writing C extensions in the Python language." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +files = [ + {file = "Cython-3.0.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e876272548d73583e90babda94c1299537006cad7a34e515a06c51b41f8657aa"}, + {file = "Cython-3.0.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adc377aa33c3309191e617bf675fdbb51ca727acb9dc1aa23fc698d8121f7e23"}, + {file = "Cython-3.0.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:401aba1869a57aba2922ccb656a6320447e55ace42709b504c2f8e8b166f46e1"}, + {file = "Cython-3.0.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:541fbe725d6534a90b93f8c577eb70924d664b227a4631b90a6e0506d1469591"}, + {file = "Cython-3.0.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:86998b01f6a6d48398df8467292c7637e57f7e3a2ca68655367f13f66fed7734"}, + {file = "Cython-3.0.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d092c0ddba7e9e530a5c5be4ac06db8360258acc27675d1fc86294a5dc8994c5"}, + {file = "Cython-3.0.10-cp310-cp310-win32.whl", hash = "sha256:3cffb666e649dba23810732497442fb339ee67ba4e0be1f0579991e83fcc2436"}, + {file = "Cython-3.0.10-cp310-cp310-win_amd64.whl", hash = "sha256:9ea31184c7b3a728ef1f81fccb161d8948c05aa86c79f63b74fb6f3ddec860ec"}, + {file = "Cython-3.0.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:051069638abfb076900b0c2bcb6facf545655b3f429e80dd14365192074af5a4"}, + {file = "Cython-3.0.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712760879600907189c7d0d346851525545484e13cd8b787e94bfd293da8ccf0"}, + {file = "Cython-3.0.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38d40fa1324ac47c04483d151f5e092406a147eac88a18aec789cf01c089c3f2"}, + {file = "Cython-3.0.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bd49a3a9fdff65446a3e1c2bfc0ec85c6ce4c3cad27cd4ad7ba150a62b7fb59"}, + {file = "Cython-3.0.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e8df79b596633b8295eaa48b1157d796775c2bb078f32267d32f3001b687f2fd"}, + {file = "Cython-3.0.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bcc9795990e525c192bc5c0775e441d7d56d7a7d02210451e9e13c0448dba51b"}, + {file = "Cython-3.0.10-cp311-cp311-win32.whl", hash = "sha256:09f2000041db482cad3bfce94e1fa3a4c82b0e57390a164c02566cbbda8c4f12"}, + {file = "Cython-3.0.10-cp311-cp311-win_amd64.whl", hash = "sha256:3919a55ec9b6c7db6f68a004c21c05ed540c40dbe459ced5d801d5a1f326a053"}, + {file = "Cython-3.0.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8f2864ab5fcd27a346f0b50f901ebeb8f60b25a60a575ccfd982e7f3e9674914"}, + {file = "Cython-3.0.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:407840c56385b9c085826fe300213e0e76ba15d1d47daf4b58569078ecb94446"}, + {file = "Cython-3.0.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a036d00caa73550a3a976432ef21c1e3fa12637e1616aab32caded35331ae96"}, + {file = "Cython-3.0.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cc6a0e7e23a96dec3f3c9d39690d4281beabd5297855140d0d30855f950275e"}, + {file = "Cython-3.0.10-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a5e14a8c6a8157d2b0cdc2e8e3444905d20a0e78e19d2a097e89fb8b04b51f6b"}, + {file = "Cython-3.0.10-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f8a2b8fa0fd8358bccb5f3304be563c4750aae175100463d212d5ea0ec74cbe0"}, + {file = "Cython-3.0.10-cp312-cp312-win32.whl", hash = "sha256:2d29e617fd23cf4b83afe8f93f2966566c9f565918ad1e86a4502fe825cc0a79"}, + {file = "Cython-3.0.10-cp312-cp312-win_amd64.whl", hash = "sha256:6c5af936940a38c300977b81598d9c0901158f220a58c177820e17e1774f1cf1"}, + {file = "Cython-3.0.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:5f465443917d5c0f69825fca3b52b64c74ac3de0143b1fff6db8ba5b48c9fb4a"}, + {file = "Cython-3.0.10-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fadb84193c25641973666e583df8df4e27c52cdc05ddce7c6f6510d690ba34a"}, + {file = "Cython-3.0.10-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fa9e7786083b6aa61594c16979d621b62e61fcd9c2edd4761641b95c7fb34b2"}, + {file = "Cython-3.0.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4780d0f98ce28191c4d841c4358b5d5e79d96520650910cd59904123821c52d"}, + {file = "Cython-3.0.10-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:32fbad02d1189be75eb96456d9c73f5548078e5338d8fa153ecb0115b6ee279f"}, + {file = "Cython-3.0.10-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:90e2f514fc753b55245351305a399463103ec18666150bb1c36779b9862388e9"}, + {file = "Cython-3.0.10-cp36-cp36m-win32.whl", hash = "sha256:a9c976e9ec429539a4367cb4b24d15a1e46b925976f4341143f49f5f161171f5"}, + {file = "Cython-3.0.10-cp36-cp36m-win_amd64.whl", hash = "sha256:a9bb402674788a7f4061aeef8057632ec440123e74ed0fb425308a59afdfa10e"}, + {file = "Cython-3.0.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:206e803598010ecc3813db8748ed685f7beeca6c413f982df9f8a505fce56563"}, + {file = "Cython-3.0.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15b6d397f4ee5ad54e373589522af37935a32863f1b23fa8c6922adf833e28e2"}, + {file = "Cython-3.0.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a181144c2f893ed8e6a994d43d0b96300bc99873f21e3b7334ca26c61c37b680"}, + {file = "Cython-3.0.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b74b700d6a793113d03fb54b63bdbadba6365379424bac7c0470605672769260"}, + {file = "Cython-3.0.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:076e9fd4e0ca33c5fa00a7479180dbfb62f17fe928e2909f82da814536e96d2b"}, + {file = "Cython-3.0.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:269f06e6961e8591d56e30b46e1a51b6ccb42cab04c29fa3b30d3e8723485fb4"}, + {file = "Cython-3.0.10-cp37-cp37m-win32.whl", hash = "sha256:d4e83a8ceff7af60064da4ccfce0ac82372544dd5392f1b350c34f1b04d0fae6"}, + {file = "Cython-3.0.10-cp37-cp37m-win_amd64.whl", hash = "sha256:40fac59c3a7fbcd9c25aea64c342c890a5e2270ce64a1525e840807800167799"}, + {file = "Cython-3.0.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f43a58bf2434870d2fc42ac2e9ff8138c9e00c6251468de279d93fa279e9ba3b"}, + {file = "Cython-3.0.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e9a885ec63d3955a08cefc4eec39fefa9fe14989c6e5e2382bd4aeb6bdb9bc3"}, + {file = "Cython-3.0.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acfbe0fff364d54906058fc61f2393f38cd7fa07d344d80923937b87e339adcf"}, + {file = "Cython-3.0.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8adcde00a8a88fab27509b558cd8c2959ab0c70c65d3814cfea8c68b83fa6dcd"}, + {file = "Cython-3.0.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2c9c1e3e78909488f3b16fabae02308423fa6369ed96ab1e250807d344cfffd7"}, + {file = "Cython-3.0.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fc6e0faf5b57523b073f0cdefadcaef3a51235d519a0594865925cadb3aeadf0"}, + {file = "Cython-3.0.10-cp38-cp38-win32.whl", hash = "sha256:35f6ede7c74024ed1982832ae61c9fad7cf60cc3f5b8c6a63bb34e38bc291936"}, + {file = "Cython-3.0.10-cp38-cp38-win_amd64.whl", hash = "sha256:950c0c7b770d2a7cec74fb6f5ccc321d0b51d151f48c075c0d0db635a60ba1b5"}, + {file = "Cython-3.0.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:077b61ee789e48700e25d4a16daa4258b8e65167136e457174df400cf9b4feab"}, + {file = "Cython-3.0.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f1f8bba9d8f37c0cffc934792b4ac7c42d0891077127c11deebe9fa0a0f7e4"}, + {file = "Cython-3.0.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:651a15a8534ebfb9b58cb0b87c269c70984b6f9c88bfe65e4f635f0e3f07dfcd"}, + {file = "Cython-3.0.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d10fc9aa82e5e53a0b7fd118f9771199cddac8feb4a6d8350b7d4109085aa775"}, + {file = "Cython-3.0.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4f610964ab252a83e573a427e28b103e2f1dd3c23bee54f32319f9e73c3c5499"}, + {file = "Cython-3.0.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c9c4c4f3ab8f8c02817b0e16e8fa7b8cc880f76e9b63fe9c010e60c1a6c2b13"}, + {file = "Cython-3.0.10-cp39-cp39-win32.whl", hash = "sha256:0bac3ccdd4e03924028220c62ae3529e17efa8ca7e9df9330de95de02f582b26"}, + {file = "Cython-3.0.10-cp39-cp39-win_amd64.whl", hash = "sha256:81f356c1c8c0885b8435bfc468025f545c5d764aa9c75ab662616dd1193c331e"}, + {file = "Cython-3.0.10-py2.py3-none-any.whl", hash = "sha256:fcbb679c0b43514d591577fd0d20021c55c240ca9ccafbdb82d3fb95e5edfee2"}, + {file = "Cython-3.0.10.tar.gz", hash = "sha256:dcc96739331fb854dcf503f94607576cfe8488066c61ca50dfd55836f132de99"}, +] + +[[package]] +name = "debugpy" +version = "1.8.1" +description = "An implementation of the Debug Adapter Protocol for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, + {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, + {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, + {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, + {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, + {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, + {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, + {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, + {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, + {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, + {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, + {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, + {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, + {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, + {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, + {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, + {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, + {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, + {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, + {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, + {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, + {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, +] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, + {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "executing" +version = "2.0.1" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = ">=3.5" +files = [ + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, +] + +[package.extras] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] + +[[package]] +name = "ghp-import" +version = "2.1.0" +description = "Copy your docs directly to the gh-pages branch." +optional = false +python-versions = "*" +files = [ + {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, + {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, +] + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["flake8", "markdown", "twine", "wheel"] + +[[package]] +name = "griffe" +version = "0.45.0" +description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." +optional = false +python-versions = ">=3.8" +files = [ + {file = "griffe-0.45.0-py3-none-any.whl", hash = "sha256:90fe5c90e1b0ca7dd6fee78f9009f4e01b37dbc9ab484a9b2c1578915db1e571"}, + {file = "griffe-0.45.0.tar.gz", hash = "sha256:85cb2868d026ea51c89bdd589ad3ccc94abc5bd8d5d948e3d4450778a2a05b4a"}, +] + +[package.dependencies] +colorama = ">=0.4" + +[[package]] +name = "idna" +version = "3.7" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, +] + +[[package]] +name = "importlib-metadata" +version = "7.1.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, + {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "importlib-resources" +version = "6.4.0" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, + {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "ipykernel" +version = "6.29.4" +description = "IPython Kernel for Jupyter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, + {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "platform_system == \"Darwin\""} +comm = ">=0.1.1" +debugpy = ">=1.6.5" +ipython = ">=7.23.1" +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +matplotlib-inline = ">=0.1" +nest-asyncio = "*" +packaging = "*" +psutil = "*" +pyzmq = ">=24" +tornado = ">=6.1" +traitlets = ">=5.4.0" + +[package.extras] +cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] +pyqt5 = ["pyqt5"] +pyside6 = ["pyside6"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "ipython" +version = "8.24.0" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.10" +files = [ + {file = "ipython-8.24.0-py3-none-any.whl", hash = "sha256:d7bf2f6c4314984e3e02393213bab8703cf163ede39672ce5918c51fe253a2a3"}, + {file = "ipython-8.24.0.tar.gz", hash = "sha256:010db3f8a728a578bb641fdd06c063b9fb8e96a9464c63aec6310fbcb5e80501"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} +prompt-toolkit = ">=3.0.41,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5.13.0" +typing-extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} + +[package.extras] +all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "stack-data", "typing-extensions"] +kernel = ["ipykernel"] +matplotlib = ["matplotlib"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] + +[[package]] +name = "jedi" +version = "0.19.1" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, +] + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jupyter-client" +version = "8.6.1" +description = "Jupyter protocol implementation and client libraries" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_client-8.6.1-py3-none-any.whl", hash = "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f"}, + {file = "jupyter_client-8.6.1.tar.gz", hash = "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f"}, +] + +[package.dependencies] +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +python-dateutil = ">=2.8.2" +pyzmq = ">=23.0" +tornado = ">=6.2" +traitlets = ">=5.3" + +[package.extras] +docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] + +[[package]] +name = "jupyter-core" +version = "5.7.2" +description = "Jupyter core package. A base package on which Jupyter projects rely." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, + {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, +] + +[package.dependencies] +platformdirs = ">=2.5" +pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} +traitlets = ">=5.3" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] +test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "markdown" +version = "3.6" +description = "Python implementation of John Gruber's Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f"}, + {file = "Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"}, +] + +[package.extras] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, + {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, +] + +[package.dependencies] +traitlets = "*" + +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for 🐍." +optional = false +python-versions = ">=3.6" +files = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] + +[[package]] +name = "mike" +version = "2.1.1" +description = "Manage multiple versions of your MkDocs-powered documentation" +optional = false +python-versions = "*" +files = [ + {file = "mike-2.1.1-py3-none-any.whl", hash = "sha256:0b1d01a397a423284593eeb1b5f3194e37169488f929b860c9bfe95c0d5efb79"}, + {file = "mike-2.1.1.tar.gz", hash = "sha256:f39ed39f3737da83ad0adc33e9f885092ed27f8c9e7ff0523add0480352a2c22"}, +] + +[package.dependencies] +importlib-metadata = "*" +importlib-resources = "*" +jinja2 = ">=2.7" +mkdocs = ">=1.0" +pyparsing = ">=3.0" +pyyaml = ">=5.1" +pyyaml-env-tag = "*" +verspec = "*" + +[package.extras] +dev = ["coverage", "flake8 (>=3.0)", "flake8-quotes", "shtab"] +test = ["coverage", "flake8 (>=3.0)", "flake8-quotes", "shtab"] + +[[package]] +name = "mkdocs" +version = "1.6.0" +description = "Project documentation with Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7"}, + {file = "mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} +ghp-import = ">=1.0" +jinja2 = ">=2.11.1" +markdown = ">=3.3.6" +markupsafe = ">=2.0.1" +mergedeep = ">=1.3.4" +mkdocs-get-deps = ">=0.2.0" +packaging = ">=20.5" +pathspec = ">=0.11.1" +pyyaml = ">=5.1" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] + +[[package]] +name = "mkdocs-autorefs" +version = "1.0.1" +description = "Automatically link across pages in MkDocs." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_autorefs-1.0.1-py3-none-any.whl", hash = "sha256:aacdfae1ab197780fb7a2dac92ad8a3d8f7ca8049a9cbe56a4218cd52e8da570"}, + {file = "mkdocs_autorefs-1.0.1.tar.gz", hash = "sha256:f684edf847eced40b570b57846b15f0bf57fb93ac2c510450775dcf16accb971"}, +] + +[package.dependencies] +Markdown = ">=3.3" +markupsafe = ">=2.0.1" +mkdocs = ">=1.1" + +[[package]] +name = "mkdocs-click" +version = "0.8.1" +description = "An MkDocs extension to generate documentation for Click command line applications" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mkdocs_click-0.8.1-py3-none-any.whl", hash = "sha256:a100ff938be63911f86465a1c21d29a669a7c51932b700fdb3daa90d13b61ee4"}, + {file = "mkdocs_click-0.8.1.tar.gz", hash = "sha256:0a88cce04870c5d70ff63138e2418219c3c4119cc928a59c66b76eb5214edba6"}, +] + +[package.dependencies] +click = ">=8.1" +markdown = ">=3.3" + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, + {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, +] + +[package.dependencies] +mergedeep = ">=1.3.4" +platformdirs = ">=2.2.0" +pyyaml = ">=5.1" + +[[package]] +name = "mkdocs-material" +version = "9.5.22" +description = "Documentation that simply works" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_material-9.5.22-py3-none-any.whl", hash = "sha256:8c7a377d323567934e6cd46915e64dc209efceaec0dec1cf2202184f5649862c"}, + {file = "mkdocs_material-9.5.22.tar.gz", hash = "sha256:22a853a456ae8c581c4628159574d6fc7c71b2c7569dc9c3a82cc70432219599"}, +] + +[package.dependencies] +babel = ">=2.10,<3.0" +colorama = ">=0.4,<1.0" +jinja2 = ">=3.0,<4.0" +markdown = ">=3.2,<4.0" +mkdocs = ">=1.6,<2.0" +mkdocs-material-extensions = ">=1.3,<2.0" +paginate = ">=0.5,<1.0" +pygments = ">=2.16,<3.0" +pymdown-extensions = ">=10.2,<11.0" +regex = ">=2022.4" +requests = ">=2.26,<3.0" + +[package.extras] +git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"] +imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"] +recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +description = "Extension pack for Python Markdown and MkDocs Material." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, + {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, +] + +[[package]] +name = "mkdocstrings" +version = "0.23.0" +description = "Automatic documentation from sources, for MkDocs." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocstrings-0.23.0-py3-none-any.whl", hash = "sha256:051fa4014dfcd9ed90254ae91de2dbb4f24e166347dae7be9a997fe16316c65e"}, + {file = "mkdocstrings-0.23.0.tar.gz", hash = "sha256:d9c6a37ffbe7c14a7a54ef1258c70b8d394e6a33a1c80832bce40b9567138d1c"}, +] + +[package.dependencies] +Jinja2 = ">=2.11.1" +Markdown = ">=3.3" +MarkupSafe = ">=1.1" +mkdocs = ">=1.2" +mkdocs-autorefs = ">=0.3.1" +mkdocstrings-python = {version = ">=0.5.2", optional = true, markers = "extra == \"python\""} +pymdown-extensions = ">=6.3" + +[package.extras] +crystal = ["mkdocstrings-crystal (>=0.3.4)"] +python = ["mkdocstrings-python (>=0.5.2)"] +python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] + +[[package]] +name = "mkdocstrings-python" +version = "1.8.0" +description = "A Python handler for mkdocstrings." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocstrings_python-1.8.0-py3-none-any.whl", hash = "sha256:4209970cc90bec194568682a535848a8d8489516c6ed4adbe58bbc67b699ca9d"}, + {file = "mkdocstrings_python-1.8.0.tar.gz", hash = "sha256:1488bddf50ee42c07d9a488dddc197f8e8999c2899687043ec5dd1643d057192"}, +] + +[package.dependencies] +griffe = ">=0.37" +mkdocstrings = ">=0.20" + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +description = "Patch asyncio to allow nested event loops" +optional = false +python-versions = ">=3.5" +files = [ + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, +] + +[[package]] +name = "numpy" +version = "1.26.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, +] + +[[package]] +name = "packaging" +version = "24.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, +] + +[[package]] +name = "paginate" +version = "0.5.6" +description = "Divides large result sets into pages for easier browsing" +optional = false +python-versions = "*" +files = [ + {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, +] + +[[package]] +name = "parso" +version = "0.8.4" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, +] + +[package.extras] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "platformdirs" +version = "4.2.1" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"}, + {file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.43" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, + {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "psutil" +version = "5.9.8" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "pycodestyle" +version = "2.11.1" +description = "Python style guide checker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, + {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, +] + +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pymdown-extensions" +version = "10.8.1" +description = "Extension pack for Python Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pymdown_extensions-10.8.1-py3-none-any.whl", hash = "sha256:f938326115884f48c6059c67377c46cf631c733ef3629b6eed1349989d1b30cb"}, + {file = "pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940"}, +] + +[package.dependencies] +markdown = ">=3.6" +pyyaml = "*" + +[package.extras] +extra = ["pygments (>=2.12)"] + +[[package]] +name = "pyparsing" +version = "3.1.2" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pytest" +version = "7.4.4" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "4.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "pytest-dependency" +version = "0.5.1" +description = "Manage dependencies of tests" +optional = false +python-versions = "*" +files = [ + {file = "pytest-dependency-0.5.1.tar.gz", hash = "sha256:c2a892906192663f85030a6ab91304e508e546cddfe557d692d61ec57a1d946b"}, +] + +[package.dependencies] +pytest = ">=3.6.0" + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +description = "A custom YAML tag for referencing environment variables in YAML files. " +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] + +[package.dependencies] +pyyaml = "*" + +[[package]] +name = "pyzmq" +version = "26.0.3" +description = "Python bindings for 0MQ" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8"}, + {file = "pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83"}, + {file = "pyzmq-26.0.3-cp311-cp311-win32.whl", hash = "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798"}, + {file = "pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97"}, + {file = "pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc"}, + {file = "pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920"}, + {file = "pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad"}, + {file = "pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a"}, +] + +[package.dependencies] +cffi = {version = "*", markers = "implementation_name == \"pypy\""} + +[[package]] +name = "regex" +version = "2024.5.10" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.8" +files = [ + {file = "regex-2024.5.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:eda3dd46df535da787ffb9036b5140f941ecb91701717df91c9daf64cabef953"}, + {file = "regex-2024.5.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1d5bd666466c8f00a06886ce1397ba8b12371c1f1c6d1bef11013e9e0a1464a8"}, + {file = "regex-2024.5.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:32e5f3b8e32918bfbdd12eca62e49ab3031125c454b507127ad6ecbd86e62fca"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:534efd2653ebc4f26fc0e47234e53bf0cb4715bb61f98c64d2774a278b58c846"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:193b7c6834a06f722f0ce1ba685efe80881de7c3de31415513862f601097648c"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:160ba087232c5c6e2a1e7ad08bd3a3f49b58c815be0504d8c8aacfb064491cd8"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:951be1eae7b47660412dc4938777a975ebc41936d64e28081bf2e584b47ec246"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8a0f0ab5453e409586b11ebe91c672040bc804ca98d03a656825f7890cbdf88"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9e6d4d6ae1827b2f8c7200aaf7501c37cf3f3896c86a6aaf2566448397c823dd"}, + {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:161a206c8f3511e2f5fafc9142a2cc25d7fe9a1ec5ad9b4ad2496a7c33e1c5d2"}, + {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:44b3267cea873684af022822195298501568ed44d542f9a2d9bebc0212e99069"}, + {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:560278c9975694e1f0bc50da187abf2cdc1e4890739ea33df2bc4a85eeef143e"}, + {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:70364a097437dd0a90b31cd77f09f7387ad9ac60ef57590971f43b7fca3082a5"}, + {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:42be5de7cc8c1edac55db92d82b68dc8e683b204d6f5414c5a51997a323d7081"}, + {file = "regex-2024.5.10-cp310-cp310-win32.whl", hash = "sha256:9a8625849387b9d558d528e263ecc9c0fbde86cfa5c2f0eef43fff480ae24d71"}, + {file = "regex-2024.5.10-cp310-cp310-win_amd64.whl", hash = "sha256:903350bf44d7e4116b4d5898b30b15755d61dcd3161e3413a49c7db76f0bee5a"}, + {file = "regex-2024.5.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bf9596cba92ce7b1fd32c7b07c6e3212c7eed0edc271757e48bfcd2b54646452"}, + {file = "regex-2024.5.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:45cc13d398b6359a7708986386f72bd156ae781c3e83a68a6d4cee5af04b1ce9"}, + {file = "regex-2024.5.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ad45f3bccfcb00868f2871dce02a755529838d2b86163ab8a246115e80cfb7d6"}, + {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33d19f0cde6838c81acffff25c7708e4adc7dd02896c9ec25c3939b1500a1778"}, + {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a9f89d7db5ef6bdf53e5cc8e6199a493d0f1374b3171796b464a74ebe8e508a"}, + {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c6c71cf92b09e5faa72ea2c68aa1f61c9ce11cb66fdc5069d712f4392ddfd00"}, + {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7467ad8b0eac0b28e52679e972b9b234b3de0ea5cee12eb50091d2b68145fe36"}, + {file = "regex-2024.5.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc0db93ad039fc2fe32ccd3dd0e0e70c4f3d6e37ae83f0a487e1aba939bd2fbd"}, + {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fa9335674d7c819674467c7b46154196c51efbaf5f5715187fd366814ba3fa39"}, + {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7dda3091838206969c2b286f9832dff41e2da545b99d1cfaea9ebd8584d02708"}, + {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:504b5116e2bd1821efd815941edff7535e93372a098e156bb9dffde30264e798"}, + {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:91b53dea84415e8115506cc62e441a2b54537359c63d856d73cb1abe05af4c9a"}, + {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1a3903128f9e17a500618e80c68165c78c741ebb17dd1a0b44575f92c3c68b02"}, + {file = "regex-2024.5.10-cp311-cp311-win32.whl", hash = "sha256:236cace6c1903effd647ed46ce6dd5d76d54985fc36dafc5256032886736c85d"}, + {file = "regex-2024.5.10-cp311-cp311-win_amd64.whl", hash = "sha256:12446827f43c7881decf2c126762e11425de5eb93b3b0d8b581344c16db7047a"}, + {file = "regex-2024.5.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:14905ed75c7a6edf423eb46c213ed3f4507c38115f1ed3c00f4ec9eafba50e58"}, + {file = "regex-2024.5.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4fad420b14ae1970a1f322e8ae84a1d9d89375eb71e1b504060ab2d1bfe68f3c"}, + {file = "regex-2024.5.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c46a76a599fcbf95f98755275c5527304cc4f1bb69919434c1e15544d7052910"}, + {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0faecb6d5779753a6066a3c7a0471a8d29fe25d9981ca9e552d6d1b8f8b6a594"}, + {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aab65121229c2ecdf4a31b793d99a6a0501225bd39b616e653c87b219ed34a49"}, + {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50e7e96a527488334379e05755b210b7da4a60fc5d6481938c1fa053e0c92184"}, + {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba034c8db4b264ef1601eb33cd23d87c5013b8fb48b8161debe2e5d3bd9156b0"}, + {file = "regex-2024.5.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:031219782d97550c2098d9a68ce9e9eaefe67d2d81d8ff84c8354f9c009e720c"}, + {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:62b5f7910b639f3c1d122d408421317c351e213ca39c964ad4121f27916631c6"}, + {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cd832bd9b6120d6074f39bdfbb3c80e416848b07ac72910f1c7f03131a6debc3"}, + {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:e91b1976358e17197157b405cab408a5f4e33310cda211c49fc6da7cffd0b2f0"}, + {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:571452362d552de508c37191b6abbbb660028b8b418e2d68c20779e0bc8eaaa8"}, + {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5253dcb0bfda7214523de58b002eb0090cb530d7c55993ce5f6d17faf953ece7"}, + {file = "regex-2024.5.10-cp312-cp312-win32.whl", hash = "sha256:2f30a5ab8902f93930dc6f627c4dd5da2703333287081c85cace0fc6e21c25af"}, + {file = "regex-2024.5.10-cp312-cp312-win_amd64.whl", hash = "sha256:3799e36d60a35162bb35b2246d8bb012192b7437dff807ef79c14e7352706306"}, + {file = "regex-2024.5.10-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bbdc5db2c98ac2bf1971ffa1410c87ca7a15800415f788971e8ba8520fc0fda9"}, + {file = "regex-2024.5.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6ccdeef4584450b6f0bddd5135354908dacad95425fcb629fe36d13e48b60f32"}, + {file = "regex-2024.5.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:29d839829209f3c53f004e1de8c3113efce6d98029f044fa5cfee666253ee7e6"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0709ba544cf50bd5cb843df4b8bb6701bae2b70a8e88da9add8386cbca5c1385"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:972b49f2fe1047b9249c958ec4fa1bdd2cf8ce305dc19d27546d5a38e57732d8"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cdbb1998da94607d5eec02566b9586f0e70d6438abf1b690261aac0edda7ab6"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7c8ee4861d9ef5b1120abb75846828c811f932d63311596ad25fa168053e00"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d35d4cc9270944e95f9c88af757b0c9fc43f396917e143a5756608462c5223b"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8722f72068b3e1156a4b2e1afde6810f1fc67155a9fa30a4b9d5b4bc46f18fb0"}, + {file = "regex-2024.5.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:696639a73ca78a380acfaa0a1f6dd8220616a99074c05bba9ba8bb916914b224"}, + {file = "regex-2024.5.10-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea057306ab469130167014b662643cfaed84651c792948891d003cf0039223a5"}, + {file = "regex-2024.5.10-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b43b78f9386d3d932a6ce5af4b45f393d2e93693ee18dc4800d30a8909df700e"}, + {file = "regex-2024.5.10-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c43395a3b7cc9862801a65c6994678484f186ce13c929abab44fb8a9e473a55a"}, + {file = "regex-2024.5.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0bc94873ba11e34837bffd7e5006703abeffc4514e2f482022f46ce05bd25e67"}, + {file = "regex-2024.5.10-cp38-cp38-win32.whl", hash = "sha256:1118ba9def608250250f4b3e3f48c62f4562ba16ca58ede491b6e7554bfa09ff"}, + {file = "regex-2024.5.10-cp38-cp38-win_amd64.whl", hash = "sha256:458d68d34fb74b906709735c927c029e62f7d06437a98af1b5b6258025223210"}, + {file = "regex-2024.5.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:15e593386ec6331e0ab4ac0795b7593f02ab2f4b30a698beb89fbdc34f92386a"}, + {file = "regex-2024.5.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ca23b41355ba95929e9505ee04e55495726aa2282003ed9b012d86f857d3e49b"}, + {file = "regex-2024.5.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2c8982ee19ccecabbaeac1ba687bfef085a6352a8c64f821ce2f43e6d76a9298"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7117cb7d6ac7f2e985f3d18aa8a1728864097da1a677ffa69e970ca215baebf1"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b66421f8878a0c82fc0c272a43e2121c8d4c67cb37429b764f0d5ad70b82993b"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:224a9269f133564109ce668213ef3cb32bc72ccf040b0b51c72a50e569e9dc9e"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab98016541543692a37905871a5ffca59b16e08aacc3d7d10a27297b443f572d"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51d27844763c273a122e08a3e86e7aefa54ee09fb672d96a645ece0454d8425e"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:853cc36e756ff673bf984e9044ccc8fad60b95a748915dddeab9488aea974c73"}, + {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4e7eaf9df15423d07b6050fb91f86c66307171b95ea53e2d87a7993b6d02c7f7"}, + {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:169fd0acd7a259f58f417e492e93d0e15fc87592cd1e971c8c533ad5703b5830"}, + {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:334b79ce9c08f26b4659a53f42892793948a613c46f1b583e985fd5a6bf1c149"}, + {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:f03b1dbd4d9596dd84955bb40f7d885204d6aac0d56a919bb1e0ff2fb7e1735a"}, + {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfa6d61a76c77610ba9274c1a90a453062bdf6887858afbe214d18ad41cf6bde"}, + {file = "regex-2024.5.10-cp39-cp39-win32.whl", hash = "sha256:249fbcee0a277c32a3ce36d8e36d50c27c968fdf969e0fbe342658d4e010fbc8"}, + {file = "regex-2024.5.10-cp39-cp39-win_amd64.whl", hash = "sha256:0ce56a923f4c01d7568811bfdffe156268c0a7aae8a94c902b92fe34c4bde785"}, + {file = "regex-2024.5.10.tar.gz", hash = "sha256:304e7e2418146ae4d0ef0e9ffa28f881f7874b45b4994cc2279b21b6e7ae50c8"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "simpleitk" +version = "2.3.1" +description = "SimpleITK is a simplified interface to the Insight Toolkit (ITK) for image registration and segmentation" +optional = false +python-versions = "*" +files = [ + {file = "SimpleITK-2.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e9075c266d2be99a67708c9b4c34143a85f65c5367b09c37549aeaf47e66210f"}, + {file = "SimpleITK-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:977c47b4a7a7737b4413bcce12125794a342455d4a0647cea40f8473bc395330"}, + {file = "SimpleITK-2.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d30c730f8ec3035d3675bd754d13d034c101b7823e10e0ab8bf68ee9bbbc1581"}, + {file = "SimpleITK-2.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d1c81beb667fc82cd25ecaca35337e97bb85b805a3b763488132e395b698824"}, + {file = "SimpleITK-2.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:752dde0a518cad3bc1a0f06efa9a071734a5bfafdb0cc784369968128f7ec198"}, + {file = "SimpleITK-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:df43581c6984af5353730834a95116cdd8dcaef1dc13e4e9a326f608f8fba74a"}, + {file = "SimpleITK-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd1c3d7f65bf5855013121bd9f2a683f4c429b746f5cc41f84af08dd28c92573"}, + {file = "SimpleITK-2.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d088fbfbbd639aebe99aed0d9cf69364e2e8e7f4771fa2acc1017f1126a497c"}, + {file = "SimpleITK-2.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cd45cf257e1a4469576e90fd0c476685b3b66d1f471d34677dd7f3876601b6"}, + {file = "SimpleITK-2.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:2aec554a4656dc84195711a8ebfe89477aa66dce2d8c2fd81890ea96ecb725fb"}, + {file = "SimpleITK-2.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2275568360bb4d99fba5cddfe815d9b1d1f673e1333922a78093cea0531eb6f8"}, + {file = "SimpleITK-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dbbab1f3fe63147b482682cbfdaf5ae39032a9b2bf7428c0e96c46d1d4f2d6cf"}, + {file = "SimpleITK-2.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92aacf919164e4b3a8e3554e64868c3ef0e6a39d50acdf9f4ef04ccee2fbc036"}, + {file = "SimpleITK-2.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b4b9e7d64e53539216666a6b5b477e033e8738b1725f938e3c331b07539bd82"}, + {file = "SimpleITK-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:72dd0bd010ee5d0482c1db37bc82d3a6e79807641760abd94ebe16592db62da1"}, + {file = "SimpleITK-2.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:76e6fffd7c4953a1e313aa48606e157cc781275955d80a03fe5be2d3b5d9709c"}, + {file = "SimpleITK-2.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:332947cdfa91a5ecb0a36cc486e7eafd4212e772901b78948d6b530ac935356a"}, + {file = "SimpleITK-2.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9164d3c4183eeb9639d830c5803d05825380ef604f42897007492df969760542"}, + {file = "SimpleITK-2.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1225ea122dc75bcdaec0ddcfffa4771c27c53acc36968cf1256e861a265abf8"}, + {file = "SimpleITK-2.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:7629299636010b25bc64100428af1cd8beed72e07d44352c05ceb0576e962f67"}, + {file = "SimpleITK-2.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a1470a1c83f4765ff869240d1a57fc2f16e73007858d4055e171eefb5e753c0"}, + {file = "SimpleITK-2.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:decf5296fd112334e8450a7ac9c360781ac7b250368cf26b9d90a4b04fdd36a2"}, + {file = "SimpleITK-2.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61847b4c2edbeb88a5943f7a6ea51ffbba32df33df2c05d36640832dae4b075f"}, + {file = "SimpleITK-2.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a81f950b76f34db65feb6c38629ecac5dcfd31a3d89a53789eefbeb6bfa4e19"}, + {file = "SimpleITK-2.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:aec45af0ec031ed2a18f4dc8e2a12188817c789ea1db0a2c863506dce9ae2b87"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tornado" +version = "6.4" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +optional = false +python-versions = ">= 3.8" +files = [ + {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, + {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"}, + {file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"}, + {file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"}, + {file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"}, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.8" +files = [ + {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, + {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "typing-extensions" +version = "4.11.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, +] + +[[package]] +name = "urllib3" +version = "2.2.1" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "verspec" +version = "0.1.0" +description = "Flexible version handling" +optional = false +python-versions = "*" +files = [ + {file = "verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31"}, + {file = "verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e"}, +] + +[package.extras] +test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] + +[[package]] +name = "watchdog" +version = "4.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, + {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, + {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, + {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, + {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, + {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, + {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, + {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + +[[package]] +name = "zipp" +version = "3.18.1" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "zstandard" +version = "0.22.0" +description = "Zstandard bindings for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zstandard-0.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:275df437ab03f8c033b8a2c181e51716c32d831082d93ce48002a5227ec93019"}, + {file = "zstandard-0.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ac9957bc6d2403c4772c890916bf181b2653640da98f32e04b96e4d6fb3252a"}, + {file = "zstandard-0.22.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe3390c538f12437b859d815040763abc728955a52ca6ff9c5d4ac707c4ad98e"}, + {file = "zstandard-0.22.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1958100b8a1cc3f27fa21071a55cb2ed32e9e5df4c3c6e661c193437f171cba2"}, + {file = "zstandard-0.22.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93e1856c8313bc688d5df069e106a4bc962eef3d13372020cc6e3ebf5e045202"}, + {file = "zstandard-0.22.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1a90ba9a4c9c884bb876a14be2b1d216609385efb180393df40e5172e7ecf356"}, + {file = "zstandard-0.22.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3db41c5e49ef73641d5111554e1d1d3af106410a6c1fb52cf68912ba7a343a0d"}, + {file = "zstandard-0.22.0-cp310-cp310-win32.whl", hash = "sha256:d8593f8464fb64d58e8cb0b905b272d40184eac9a18d83cf8c10749c3eafcd7e"}, + {file = "zstandard-0.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:f1a4b358947a65b94e2501ce3e078bbc929b039ede4679ddb0460829b12f7375"}, + {file = "zstandard-0.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:589402548251056878d2e7c8859286eb91bd841af117dbe4ab000e6450987e08"}, + {file = "zstandard-0.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a97079b955b00b732c6f280d5023e0eefe359045e8b83b08cf0333af9ec78f26"}, + {file = "zstandard-0.22.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:445b47bc32de69d990ad0f34da0e20f535914623d1e506e74d6bc5c9dc40bb09"}, + {file = "zstandard-0.22.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33591d59f4956c9812f8063eff2e2c0065bc02050837f152574069f5f9f17775"}, + {file = "zstandard-0.22.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:888196c9c8893a1e8ff5e89b8f894e7f4f0e64a5af4d8f3c410f0319128bb2f8"}, + {file = "zstandard-0.22.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:53866a9d8ab363271c9e80c7c2e9441814961d47f88c9bc3b248142c32141d94"}, + {file = "zstandard-0.22.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4ac59d5d6910b220141c1737b79d4a5aa9e57466e7469a012ed42ce2d3995e88"}, + {file = "zstandard-0.22.0-cp311-cp311-win32.whl", hash = "sha256:2b11ea433db22e720758cba584c9d661077121fcf60ab43351950ded20283440"}, + {file = "zstandard-0.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:11f0d1aab9516a497137b41e3d3ed4bbf7b2ee2abc79e5c8b010ad286d7464bd"}, + {file = "zstandard-0.22.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6c25b8eb733d4e741246151d895dd0308137532737f337411160ff69ca24f93a"}, + {file = "zstandard-0.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f9b2cde1cd1b2a10246dbc143ba49d942d14fb3d2b4bccf4618d475c65464912"}, + {file = "zstandard-0.22.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a88b7df61a292603e7cd662d92565d915796b094ffb3d206579aaebac6b85d5f"}, + {file = "zstandard-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466e6ad8caefb589ed281c076deb6f0cd330e8bc13c5035854ffb9c2014b118c"}, + {file = "zstandard-0.22.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d67d0d53d2a138f9e29d8acdabe11310c185e36f0a848efa104d4e40b808e4"}, + {file = "zstandard-0.22.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:39b2853efc9403927f9065cc48c9980649462acbdf81cd4f0cb773af2fd734bc"}, + {file = "zstandard-0.22.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8a1b2effa96a5f019e72874969394edd393e2fbd6414a8208fea363a22803b45"}, + {file = "zstandard-0.22.0-cp312-cp312-win32.whl", hash = "sha256:88c5b4b47a8a138338a07fc94e2ba3b1535f69247670abfe422de4e0b344aae2"}, + {file = "zstandard-0.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:de20a212ef3d00d609d0b22eb7cc798d5a69035e81839f549b538eff4105d01c"}, + {file = "zstandard-0.22.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d75f693bb4e92c335e0645e8845e553cd09dc91616412d1d4650da835b5449df"}, + {file = "zstandard-0.22.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:36a47636c3de227cd765e25a21dc5dace00539b82ddd99ee36abae38178eff9e"}, + {file = "zstandard-0.22.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68953dc84b244b053c0d5f137a21ae8287ecf51b20872eccf8eaac0302d3e3b0"}, + {file = "zstandard-0.22.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2612e9bb4977381184bb2463150336d0f7e014d6bb5d4a370f9a372d21916f69"}, + {file = "zstandard-0.22.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23d2b3c2b8e7e5a6cb7922f7c27d73a9a615f0a5ab5d0e03dd533c477de23004"}, + {file = "zstandard-0.22.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d43501f5f31e22baf822720d82b5547f8a08f5386a883b32584a185675c8fbf"}, + {file = "zstandard-0.22.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a493d470183ee620a3df1e6e55b3e4de8143c0ba1b16f3ded83208ea8ddfd91d"}, + {file = "zstandard-0.22.0-cp38-cp38-win32.whl", hash = "sha256:7034d381789f45576ec3f1fa0e15d741828146439228dc3f7c59856c5bcd3292"}, + {file = "zstandard-0.22.0-cp38-cp38-win_amd64.whl", hash = "sha256:d8fff0f0c1d8bc5d866762ae95bd99d53282337af1be9dc0d88506b340e74b73"}, + {file = "zstandard-0.22.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2fdd53b806786bd6112d97c1f1e7841e5e4daa06810ab4b284026a1a0e484c0b"}, + {file = "zstandard-0.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:73a1d6bd01961e9fd447162e137ed949c01bdb830dfca487c4a14e9742dccc93"}, + {file = "zstandard-0.22.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9501f36fac6b875c124243a379267d879262480bf85b1dbda61f5ad4d01b75a3"}, + {file = "zstandard-0.22.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48f260e4c7294ef275744210a4010f116048e0c95857befb7462e033f09442fe"}, + {file = "zstandard-0.22.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959665072bd60f45c5b6b5d711f15bdefc9849dd5da9fb6c873e35f5d34d8cfb"}, + {file = "zstandard-0.22.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d22fdef58976457c65e2796e6730a3ea4a254f3ba83777ecfc8592ff8d77d303"}, + {file = "zstandard-0.22.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a7ccf5825fd71d4542c8ab28d4d482aace885f5ebe4b40faaa290eed8e095a4c"}, + {file = "zstandard-0.22.0-cp39-cp39-win32.whl", hash = "sha256:f058a77ef0ece4e210bb0450e68408d4223f728b109764676e1a13537d056bb0"}, + {file = "zstandard-0.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:e9e9d4e2e336c529d4c435baad846a181e39a982f823f7e4495ec0b0ec8538d2"}, + {file = "zstandard-0.22.0.tar.gz", hash = "sha256:8226a33c542bcb54cd6bd0a366067b610b41713b64c9abec1bc4533d69f51e70"}, +] + +[package.dependencies] +cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\""} + +[package.extras] +cffi = ["cffi (>=1.11)"] + +[metadata] +lock-version = "2.0" +python-versions = "~=3.10.0" +content-hash = "cd962cdf6abefe2eda6b33aa1ccaab485de7c30aaf4f8d9515c49f45a8dcaefb" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b8e4f2d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,29 @@ +[tool.poetry] +name = "bioxelnodes" +version = "0.1.1" +description = "" +authors = ["Ma Nan "] +license = "MIT" +readme = "README.md" + +[tool.poetry.dependencies] +python = "~=3.10.0" +bpy = "~=4.0" +simpleitk = "^2.3.1" + +[tool.poetry.group.dev.dependencies] +ipykernel = "^6.25.2" +pytest = "^7.4.2" +pytest-dependency = "^0.5.1" +mkdocs = "^1.5.3" +mkdocs-material = "^9.4.6" +mkdocstrings = { extras = ["python"], version = "^0.23.0" } +mkdocs-click = "^0.8.1" +autopep8 = "^2.0.4" +pytest-cov = "^4.1.0" +mike = "^2.0.0" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29