├── LICENSE
├── README.md
├── examples
├── __init__.py
├── with_playwright.py
└── with_selenium.py
├── imgs
├── bezier.png
├── gaussian.png
├── oxy.png
└── perlin.png
├── oxymouse
├── __init__.py
├── algorithms
│ ├── __init__.py
│ ├── base.py
│ ├── bezier_mouse
│ │ ├── __init__.py
│ │ └── bezier_mouse.py
│ ├── gaussian_mouse
│ │ ├── __init__.py
│ │ └── gaussian_mouse.py
│ ├── oxy
│ │ ├── __init__.py
│ │ └── oxy_mouse.py
│ └── perlin_mouse
│ │ ├── __init__.py
│ │ └── perlin_mouse.py
├── config.py
└── oxymouse.py
├── poetry.lock
├── pyproject.toml
└── visualize.py
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Oxylabs
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | 🐭 Oxy® Mouse
3 |
4 |
5 |
Generate mouse movements with Python & different algorithms
6 |
7 |
12 |
13 | [](https://discord.gg/Pds3gBmKMH)
14 |
15 | OxyMouse is a Python library for generating mouse movements.
16 |
17 | It is designed to work with any browser control library that supports 2D moving of the mouse cursor.
18 |
19 | ## Installation
20 |
21 | ```bash
22 | pip install oxymouse
23 | ```
24 |
25 | ## Usage
26 |
27 | Specify `algorithm` an algorithm.
28 |
29 | Supported algorithms:
30 |
31 | `bezier`, `gaussian`, `perlin`, 'oxy'
32 |
33 | ```python
34 |
35 | from oxymouse import OxyMouse
36 |
37 | mouse = OxyMouse(algorithm="bezier")
38 | movements = mouse.generate_random_coordinates(viewport_width=1920, viewport_height=1080)
39 | ```
40 |
41 |
42 | #### generate_random_coordinates
43 |
44 | This method will generate random coordinates based on your viewport width and viewport height.
45 |
46 |
47 | #### generate_coordinates
48 |
49 | This method will generate random coordinates from a given 2D point to another 2D point.
50 |
51 | You can use this to generate movements to a button.
52 |
53 | For example:
54 |
55 | - get button coordinates
56 | - get current mouse coordinates
57 | - generate movements from current mouse coordinates to button coordinates
58 |
59 | ```python
60 | from oxymouse import OxyMouse
61 |
62 | mouse = OxyMouse(algorithm="bezier")
63 | movements = mouse.generate_coordinates(from_x=400, from_y=500, to_x=1000, to_y=1200)
64 | ```
65 |
66 | #### generate_scroll_coordinates
67 |
68 | This method will generate random coordinates for scrolling.
69 |
70 | ```python
71 | from oxymouse import OxyMouse
72 |
73 | mouse = OxyMouse(algorithm="bezier")
74 | movements = mouse.generate_scroll_coordinates()
75 | ```
76 |
77 | ## Supported Algorithms
78 |
79 | ### Bezier
80 |
81 | The Bezier algorithm generates mouse movements using the Bezier curve.
82 | Perfect for moving to click a button
83 |
84 | 
85 |
86 | ### Gaussian
87 |
88 | The Gaussian algorithm generates mouse movements using the Gaussian distribution.
89 | Perfect for simulating human-like mouse movements
90 |
91 | 
92 |
93 | ### Perlin
94 |
95 | The Perlin algorithm generates mouse movements using the Perlin noise.
96 | Perfect for simulating human-like mouse movements
97 |
98 | 
99 |
100 | ### OxyMouse
101 |
102 | Custom algorithm that generates mouse movements using a custom algorithm.
103 |
104 | 
105 |
106 | ### Testing
107 |
108 | You can easily test generated mouse movements visually with specific algorithm.
109 |
110 | Use the CLI to test the generated mouse movements.
111 |
112 | For example, to test the generated mouse movements with the `Bezier` algorithm and `generate_coordinates` function.
113 |
114 | ```bash
115 | python3 visualize.py bezier gc
116 | ```
117 |
118 | You will see the generated mouse movements in a window. Similar in the examples above.
119 |
120 | Other function names:
121 | ```
122 | function_names_to_function_map = {
123 | "gc": "generate_coordinates",
124 | "grc": "generate_random_coordinates",
125 | "gsc": "generate_scroll_coordinates",
126 | }
127 | ```
128 |
129 | ## Contributing
130 |
131 | Contributions are welcome! For feature requests and bug reports please submit an issue!
132 |
--------------------------------------------------------------------------------
/examples/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxylabs/OxyMouse/da69ab6e3b35f5fde0c2f72711e1e145816841e2/examples/__init__.py
--------------------------------------------------------------------------------
/examples/with_playwright.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import random
3 |
4 | from oxylabs import OxyMouse
5 | from playwright.async_api import async_playwright
6 |
7 |
8 | async def generate_random_movements() -> list[tuple[int, int]]:
9 | mouse = OxyMouse(algorithm="gaussian")
10 | movements = mouse.generate_coordinates()
11 | return movements
12 |
13 |
14 | async def move_mouse_smoothly(page, movements: list[tuple[int, int]]):
15 | for x, y in movements:
16 | await page.mouse.move(x, y)
17 | await asyncio.sleep(random.uniform(0.001, 0.003)) # Add small random delays
18 |
19 |
20 | async def main():
21 | async with async_playwright() as p:
22 | browser = await p.chromium.launch()
23 | page = await browser.new_page()
24 |
25 | try:
26 | await page.goto("https://oxylabs.io", wait_until="domcontentloaded")
27 |
28 | movements = await generate_random_movements()
29 |
30 | await move_mouse_smoothly(page, movements)
31 |
32 | await asyncio.sleep(5)
33 |
34 | finally:
35 | await browser.close()
36 |
37 |
38 | asyncio.run(main())
39 |
--------------------------------------------------------------------------------
/examples/with_selenium.py:
--------------------------------------------------------------------------------
1 | import random
2 | import time
3 |
4 | from selenium import webdriver
5 | from selenium.webdriver.common.action_chains import ActionChains
6 | from selenium.webdriver.common.by import By
7 | from selenium.webdriver.support import expected_conditions as EC
8 | from selenium.webdriver.support.ui import WebDriverWait
9 |
10 | from oxymouse import OxyMouse
11 |
12 |
13 | def generate_random_movements() -> list[tuple[int, int]]:
14 | mouse = OxyMouse(algorithm="perlin")
15 | movements = mouse.generate_coordinates()
16 | return movements
17 |
18 |
19 | def move_mouse_smoothly(driver, movements: list[tuple[int, int]]):
20 | actions = ActionChains(driver)
21 | for x, y in movements:
22 | actions.move_by_offset(x, y)
23 | actions.pause(random.uniform(0.001, 0.003)) # Add small random delays
24 | actions.perform()
25 |
26 |
27 | driver = webdriver.Chrome()
28 |
29 | try:
30 | driver.get("https://oxylabs.io")
31 |
32 | # Wait for the page to load
33 | WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.TAG_NAME, "body")))
34 |
35 | movements = generate_random_movements()
36 |
37 | move_mouse_smoothly(driver, movements)
38 |
39 | time.sleep(5)
40 |
41 | finally:
42 | driver.quit()
43 |
--------------------------------------------------------------------------------
/imgs/bezier.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxylabs/OxyMouse/da69ab6e3b35f5fde0c2f72711e1e145816841e2/imgs/bezier.png
--------------------------------------------------------------------------------
/imgs/gaussian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxylabs/OxyMouse/da69ab6e3b35f5fde0c2f72711e1e145816841e2/imgs/gaussian.png
--------------------------------------------------------------------------------
/imgs/oxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxylabs/OxyMouse/da69ab6e3b35f5fde0c2f72711e1e145816841e2/imgs/oxy.png
--------------------------------------------------------------------------------
/imgs/perlin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxylabs/OxyMouse/da69ab6e3b35f5fde0c2f72711e1e145816841e2/imgs/perlin.png
--------------------------------------------------------------------------------
/oxymouse/__init__.py:
--------------------------------------------------------------------------------
1 | from oxymouse.oxymouse import OxyMouse
2 |
3 | __all__ = ["OxyMouse"]
4 |
--------------------------------------------------------------------------------
/oxymouse/algorithms/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxylabs/OxyMouse/da69ab6e3b35f5fde0c2f72711e1e145816841e2/oxymouse/algorithms/__init__.py
--------------------------------------------------------------------------------
/oxymouse/algorithms/base.py:
--------------------------------------------------------------------------------
1 | import abc
2 |
3 |
4 | class MouseMovement:
5 | @staticmethod
6 | @abc.abstractmethod
7 | def generate_coordinates(from_x: int, from_y: int, to_x: int, to_y: int) -> list[tuple[int, int]]:
8 | """
9 | Generate a list of coordinates from (from_x, from_y) to (to_x, to_y).
10 | """
11 | raise NotImplementedError
12 |
13 | @staticmethod
14 | @abc.abstractmethod
15 | def generate_random_coordinates(viewport_width: int, viewport_height: int) -> list[tuple[int, int]]:
16 | """
17 | Generate random coordinates within the given viewport dimensions.
18 | """
19 | raise NotImplementedError
20 |
21 | @staticmethod
22 | @abc.abstractmethod
23 | def generate_scroll_coordinates(start_y: int, end_y: int) -> list[tuple[int, int]]:
24 | """
25 | Generate a list of y-coordinates for scrolling from start_y to end_y.
26 | """
27 | raise NotImplementedError
28 |
--------------------------------------------------------------------------------
/oxymouse/algorithms/bezier_mouse/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxylabs/OxyMouse/da69ab6e3b35f5fde0c2f72711e1e145816841e2/oxymouse/algorithms/bezier_mouse/__init__.py
--------------------------------------------------------------------------------
/oxymouse/algorithms/bezier_mouse/bezier_mouse.py:
--------------------------------------------------------------------------------
1 | import random
2 | from typing import Any
3 |
4 | import numpy as np
5 | from scipy.special import comb
6 |
7 | from oxymouse.algorithms.base import MouseMovement
8 |
9 |
10 | class BezierMouse(MouseMovement):
11 | @staticmethod
12 | def bernstein_poly(
13 | i: int, n: int, t: np.ndarray[Any, np.dtype[np.float64]]
14 | ) -> np.ndarray[Any, np.dtype[np.float64]]:
15 | """
16 | The Bernstein polynomial of n, i as a function of t
17 | """
18 | return comb(n, i) * (t**i) * (1 - t) ** (n - i)
19 |
20 | @staticmethod
21 | def bezier_curve(points: list[tuple[int, int]], num_steps: int = 1000) -> list[tuple[int, int]]:
22 | """
23 | Given a set of control points, return the
24 | bezier curve defined by the control points.
25 | points should be a list of lists, or list of tuples
26 | such as [ [1,1], [2,3], [4,5], [3,5] ]
27 | """
28 | n_points = len(points)
29 | xpoints = np.array([p[0] for p in points])
30 | ypoints = np.array([p[1] for p in points])
31 |
32 | t = np.linspace(0.0, 1.0, num_steps)
33 |
34 | polynomial_array = np.array([BezierMouse.bernstein_poly(i, n_points - 1, t) for i in range(n_points)])
35 |
36 | xvals = np.dot(xpoints, polynomial_array)
37 | yvals = np.dot(ypoints, polynomial_array)
38 |
39 | return list(zip(xvals.astype(int), yvals.astype(int)))
40 |
41 | @staticmethod
42 | def generate_bezier_mouse_movements( # pylint: disable=too-many-positional-arguments
43 | start_x: int,
44 | start_y: int,
45 | end_x: int,
46 | end_y: int,
47 | duration: float = 1.0,
48 | complexity: int = 4,
49 | randomness: float = 1.0,
50 | ) -> list[tuple[int, int]]:
51 | """
52 | Generate mouse movements using Bézier curves.
53 |
54 | :param start_x: Starting x-coordinate
55 | :param start_y: Starting y-coordinate
56 | :param end_x: Ending x-coordinate
57 | :param end_y: Ending y-coordinate
58 | :param duration: Duration of the movement in seconds
59 | :param complexity: Number of control points (minimum 4, includes start and end points)
60 | :param randomness: Controls the randomness of control points (0.0 to 1.0)
61 | """
62 | complexity = max(4, complexity) # Ensure at least 4 control points for a cubic Bézier curve
63 |
64 | control_points = [(start_x, start_y)]
65 | for i in range(complexity - 2):
66 | cx = random.randint(min(start_x, end_x), max(start_x, end_x))
67 | cy = random.randint(min(start_y, end_y), max(start_y, end_y))
68 | control_points.append((cx, cy))
69 | control_points.append((end_x, end_y))
70 |
71 | for i in range(1, len(control_points) - 1):
72 | control_points[i] = (
73 | int(control_points[i][0] + random.uniform(-randomness * 100, randomness * 100)),
74 | int(control_points[i][1] + random.uniform(-randomness * 100, randomness * 100)),
75 | )
76 |
77 | num_steps = int(duration * 60) # Assuming 60 fps
78 | curve_points = BezierMouse.bezier_curve(control_points, num_steps)
79 |
80 | return curve_points
81 |
82 | @staticmethod
83 | def generate_coordinates(
84 | from_x: int = 0, from_y: int = 0, to_x: int = 1000, to_y: int = 1000
85 | ) -> list[tuple[int, int]]:
86 | """
87 | Generate a list of coordinates from (from_x, from_y) to (to_x, to_y) using Bézier curves.
88 | """
89 | return BezierMouse.generate_bezier_mouse_movements(from_x, from_y, to_x, to_y)
90 |
91 | @staticmethod
92 | def generate_random_coordinates(viewport_width: int = 1920, viewport_height: int = 1080) -> list[tuple[int, int]]:
93 | """
94 | Generate random coordinates within the given viewport dimensions using Bézier curves.
95 | """
96 | start_x, start_y = 0, 0
97 | end_x = random.randint(0, viewport_width)
98 | end_y = random.randint(0, viewport_height)
99 | movements = BezierMouse.generate_bezier_mouse_movements(start_x, start_y, end_x, end_y)
100 | return movements
101 |
102 | @staticmethod
103 | def generate_scroll_coordinates(start_y: int = 0, end_y: int = 1000) -> list[tuple[int, int]]:
104 | """
105 | Generate a list of y-coordinates for scrolling from start_y to end_y using Bézier curves.
106 | """
107 | movements = BezierMouse.generate_bezier_mouse_movements(0, start_y, 0, end_y)
108 | y_coords = [m[1] for m in movements]
109 |
110 | y_coords.append(end_y)
111 | x_coords = [0] * len(y_coords)
112 |
113 | return list(zip(x_coords, y_coords))
114 |
--------------------------------------------------------------------------------
/oxymouse/algorithms/gaussian_mouse/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxylabs/OxyMouse/da69ab6e3b35f5fde0c2f72711e1e145816841e2/oxymouse/algorithms/gaussian_mouse/__init__.py
--------------------------------------------------------------------------------
/oxymouse/algorithms/gaussian_mouse/gaussian_mouse.py:
--------------------------------------------------------------------------------
1 | import random
2 | from typing import Any
3 |
4 | import numpy as np
5 | from scipy.ndimage import gaussian_filter1d
6 |
7 | from oxymouse.algorithms.base import MouseMovement
8 |
9 |
10 | class GaussianMouse(MouseMovement):
11 | @staticmethod
12 | def random_walk(length: int, stddev: float) -> np.ndarray[Any, np.dtype[np.float64]]:
13 | return np.cumsum(np.random.normal(0, stddev, length))
14 |
15 | @staticmethod
16 | def gaussian_smooth(
17 | data: np.ndarray[Any, np.dtype[np.float64]], sigma: float
18 | ) -> np.ndarray[Any, np.dtype[np.float64]]:
19 | return gaussian_filter1d(data, sigma)
20 |
21 | @staticmethod
22 | def morph_distribution(
23 | data: np.ndarray[Any, np.dtype[np.float64]], target_mean: float, target_std: float
24 | ) -> np.ndarray[Any, np.dtype[np.float64]]:
25 | return (data - np.mean(data)) / np.std(data) * target_std + target_mean
26 |
27 | @staticmethod
28 | def bezier_curve(p0: float, p1: float, p2: float, t: float) -> float:
29 | return (1 - t) ** 2 * p0 + 2 * (1 - t) * t * p1 + t**2 * p2
30 |
31 | @staticmethod
32 | def generate_gaussian_mouse_movements( # pylint: disable=too-many-locals, too-many-positional-arguments
33 | start_x: int,
34 | start_y: int,
35 | end_x: int,
36 | end_y: int,
37 | duration: float = 1.0,
38 | smoothness: float = 2.0,
39 | randomness: float = 1.0,
40 | ) -> list[tuple[int, int]]:
41 | """
42 | Generate mouse movements using Gaussian random walk and Bezier curves.
43 |
44 | :param start_x: Starting x-coordinate
45 | :param start_y: Starting y-coordinate
46 | :param end_x: Ending x-coordinate
47 | :param end_y: Ending y-coordinate
48 | :param duration: Duration of the movement in seconds
49 | :param smoothness: Controls the smoothness of the path (higher value = smoother)
50 | :param randomness: Controls the randomness of the path (higher value = more random)
51 | """
52 | num_points = int(duration * 60)
53 |
54 | stddev = randomness * 10
55 | random_x = GaussianMouse.random_walk(num_points, stddev)
56 | random_y = GaussianMouse.random_walk(num_points, stddev)
57 |
58 | smooth_x = GaussianMouse.gaussian_smooth(random_x, sigma=smoothness)
59 | smooth_y = GaussianMouse.gaussian_smooth(random_y, sigma=smoothness)
60 |
61 | human_mean_x, human_std_x = (end_x - start_x) / 2, (end_x - start_x) / 6
62 | human_mean_y, human_std_y = (end_y - start_y) / 2, (end_y - start_y) / 6
63 | morphed_x = GaussianMouse.morph_distribution(smooth_x, human_mean_x, human_std_x)
64 | morphed_y = GaussianMouse.morph_distribution(smooth_y, human_mean_y, human_std_y)
65 |
66 | control_x = random.uniform(start_x, end_x)
67 | control_y = random.uniform(start_y, end_y)
68 |
69 | t_values = np.linspace(0, 1, num_points)
70 | bezier_x = [GaussianMouse.bezier_curve(start_x, control_x, end_x, t) for t in t_values]
71 | bezier_y = [GaussianMouse.bezier_curve(start_y, control_y, end_y, t) for t in t_values]
72 |
73 | final_x = [int(bx + mx) for bx, mx in zip(bezier_x, morphed_x)]
74 | final_y = [int(by + my) for by, my in zip(bezier_y, morphed_y)]
75 |
76 | final_x[0], final_y[0] = start_x, start_y
77 | final_x[-1], final_y[-1] = end_x, end_y
78 |
79 | mouse_path = list(zip(final_x, final_y))
80 | return mouse_path
81 |
82 | @staticmethod
83 | def generate_coordinates(
84 | from_x: int = 0, from_y: int = 0, to_x: int = 1000, to_y: int = 1000
85 | ) -> list[tuple[int, int]]:
86 | """
87 | Generate a list of coordinates from (from_x, from_y) to (to_x, to_y) using Gaussian random walk.
88 | """
89 | return GaussianMouse.generate_gaussian_mouse_movements(from_x, from_y, to_x, to_y)
90 |
91 | @staticmethod
92 | def generate_random_coordinates(viewport_width: int = 1920, viewport_height: int = 1080) -> list[tuple[int, int]]:
93 | """
94 | Generate random coordinates within the given viewport dimensions using Gaussian random walk.
95 | """
96 | start_x, start_y = 0, 0
97 | end_x = random.randint(0, viewport_width)
98 | end_y = random.randint(0, viewport_height)
99 | movements = GaussianMouse.generate_gaussian_mouse_movements(start_x, start_y, end_x, end_y)
100 | return movements
101 |
102 | @staticmethod
103 | def generate_scroll_coordinates(start_y: int = 0, end_y: int = 1000) -> list[tuple[int, int]]:
104 | """
105 | Generate a list of y-coordinates for scrolling from start_y to end_y using Gaussian random walk.
106 | """
107 | movements = GaussianMouse.generate_gaussian_mouse_movements(0, start_y, 0, end_y)
108 | y_coords = [m[1] for m in movements]
109 |
110 | y_coords.append(end_y)
111 | x_coords = [0] * len(y_coords)
112 |
113 | return list(zip(x_coords, y_coords))
114 |
--------------------------------------------------------------------------------
/oxymouse/algorithms/oxy/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxylabs/OxyMouse/da69ab6e3b35f5fde0c2f72711e1e145816841e2/oxymouse/algorithms/oxy/__init__.py
--------------------------------------------------------------------------------
/oxymouse/algorithms/oxy/oxy_mouse.py:
--------------------------------------------------------------------------------
1 | import random
2 | import time
3 | from enum import Enum
4 |
5 | import numpy as np
6 | from noise import pnoise2
7 |
8 | from oxymouse.algorithms.base import MouseMovement
9 |
10 |
11 | class MouseState(Enum):
12 | ACCELERATING = 1
13 | PRECISE_MOVEMENT = 2
14 | DECELERATING = 3
15 |
16 |
17 | class OxyMouse(MouseMovement):
18 | @staticmethod
19 | def _generate_movements(
20 | duration: float = 1.0,
21 | octaves: int = 6,
22 | persistence: float = 0.5,
23 | lacunarity: float = 2.0,
24 | seed: int = random.randint(0, 100000),
25 | max_velocity: float = 10000.0,
26 | ) -> list[tuple[int, int]]:
27 | """
28 | Generate mouse movements with realistic acceleration patterns and corrective movements.
29 | """
30 | random.seed(seed)
31 | start_time = time.time()
32 | coordinates = []
33 |
34 | phases = [
35 | (MouseState.ACCELERATING, 0.2), # Initial burst
36 | (MouseState.PRECISE_MOVEMENT, 0.3), # Careful adjustments
37 | (MouseState.DECELERATING, 0.2), # Slowdown
38 | (MouseState.PRECISE_MOVEMENT, 0.2), # Final adjustments
39 | (MouseState.DECELERATING, 0.1), # Final positioning
40 | ]
41 |
42 | last_x, last_y = 0, 0
43 | last_time = start_time
44 | current_velocity = 0
45 | phase_start_time = start_time
46 | current_phase_idx = 0
47 |
48 | while time.time() - start_time < duration and current_phase_idx < len(phases):
49 | current_time = time.time()
50 | dt = current_time - last_time
51 | phase_elapsed = current_time - phase_start_time
52 |
53 | current_state, phase_duration = phases[current_phase_idx]
54 | phase_progress = phase_elapsed / (phase_duration * duration)
55 |
56 | if phase_progress >= 1.0:
57 | current_phase_idx += 1
58 | phase_start_time = current_time
59 | continue
60 |
61 | t = (current_time - start_time) / duration
62 | x_noise = pnoise2(t * 3, seed, octaves=octaves, persistence=persistence, lacunarity=lacunarity)
63 | y_noise = pnoise2(t * 3, seed + 1, octaves=octaves, persistence=persistence, lacunarity=lacunarity)
64 |
65 | if current_state == MouseState.ACCELERATING:
66 | # Rapid acceleration with some overshooting
67 | target_velocity = max_velocity * (1 - np.exp(-phase_progress * 5))
68 | jitter = random.uniform(-0.1, 0.1) * target_velocity
69 | current_velocity = target_velocity + jitter
70 |
71 | elif current_state == MouseState.PRECISE_MOVEMENT:
72 | # Small corrective movements with reduced speed
73 | target_velocity = max_velocity * 0.2 * (np.sin(phase_progress * 4 * np.pi) * 0.5 + 0.5)
74 | current_velocity = target_velocity * random.uniform(0.8, 1.2)
75 |
76 | elif current_state == MouseState.DECELERATING:
77 | # Smooth deceleration with micro-adjustments
78 | target_velocity = max_velocity * np.exp(-phase_progress * 3)
79 | current_velocity = target_velocity * random.uniform(0.9, 1.1)
80 |
81 | max_movement = current_velocity * dt
82 | movement_angle = np.arctan2(y_noise, x_noise) + random.uniform(-0.1, 0.1)
83 |
84 | dx = np.cos(movement_angle) * max_movement
85 | dy = np.sin(movement_angle) * max_movement
86 |
87 | # Add micro-corrections (tremor)
88 | if current_state == MouseState.PRECISE_MOVEMENT:
89 | tremor_amplitude = 2.0
90 | dx += random.uniform(-tremor_amplitude, tremor_amplitude)
91 | dy += random.uniform(-tremor_amplitude, tremor_amplitude)
92 |
93 | new_x = int(last_x + dx)
94 | new_y = int(last_y + dy)
95 |
96 | coordinates.append((new_x, new_y))
97 |
98 | last_x, last_y = new_x, new_y
99 | last_time = current_time
100 | time.sleep(0.01)
101 |
102 | return coordinates
103 |
104 | @staticmethod
105 | def generate_coordinates(
106 | from_x: int = 0, from_y: int = 0, to_x: int = 1000, to_y: int = 1000
107 | ) -> list[tuple[int, int]]:
108 | """
109 | Generate a list of coordinates from (from_x, from_y) to (to_x, to_y) using Perlin noise.
110 | """
111 | movements = OxyMouse._generate_movements()
112 |
113 | x_scale = (to_x - from_x) / (max(m[0] for m in movements) - min(m[0] for m in movements))
114 | y_scale = (to_y - from_y) / (max(m[1] for m in movements) - min(m[1] for m in movements))
115 |
116 | scaled_movements = [
117 | (int(from_x + (m[0] - movements[0][0]) * x_scale), int(from_y + (m[1] - movements[0][1]) * y_scale))
118 | for m in movements
119 | ]
120 |
121 | return scaled_movements
122 |
123 | @staticmethod
124 | def generate_random_coordinates(viewport_width: int = 1920, viewport_height: int = 1080) -> list[tuple[int, int]]:
125 | """
126 | Generate random coordinates within the given viewport dimensions.
127 | """
128 |
129 | movements = OxyMouse._generate_movements()
130 | return movements
131 |
132 | @staticmethod
133 | def generate_scroll_coordinates(start_y: int = 0, end_y: int = 1000) -> list[tuple[int, int]]:
134 | """
135 | Generate a list of y-coordinates for scrolling from start_y to end_y.
136 | """
137 | movements = OxyMouse._generate_movements()
138 |
139 | y_coords = [int(start_y + (m[1] / 1080) * (end_y - start_y)) for m in movements]
140 |
141 | y_coords.append(end_y)
142 | x_coords = [0] * len(y_coords)
143 | return list(zip(x_coords, y_coords))
144 |
--------------------------------------------------------------------------------
/oxymouse/algorithms/perlin_mouse/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxylabs/OxyMouse/da69ab6e3b35f5fde0c2f72711e1e145816841e2/oxymouse/algorithms/perlin_mouse/__init__.py
--------------------------------------------------------------------------------
/oxymouse/algorithms/perlin_mouse/perlin_mouse.py:
--------------------------------------------------------------------------------
1 | import random
2 | import time
3 |
4 | from noise import pnoise2
5 |
6 | from oxymouse.algorithms.base import MouseMovement
7 |
8 |
9 | class PerlinMouse(MouseMovement):
10 | @staticmethod
11 | def generate_perlin_mouse_movements(
12 | duration: float = 1.0,
13 | octaves: int = 6,
14 | persistence: float = 0.5,
15 | lacunarity: float = 2.0,
16 | seed: int = random.randint(0, 100000),
17 | ) -> list[tuple[int, int]]:
18 | """
19 | Generate mouse movements using Perlin noise.
20 |
21 | :param duration: Duration of the movement in seconds
22 | :param octaves: Number of octaves for the noise
23 | :param persistence: Persistence for the noise
24 | :param lacunarity: Lacunarity for the noise
25 | :param seed: Seed for reproducible results
26 | """
27 | start_time = time.time()
28 | screen_width, screen_height = 1920, 1080
29 |
30 | coordinates = []
31 |
32 | while time.time() - start_time < duration:
33 | # Generate noise values
34 | t = (time.time() - start_time) / duration
35 | x_noise = pnoise2(t, seed, octaves=octaves, persistence=persistence, lacunarity=lacunarity)
36 | y_noise = pnoise2(t, seed + 1, octaves=octaves, persistence=persistence, lacunarity=lacunarity)
37 |
38 | # Map noise to screen coordinates
39 | x = int((x_noise + 1) / 2 * screen_width)
40 | y = int((y_noise + 1) / 2 * screen_height)
41 |
42 | coordinates.append((x, y))
43 |
44 | time.sleep(0.01)
45 | return coordinates
46 |
47 | @staticmethod
48 | def generate_coordinates(
49 | from_x: int = 0, from_y: int = 0, to_x: int = 1000, to_y: int = 1000
50 | ) -> list[tuple[int, int]]:
51 | """
52 | Generate a list of coordinates from (from_x, from_y) to (to_x, to_y) using Perlin noise.
53 | """
54 | movements = PerlinMouse.generate_perlin_mouse_movements()
55 |
56 | # Scale and translate the movements to fit the desired start and end points
57 | x_scale = (to_x - from_x) / (max(m[0] for m in movements) - min(m[0] for m in movements))
58 | y_scale = (to_y - from_y) / (max(m[1] for m in movements) - min(m[1] for m in movements))
59 |
60 | scaled_movements = [
61 | (int(from_x + (m[0] - movements[0][0]) * x_scale), int(from_y + (m[1] - movements[0][1]) * y_scale))
62 | for m in movements
63 | ]
64 |
65 | return scaled_movements
66 |
67 | @staticmethod
68 | def generate_random_coordinates(viewport_width: int = 1920, viewport_height: int = 1080) -> list[tuple[int, int]]:
69 | """
70 | Generate random coordinates within the given viewport dimensions using Perlin noise.
71 | """
72 |
73 | movements = PerlinMouse.generate_perlin_mouse_movements()
74 | return movements
75 |
76 | @staticmethod
77 | def generate_scroll_coordinates(start_y: int = 0, end_y: int = 1000) -> list[tuple[int, int]]:
78 | """
79 | Generate a list of y-coordinates for scrolling from start_y to end_y using Perlin noise.
80 | """
81 | movements = PerlinMouse.generate_perlin_mouse_movements()
82 |
83 | y_coords = [int(start_y + (m[1] / 1080) * (end_y - start_y)) for m in movements]
84 |
85 | y_coords.append(end_y)
86 | x_coords = [0] * len(y_coords)
87 | return list(zip(x_coords, y_coords))
88 |
--------------------------------------------------------------------------------
/oxymouse/config.py:
--------------------------------------------------------------------------------
1 | from oxymouse.algorithms.bezier_mouse.bezier_mouse import BezierMouse
2 | from oxymouse.algorithms.gaussian_mouse.gaussian_mouse import GaussianMouse
3 | from oxymouse.algorithms.oxy.oxy_mouse import OxyMouse
4 | from oxymouse.algorithms.perlin_mouse.perlin_mouse import PerlinMouse
5 |
6 | mouses = {"perlin": PerlinMouse(), "bezier": BezierMouse(), "gaussian": GaussianMouse(), "oxy": OxyMouse()}
7 |
--------------------------------------------------------------------------------
/oxymouse/oxymouse.py:
--------------------------------------------------------------------------------
1 | from oxymouse.algorithms.base import MouseMovement
2 | from oxymouse.config import mouses
3 |
4 |
5 | class OxyMouse:
6 | def __init__(self, algorithm: str) -> None:
7 | self.mouse: MouseMovement
8 |
9 | self.mouse = mouses.get(algorithm)
10 | if not self.mouse:
11 | raise ValueError("Invalid algorithm")
12 |
13 | def generate_coordinates(
14 | self, from_x: int = 0, from_y: int = 0, to_x: int = 1000, to_y: int = 1000
15 | ) -> list[tuple[int, int]]:
16 | return self.mouse.generate_coordinates(from_x, from_y, to_x, to_y)
17 |
18 | def generate_random_coordinates(
19 | self, viewport_width: int = 1920, viewport_height: int = 1080
20 | ) -> list[tuple[int, int]]:
21 | return self.mouse.generate_random_coordinates(viewport_width, viewport_height)
22 |
23 | def generate_scroll_coordinates(self, start_y: int = 0, end_y: int = 1000) -> list[tuple[int, int]]:
24 | return self.mouse.generate_scroll_coordinates(start_y, end_y)
25 |
--------------------------------------------------------------------------------
/poetry.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
2 |
3 | [[package]]
4 | name = "astroid"
5 | version = "3.3.4"
6 | description = "An abstract syntax tree for Python with inference support."
7 | optional = false
8 | python-versions = ">=3.9.0"
9 | files = [
10 | {file = "astroid-3.3.4-py3-none-any.whl", hash = "sha256:5eba185467253501b62a9f113c263524b4f5d55e1b30456370eed4cdbd6438fd"},
11 | {file = "astroid-3.3.4.tar.gz", hash = "sha256:e73d0b62dd680a7c07cb2cd0ce3c22570b044dd01bd994bc3a2dd16c6cbba162"},
12 | ]
13 |
14 | [package.dependencies]
15 | typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""}
16 |
17 | [[package]]
18 | name = "click"
19 | version = "8.1.7"
20 | description = "Composable command line interface toolkit"
21 | optional = false
22 | python-versions = ">=3.7"
23 | files = [
24 | {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
25 | {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
26 | ]
27 |
28 | [package.dependencies]
29 | colorama = {version = "*", markers = "platform_system == \"Windows\""}
30 |
31 | [[package]]
32 | name = "colorama"
33 | version = "0.4.6"
34 | description = "Cross-platform colored terminal text."
35 | optional = false
36 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
37 | files = [
38 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
39 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
40 | ]
41 |
42 | [[package]]
43 | name = "contourpy"
44 | version = "1.3.0"
45 | description = "Python library for calculating contours of 2D quadrilateral grids"
46 | optional = false
47 | python-versions = ">=3.9"
48 | files = [
49 | {file = "contourpy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7"},
50 | {file = "contourpy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42"},
51 | {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7"},
52 | {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab"},
53 | {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589"},
54 | {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41"},
55 | {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d"},
56 | {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223"},
57 | {file = "contourpy-1.3.0-cp310-cp310-win32.whl", hash = "sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f"},
58 | {file = "contourpy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b"},
59 | {file = "contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad"},
60 | {file = "contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49"},
61 | {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66"},
62 | {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081"},
63 | {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1"},
64 | {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d"},
65 | {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c"},
66 | {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb"},
67 | {file = "contourpy-1.3.0-cp311-cp311-win32.whl", hash = "sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c"},
68 | {file = "contourpy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67"},
69 | {file = "contourpy-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f"},
70 | {file = "contourpy-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6"},
71 | {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639"},
72 | {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c"},
73 | {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06"},
74 | {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09"},
75 | {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd"},
76 | {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35"},
77 | {file = "contourpy-1.3.0-cp312-cp312-win32.whl", hash = "sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb"},
78 | {file = "contourpy-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b"},
79 | {file = "contourpy-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3"},
80 | {file = "contourpy-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7"},
81 | {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84"},
82 | {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0"},
83 | {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b"},
84 | {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da"},
85 | {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14"},
86 | {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8"},
87 | {file = "contourpy-1.3.0-cp313-cp313-win32.whl", hash = "sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294"},
88 | {file = "contourpy-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087"},
89 | {file = "contourpy-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8"},
90 | {file = "contourpy-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b"},
91 | {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973"},
92 | {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18"},
93 | {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8"},
94 | {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6"},
95 | {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2"},
96 | {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927"},
97 | {file = "contourpy-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a11077e395f67ffc2c44ec2418cfebed032cd6da3022a94fc227b6faf8e2acb8"},
98 | {file = "contourpy-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e8134301d7e204c88ed7ab50028ba06c683000040ede1d617298611f9dc6240c"},
99 | {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12968fdfd5bb45ffdf6192a590bd8ddd3ba9e58360b29683c6bb71a7b41edca"},
100 | {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fd2a0fc506eccaaa7595b7e1418951f213cf8255be2600f1ea1b61e46a60c55f"},
101 | {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cfb5c62ce023dfc410d6059c936dcf96442ba40814aefbfa575425a3a7f19dc"},
102 | {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68a32389b06b82c2fdd68276148d7b9275b5f5cf13e5417e4252f6d1a34f72a2"},
103 | {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:94e848a6b83da10898cbf1311a815f770acc9b6a3f2d646f330d57eb4e87592e"},
104 | {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d78ab28a03c854a873787a0a42254a0ccb3cb133c672f645c9f9c8f3ae9d0800"},
105 | {file = "contourpy-1.3.0-cp39-cp39-win32.whl", hash = "sha256:81cb5ed4952aae6014bc9d0421dec7c5835c9c8c31cdf51910b708f548cf58e5"},
106 | {file = "contourpy-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:14e262f67bd7e6eb6880bc564dcda30b15e351a594657e55b7eec94b6ef72843"},
107 | {file = "contourpy-1.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c"},
108 | {file = "contourpy-1.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779"},
109 | {file = "contourpy-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4"},
110 | {file = "contourpy-1.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:00ccd0dbaad6d804ab259820fa7cb0b8036bda0686ef844d24125d8287178ce0"},
111 | {file = "contourpy-1.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca947601224119117f7c19c9cdf6b3ab54c5726ef1d906aa4a69dfb6dd58102"},
112 | {file = "contourpy-1.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6ec93afeb848a0845a18989da3beca3eec2c0f852322efe21af1931147d12cb"},
113 | {file = "contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4"},
114 | ]
115 |
116 | [package.dependencies]
117 | numpy = ">=1.23"
118 |
119 | [package.extras]
120 | bokeh = ["bokeh", "selenium"]
121 | docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"]
122 | mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.11.1)", "types-Pillow"]
123 | test = ["Pillow", "contourpy[test-no-images]", "matplotlib"]
124 | test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"]
125 |
126 | [[package]]
127 | name = "cycler"
128 | version = "0.12.1"
129 | description = "Composable style cycles"
130 | optional = false
131 | python-versions = ">=3.8"
132 | files = [
133 | {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"},
134 | {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"},
135 | ]
136 |
137 | [package.extras]
138 | docs = ["ipython", "matplotlib", "numpydoc", "sphinx"]
139 | tests = ["pytest", "pytest-cov", "pytest-xdist"]
140 |
141 | [[package]]
142 | name = "dill"
143 | version = "0.3.8"
144 | description = "serialize all of Python"
145 | optional = false
146 | python-versions = ">=3.8"
147 | files = [
148 | {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"},
149 | {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"},
150 | ]
151 |
152 | [package.extras]
153 | graph = ["objgraph (>=1.7.2)"]
154 | profile = ["gprof2dot (>=2022.7.29)"]
155 |
156 | [[package]]
157 | name = "fonttools"
158 | version = "4.54.1"
159 | description = "Tools to manipulate font files"
160 | optional = false
161 | python-versions = ">=3.8"
162 | files = [
163 | {file = "fonttools-4.54.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ed7ee041ff7b34cc62f07545e55e1468808691dddfd315d51dd82a6b37ddef2"},
164 | {file = "fonttools-4.54.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41bb0b250c8132b2fcac148e2e9198e62ff06f3cc472065dff839327945c5882"},
165 | {file = "fonttools-4.54.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7965af9b67dd546e52afcf2e38641b5be956d68c425bef2158e95af11d229f10"},
166 | {file = "fonttools-4.54.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278913a168f90d53378c20c23b80f4e599dca62fbffae4cc620c8eed476b723e"},
167 | {file = "fonttools-4.54.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0e88e3018ac809b9662615072dcd6b84dca4c2d991c6d66e1970a112503bba7e"},
168 | {file = "fonttools-4.54.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4aa4817f0031206e637d1e685251ac61be64d1adef111060df84fdcbc6ab6c44"},
169 | {file = "fonttools-4.54.1-cp310-cp310-win32.whl", hash = "sha256:7e3b7d44e18c085fd8c16dcc6f1ad6c61b71ff463636fcb13df7b1b818bd0c02"},
170 | {file = "fonttools-4.54.1-cp310-cp310-win_amd64.whl", hash = "sha256:dd9cc95b8d6e27d01e1e1f1fae8559ef3c02c76317da650a19047f249acd519d"},
171 | {file = "fonttools-4.54.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5419771b64248484299fa77689d4f3aeed643ea6630b2ea750eeab219588ba20"},
172 | {file = "fonttools-4.54.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:301540e89cf4ce89d462eb23a89464fef50915255ece765d10eee8b2bf9d75b2"},
173 | {file = "fonttools-4.54.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76ae5091547e74e7efecc3cbf8e75200bc92daaeb88e5433c5e3e95ea8ce5aa7"},
174 | {file = "fonttools-4.54.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07"},
175 | {file = "fonttools-4.54.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d26732ae002cc3d2ecab04897bb02ae3f11f06dd7575d1df46acd2f7c012a8d8"},
176 | {file = "fonttools-4.54.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58974b4987b2a71ee08ade1e7f47f410c367cdfc5a94fabd599c88165f56213a"},
177 | {file = "fonttools-4.54.1-cp311-cp311-win32.whl", hash = "sha256:ab774fa225238986218a463f3fe151e04d8c25d7de09df7f0f5fce27b1243dbc"},
178 | {file = "fonttools-4.54.1-cp311-cp311-win_amd64.whl", hash = "sha256:07e005dc454eee1cc60105d6a29593459a06321c21897f769a281ff2d08939f6"},
179 | {file = "fonttools-4.54.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:54471032f7cb5fca694b5f1a0aaeba4af6e10ae989df408e0216f7fd6cdc405d"},
180 | {file = "fonttools-4.54.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fa92cb248e573daab8d032919623cc309c005086d743afb014c836636166f08"},
181 | {file = "fonttools-4.54.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a911591200114969befa7f2cb74ac148bce5a91df5645443371aba6d222e263"},
182 | {file = "fonttools-4.54.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93d458c8a6a354dc8b48fc78d66d2a8a90b941f7fec30e94c7ad9982b1fa6bab"},
183 | {file = "fonttools-4.54.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5eb2474a7c5be8a5331146758debb2669bf5635c021aee00fd7c353558fc659d"},
184 | {file = "fonttools-4.54.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9c563351ddc230725c4bdf7d9e1e92cbe6ae8553942bd1fb2b2ff0884e8b714"},
185 | {file = "fonttools-4.54.1-cp312-cp312-win32.whl", hash = "sha256:fdb062893fd6d47b527d39346e0c5578b7957dcea6d6a3b6794569370013d9ac"},
186 | {file = "fonttools-4.54.1-cp312-cp312-win_amd64.whl", hash = "sha256:e4564cf40cebcb53f3dc825e85910bf54835e8a8b6880d59e5159f0f325e637e"},
187 | {file = "fonttools-4.54.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6e37561751b017cf5c40fce0d90fd9e8274716de327ec4ffb0df957160be3bff"},
188 | {file = "fonttools-4.54.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:357cacb988a18aace66e5e55fe1247f2ee706e01debc4b1a20d77400354cddeb"},
189 | {file = "fonttools-4.54.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e953cc0bddc2beaf3a3c3b5dd9ab7554677da72dfaf46951e193c9653e515a"},
190 | {file = "fonttools-4.54.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:58d29b9a294573d8319f16f2f79e42428ba9b6480442fa1836e4eb89c4d9d61c"},
191 | {file = "fonttools-4.54.1-cp313-cp313-win32.whl", hash = "sha256:9ef1b167e22709b46bf8168368b7b5d3efeaaa746c6d39661c1b4405b6352e58"},
192 | {file = "fonttools-4.54.1-cp313-cp313-win_amd64.whl", hash = "sha256:262705b1663f18c04250bd1242b0515d3bbae177bee7752be67c979b7d47f43d"},
193 | {file = "fonttools-4.54.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ed2f80ca07025551636c555dec2b755dd005e2ea8fbeb99fc5cdff319b70b23b"},
194 | {file = "fonttools-4.54.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9dc080e5a1c3b2656caff2ac2633d009b3a9ff7b5e93d0452f40cd76d3da3b3c"},
195 | {file = "fonttools-4.54.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d152d1be65652fc65e695e5619e0aa0982295a95a9b29b52b85775243c06556"},
196 | {file = "fonttools-4.54.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8583e563df41fdecef31b793b4dd3af8a9caa03397be648945ad32717a92885b"},
197 | {file = "fonttools-4.54.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0d1d353ef198c422515a3e974a1e8d5b304cd54a4c2eebcae708e37cd9eeffb1"},
198 | {file = "fonttools-4.54.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fda582236fee135d4daeca056c8c88ec5f6f6d88a004a79b84a02547c8f57386"},
199 | {file = "fonttools-4.54.1-cp38-cp38-win32.whl", hash = "sha256:e7d82b9e56716ed32574ee106cabca80992e6bbdcf25a88d97d21f73a0aae664"},
200 | {file = "fonttools-4.54.1-cp38-cp38-win_amd64.whl", hash = "sha256:ada215fd079e23e060157aab12eba0d66704316547f334eee9ff26f8c0d7b8ab"},
201 | {file = "fonttools-4.54.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5b8a096e649768c2f4233f947cf9737f8dbf8728b90e2771e2497c6e3d21d13"},
202 | {file = "fonttools-4.54.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e10d2e0a12e18f4e2dd031e1bf7c3d7017be5c8dbe524d07706179f355c5dac"},
203 | {file = "fonttools-4.54.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31c32d7d4b0958600eac75eaf524b7b7cb68d3a8c196635252b7a2c30d80e986"},
204 | {file = "fonttools-4.54.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c39287f5c8f4a0c5a55daf9eaf9ccd223ea59eed3f6d467133cc727d7b943a55"},
205 | {file = "fonttools-4.54.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a7a310c6e0471602fe3bf8efaf193d396ea561486aeaa7adc1f132e02d30c4b9"},
206 | {file = "fonttools-4.54.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d3b659d1029946f4ff9b6183984578041b520ce0f8fb7078bb37ec7445806b33"},
207 | {file = "fonttools-4.54.1-cp39-cp39-win32.whl", hash = "sha256:e96bc94c8cda58f577277d4a71f51c8e2129b8b36fd05adece6320dd3d57de8a"},
208 | {file = "fonttools-4.54.1-cp39-cp39-win_amd64.whl", hash = "sha256:e8a4b261c1ef91e7188a30571be6ad98d1c6d9fa2427244c545e2fa0a2494dd7"},
209 | {file = "fonttools-4.54.1-py3-none-any.whl", hash = "sha256:37cddd62d83dc4f72f7c3f3c2bcf2697e89a30efb152079896544a93907733bd"},
210 | {file = "fonttools-4.54.1.tar.gz", hash = "sha256:957f669d4922f92c171ba01bef7f29410668db09f6c02111e22b2bce446f3285"},
211 | ]
212 |
213 | [package.extras]
214 | all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"]
215 | graphite = ["lz4 (>=1.7.4.2)"]
216 | interpolatable = ["munkres", "pycairo", "scipy"]
217 | lxml = ["lxml (>=4.0)"]
218 | pathops = ["skia-pathops (>=0.5.0)"]
219 | plot = ["matplotlib"]
220 | repacker = ["uharfbuzz (>=0.23.0)"]
221 | symfont = ["sympy"]
222 | type1 = ["xattr"]
223 | ufo = ["fs (>=2.2.0,<3)"]
224 | unicode = ["unicodedata2 (>=15.1.0)"]
225 | woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
226 |
227 | [[package]]
228 | name = "isort"
229 | version = "5.13.2"
230 | description = "A Python utility / library to sort Python imports."
231 | optional = false
232 | python-versions = ">=3.8.0"
233 | files = [
234 | {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
235 | {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
236 | ]
237 |
238 | [package.extras]
239 | colors = ["colorama (>=0.4.6)"]
240 |
241 | [[package]]
242 | name = "kiwisolver"
243 | version = "1.4.7"
244 | description = "A fast implementation of the Cassowary constraint solver"
245 | optional = false
246 | python-versions = ">=3.8"
247 | files = [
248 | {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6"},
249 | {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17"},
250 | {file = "kiwisolver-1.4.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa0abdf853e09aff551db11fce173e2177d00786c688203f52c87ad7fcd91ef9"},
251 | {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d53103597a252fb3ab8b5845af04c7a26d5e7ea8122303dd7a021176a87e8b9"},
252 | {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:88f17c5ffa8e9462fb79f62746428dd57b46eb931698e42e990ad63103f35e6c"},
253 | {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a9ca9c710d598fd75ee5de59d5bda2684d9db36a9f50b6125eaea3969c2599"},
254 | {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f4d742cb7af1c28303a51b7a27aaee540e71bb8e24f68c736f6f2ffc82f2bf05"},
255 | {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e28c7fea2196bf4c2f8d46a0415c77a1c480cc0724722f23d7410ffe9842c407"},
256 | {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e968b84db54f9d42046cf154e02911e39c0435c9801681e3fc9ce8a3c4130278"},
257 | {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0c18ec74c0472de033e1bebb2911c3c310eef5649133dd0bedf2a169a1b269e5"},
258 | {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8f0ea6da6d393d8b2e187e6a5e3fb81f5862010a40c3945e2c6d12ae45cfb2ad"},
259 | {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f106407dda69ae456dd1227966bf445b157ccc80ba0dff3802bb63f30b74e895"},
260 | {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84ec80df401cfee1457063732d90022f93951944b5b58975d34ab56bb150dfb3"},
261 | {file = "kiwisolver-1.4.7-cp310-cp310-win32.whl", hash = "sha256:71bb308552200fb2c195e35ef05de12f0c878c07fc91c270eb3d6e41698c3bcc"},
262 | {file = "kiwisolver-1.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:44756f9fd339de0fb6ee4f8c1696cfd19b2422e0d70b4cefc1cc7f1f64045a8c"},
263 | {file = "kiwisolver-1.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:78a42513018c41c2ffd262eb676442315cbfe3c44eed82385c2ed043bc63210a"},
264 | {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54"},
265 | {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95"},
266 | {file = "kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935"},
267 | {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb"},
268 | {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02"},
269 | {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51"},
270 | {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052"},
271 | {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18"},
272 | {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545"},
273 | {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b"},
274 | {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36"},
275 | {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3"},
276 | {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523"},
277 | {file = "kiwisolver-1.4.7-cp311-cp311-win32.whl", hash = "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d"},
278 | {file = "kiwisolver-1.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b"},
279 | {file = "kiwisolver-1.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376"},
280 | {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2"},
281 | {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a"},
282 | {file = "kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee"},
283 | {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640"},
284 | {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f"},
285 | {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483"},
286 | {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258"},
287 | {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e"},
288 | {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107"},
289 | {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948"},
290 | {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038"},
291 | {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383"},
292 | {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520"},
293 | {file = "kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b"},
294 | {file = "kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb"},
295 | {file = "kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a"},
296 | {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e"},
297 | {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6"},
298 | {file = "kiwisolver-1.4.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750"},
299 | {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d"},
300 | {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379"},
301 | {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c"},
302 | {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34"},
303 | {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1"},
304 | {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f"},
305 | {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b"},
306 | {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27"},
307 | {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a"},
308 | {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee"},
309 | {file = "kiwisolver-1.4.7-cp313-cp313-win32.whl", hash = "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07"},
310 | {file = "kiwisolver-1.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76"},
311 | {file = "kiwisolver-1.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650"},
312 | {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5d5abf8f8ec1f4e22882273c423e16cae834c36856cac348cfbfa68e01c40f3a"},
313 | {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aeb3531b196ef6f11776c21674dba836aeea9d5bd1cf630f869e3d90b16cfade"},
314 | {file = "kiwisolver-1.4.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7d755065e4e866a8086c9bdada157133ff466476a2ad7861828e17b6026e22c"},
315 | {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08471d4d86cbaec61f86b217dd938a83d85e03785f51121e791a6e6689a3be95"},
316 | {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bbfcb7165ce3d54a3dfbe731e470f65739c4c1f85bb1018ee912bae139e263b"},
317 | {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d34eb8494bea691a1a450141ebb5385e4b69d38bb8403b5146ad279f4b30fa3"},
318 | {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9242795d174daa40105c1d86aba618e8eab7bf96ba8c3ee614da8302a9f95503"},
319 | {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a0f64a48bb81af7450e641e3fe0b0394d7381e342805479178b3d335d60ca7cf"},
320 | {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8e045731a5416357638d1700927529e2b8ab304811671f665b225f8bf8d8f933"},
321 | {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4322872d5772cae7369f8351da1edf255a604ea7087fe295411397d0cfd9655e"},
322 | {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e1631290ee9271dffe3062d2634c3ecac02c83890ada077d225e081aca8aab89"},
323 | {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:edcfc407e4eb17e037bca59be0e85a2031a2ac87e4fed26d3e9df88b4165f92d"},
324 | {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4d05d81ecb47d11e7f8932bd8b61b720bf0b41199358f3f5e36d38e28f0532c5"},
325 | {file = "kiwisolver-1.4.7-cp38-cp38-win32.whl", hash = "sha256:b38ac83d5f04b15e515fd86f312479d950d05ce2368d5413d46c088dda7de90a"},
326 | {file = "kiwisolver-1.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:d83db7cde68459fc803052a55ace60bea2bae361fc3b7a6d5da07e11954e4b09"},
327 | {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9362ecfca44c863569d3d3c033dbe8ba452ff8eed6f6b5806382741a1334bd"},
328 | {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8df2eb9b2bac43ef8b082e06f750350fbbaf2887534a5be97f6cf07b19d9583"},
329 | {file = "kiwisolver-1.4.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f32d6edbc638cde7652bd690c3e728b25332acbadd7cad670cc4a02558d9c417"},
330 | {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e2e6c39bd7b9372b0be21456caab138e8e69cc0fc1190a9dfa92bd45a1e6e904"},
331 | {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dda56c24d869b1193fcc763f1284b9126550eaf84b88bbc7256e15028f19188a"},
332 | {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79849239c39b5e1fd906556c474d9b0439ea6792b637511f3fe3a41158d89ca8"},
333 | {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e3bc157fed2a4c02ec468de4ecd12a6e22818d4f09cde2c31ee3226ffbefab2"},
334 | {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3da53da805b71e41053dc670f9a820d1157aae77b6b944e08024d17bcd51ef88"},
335 | {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8705f17dfeb43139a692298cb6637ee2e59c0194538153e83e9ee0c75c2eddde"},
336 | {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:82a5c2f4b87c26bb1a0ef3d16b5c4753434633b83d365cc0ddf2770c93829e3c"},
337 | {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce8be0466f4c0d585cdb6c1e2ed07232221df101a4c6f28821d2aa754ca2d9e2"},
338 | {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:409afdfe1e2e90e6ee7fc896f3df9a7fec8e793e58bfa0d052c8a82f99c37abb"},
339 | {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5b9c3f4ee0b9a439d2415012bd1b1cc2df59e4d6a9939f4d669241d30b414327"},
340 | {file = "kiwisolver-1.4.7-cp39-cp39-win32.whl", hash = "sha256:a79ae34384df2b615eefca647a2873842ac3b596418032bef9a7283675962644"},
341 | {file = "kiwisolver-1.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:cf0438b42121a66a3a667de17e779330fc0f20b0d97d59d2f2121e182b0505e4"},
342 | {file = "kiwisolver-1.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:764202cc7e70f767dab49e8df52c7455e8de0df5d858fa801a11aa0d882ccf3f"},
343 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:94252291e3fe68001b1dd747b4c0b3be12582839b95ad4d1b641924d68fd4643"},
344 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b7dfa3b546da08a9f622bb6becdb14b3e24aaa30adba66749d38f3cc7ea9706"},
345 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd3de6481f4ed8b734da5df134cd5a6a64fe32124fe83dde1e5b5f29fe30b1e6"},
346 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a91b5f9f1205845d488c928e8570dcb62b893372f63b8b6e98b863ebd2368ff2"},
347 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fa14dbd66b8b8f470d5fc79c089a66185619d31645f9b0773b88b19f7223c4"},
348 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:eb542fe7933aa09d8d8f9d9097ef37532a7df6497819d16efe4359890a2f417a"},
349 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bfa1acfa0c54932d5607e19a2c24646fb4c1ae2694437789129cf099789a3b00"},
350 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:eee3ea935c3d227d49b4eb85660ff631556841f6e567f0f7bda972df6c2c9935"},
351 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f3160309af4396e0ed04db259c3ccbfdc3621b5559b5453075e5de555e1f3a1b"},
352 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a17f6a29cf8935e587cc8a4dbfc8368c55edc645283db0ce9801016f83526c2d"},
353 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10849fb2c1ecbfae45a693c070e0320a91b35dd4bcf58172c023b994283a124d"},
354 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ac542bf38a8a4be2dc6b15248d36315ccc65f0743f7b1a76688ffb6b5129a5c2"},
355 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8b01aac285f91ca889c800042c35ad3b239e704b150cfd3382adfc9dcc780e39"},
356 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:48be928f59a1f5c8207154f935334d374e79f2b5d212826307d072595ad76a2e"},
357 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f37cfe618a117e50d8c240555331160d73d0411422b59b5ee217843d7b693608"},
358 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599b5c873c63a1f6ed7eead644a8a380cfbdf5db91dcb6f85707aaab213b1674"},
359 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:801fa7802e5cfabe3ab0c81a34c323a319b097dfb5004be950482d882f3d7225"},
360 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0c6c43471bc764fad4bc99c5c2d6d16a676b1abf844ca7c8702bdae92df01ee0"},
361 | {file = "kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60"},
362 | ]
363 |
364 | [[package]]
365 | name = "markdown-it-py"
366 | version = "3.0.0"
367 | description = "Python port of markdown-it. Markdown parsing, done right!"
368 | optional = false
369 | python-versions = ">=3.8"
370 | files = [
371 | {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
372 | {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
373 | ]
374 |
375 | [package.dependencies]
376 | mdurl = ">=0.1,<1.0"
377 |
378 | [package.extras]
379 | benchmarking = ["psutil", "pytest", "pytest-benchmark"]
380 | code-style = ["pre-commit (>=3.0,<4.0)"]
381 | compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
382 | linkify = ["linkify-it-py (>=1,<3)"]
383 | plugins = ["mdit-py-plugins"]
384 | profiling = ["gprof2dot"]
385 | rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
386 | testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
387 |
388 | [[package]]
389 | name = "matplotlib"
390 | version = "3.9.2"
391 | description = "Python plotting package"
392 | optional = false
393 | python-versions = ">=3.9"
394 | files = [
395 | {file = "matplotlib-3.9.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9d78bbc0cbc891ad55b4f39a48c22182e9bdaea7fc0e5dbd364f49f729ca1bbb"},
396 | {file = "matplotlib-3.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c375cc72229614632c87355366bdf2570c2dac01ac66b8ad048d2dabadf2d0d4"},
397 | {file = "matplotlib-3.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d94ff717eb2bd0b58fe66380bd8b14ac35f48a98e7c6765117fe67fb7684e64"},
398 | {file = "matplotlib-3.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab68d50c06938ef28681073327795c5db99bb4666214d2d5f880ed11aeaded66"},
399 | {file = "matplotlib-3.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:65aacf95b62272d568044531e41de26285d54aec8cb859031f511f84bd8b495a"},
400 | {file = "matplotlib-3.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:3fd595f34aa8a55b7fc8bf9ebea8aa665a84c82d275190a61118d33fbc82ccae"},
401 | {file = "matplotlib-3.9.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8dd059447824eec055e829258ab092b56bb0579fc3164fa09c64f3acd478772"},
402 | {file = "matplotlib-3.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c797dac8bb9c7a3fd3382b16fe8f215b4cf0f22adccea36f1545a6d7be310b41"},
403 | {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d719465db13267bcef19ea8954a971db03b9f48b4647e3860e4bc8e6ed86610f"},
404 | {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8912ef7c2362f7193b5819d17dae8629b34a95c58603d781329712ada83f9447"},
405 | {file = "matplotlib-3.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7741f26a58a240f43bee74965c4882b6c93df3e7eb3de160126d8c8f53a6ae6e"},
406 | {file = "matplotlib-3.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae82a14dab96fbfad7965403c643cafe6515e386de723e498cf3eeb1e0b70cc7"},
407 | {file = "matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9"},
408 | {file = "matplotlib-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d"},
409 | {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7"},
410 | {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c"},
411 | {file = "matplotlib-3.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e"},
412 | {file = "matplotlib-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3"},
413 | {file = "matplotlib-3.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9"},
414 | {file = "matplotlib-3.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa"},
415 | {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b"},
416 | {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413"},
417 | {file = "matplotlib-3.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b"},
418 | {file = "matplotlib-3.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49"},
419 | {file = "matplotlib-3.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03"},
420 | {file = "matplotlib-3.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30"},
421 | {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51"},
422 | {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c"},
423 | {file = "matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e"},
424 | {file = "matplotlib-3.9.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:cef2a73d06601437be399908cf13aee74e86932a5ccc6ccdf173408ebc5f6bb2"},
425 | {file = "matplotlib-3.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e0830e188029c14e891fadd99702fd90d317df294c3298aad682739c5533721a"},
426 | {file = "matplotlib-3.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ba9c1299c920964e8d3857ba27173b4dbb51ca4bab47ffc2c2ba0eb5e2cbc5"},
427 | {file = "matplotlib-3.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cd93b91ab47a3616b4d3c42b52f8363b88ca021e340804c6ab2536344fad9ca"},
428 | {file = "matplotlib-3.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6d1ce5ed2aefcdce11904fc5bbea7d9c21fff3d5f543841edf3dea84451a09ea"},
429 | {file = "matplotlib-3.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:b2696efdc08648536efd4e1601b5fd491fd47f4db97a5fbfd175549a7365c1b2"},
430 | {file = "matplotlib-3.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d52a3b618cb1cbb769ce2ee1dcdb333c3ab6e823944e9a2d36e37253815f9556"},
431 | {file = "matplotlib-3.9.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:039082812cacd6c6bec8e17a9c1e6baca230d4116d522e81e1f63a74d01d2e21"},
432 | {file = "matplotlib-3.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6758baae2ed64f2331d4fd19be38b7b4eae3ecec210049a26b6a4f3ae1c85dcc"},
433 | {file = "matplotlib-3.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:050598c2b29e0b9832cde72bcf97627bf00262adbc4a54e2b856426bb2ef0697"},
434 | {file = "matplotlib-3.9.2.tar.gz", hash = "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92"},
435 | ]
436 |
437 | [package.dependencies]
438 | contourpy = ">=1.0.1"
439 | cycler = ">=0.10"
440 | fonttools = ">=4.22.0"
441 | kiwisolver = ">=1.3.1"
442 | numpy = ">=1.23"
443 | packaging = ">=20.0"
444 | pillow = ">=8"
445 | pyparsing = ">=2.3.1"
446 | python-dateutil = ">=2.7"
447 |
448 | [package.extras]
449 | dev = ["meson-python (>=0.13.1)", "numpy (>=1.25)", "pybind11 (>=2.6)", "setuptools (>=64)", "setuptools_scm (>=7)"]
450 |
451 | [[package]]
452 | name = "mccabe"
453 | version = "0.7.0"
454 | description = "McCabe checker, plugin for flake8"
455 | optional = false
456 | python-versions = ">=3.6"
457 | files = [
458 | {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
459 | {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
460 | ]
461 |
462 | [[package]]
463 | name = "mdurl"
464 | version = "0.1.2"
465 | description = "Markdown URL utilities"
466 | optional = false
467 | python-versions = ">=3.7"
468 | files = [
469 | {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
470 | {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
471 | ]
472 |
473 | [[package]]
474 | name = "mouseinfo"
475 | version = "0.1.3"
476 | description = "An application to display XY position and RGB color information for the pixel currently under the mouse. Works on Python 2 and 3."
477 | optional = false
478 | python-versions = "*"
479 | files = [
480 | {file = "MouseInfo-0.1.3.tar.gz", hash = "sha256:2c62fb8885062b8e520a3cce0a297c657adcc08c60952eb05bc8256ef6f7f6e7"},
481 | ]
482 |
483 | [package.dependencies]
484 | pyperclip = "*"
485 | python3-Xlib = {version = "*", markers = "platform_system == \"Linux\" and python_version >= \"3.0\""}
486 | rubicon-objc = {version = "*", markers = "platform_system == \"Darwin\""}
487 |
488 | [[package]]
489 | name = "mypy"
490 | version = "1.11.2"
491 | description = "Optional static typing for Python"
492 | optional = false
493 | python-versions = ">=3.8"
494 | files = [
495 | {file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"},
496 | {file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"},
497 | {file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"},
498 | {file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"},
499 | {file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"},
500 | {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"},
501 | {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"},
502 | {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"},
503 | {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"},
504 | {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"},
505 | {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"},
506 | {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"},
507 | {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"},
508 | {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"},
509 | {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"},
510 | {file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"},
511 | {file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"},
512 | {file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"},
513 | {file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"},
514 | {file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"},
515 | {file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"},
516 | {file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"},
517 | {file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"},
518 | {file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"},
519 | {file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"},
520 | {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"},
521 | {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"},
522 | ]
523 |
524 | [package.dependencies]
525 | mypy-extensions = ">=1.0.0"
526 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
527 | typing-extensions = ">=4.6.0"
528 |
529 | [package.extras]
530 | dmypy = ["psutil (>=4.0)"]
531 | install-types = ["pip"]
532 | mypyc = ["setuptools (>=50)"]
533 | reports = ["lxml"]
534 |
535 | [[package]]
536 | name = "mypy-extensions"
537 | version = "1.0.0"
538 | description = "Type system extensions for programs checked with the mypy type checker."
539 | optional = false
540 | python-versions = ">=3.5"
541 | files = [
542 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
543 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
544 | ]
545 |
546 | [[package]]
547 | name = "noise"
548 | version = "1.2.2"
549 | description = "Perlin noise for Python"
550 | optional = false
551 | python-versions = "*"
552 | files = [
553 | {file = "noise-1.2.2-cp27-none-win32.whl", hash = "sha256:f7ef26a4c334224e7763e740fc945c26c0abf9ba51a19d4f5befa1d20d7da0b7"},
554 | {file = "noise-1.2.2-cp27-none-win_amd64.whl", hash = "sha256:15582a58c9ee79b07436a1220bd6c4145266865262d1e6478d37a08b7d910da8"},
555 | {file = "noise-1.2.2-cp33-none-win32.whl", hash = "sha256:93ac2977cf0e8f5cb90a2e828a5dfefc438bfb1fb8d7fd1ee305f05eadc8578e"},
556 | {file = "noise-1.2.2-cp33-none-win_amd64.whl", hash = "sha256:20d1c89a2b8c3714abe5a5fa653b3ab9ab01aee1475993b8bdb9d5e26bc081cc"},
557 | {file = "noise-1.2.2-cp34-none-win32.whl", hash = "sha256:f82933563ef89651865cc7cbfab11721a2229f5c6c8c009a041be4fb887949f2"},
558 | {file = "noise-1.2.2-cp34-none-win_amd64.whl", hash = "sha256:065be3531a6b7a7dfcb6840646400a75e081511c524caa04feaea11e16e7ab24"},
559 | {file = "noise-1.2.2.tar.gz", hash = "sha256:57a2797436574391ff63a111e852e53a4164ecd81ad23639641743cd1a209b65"},
560 | {file = "noise-1.2.2.zip", hash = "sha256:36036cdaca131ddd2ab4397fba649af7f074ec08031e1e0a51031d0ae23b509a"},
561 | ]
562 |
563 | [[package]]
564 | name = "numpy"
565 | version = "2.1.1"
566 | description = "Fundamental package for array computing in Python"
567 | optional = false
568 | python-versions = ">=3.10"
569 | files = [
570 | {file = "numpy-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8a0e34993b510fc19b9a2ce7f31cb8e94ecf6e924a40c0c9dd4f62d0aac47d9"},
571 | {file = "numpy-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7dd86dfaf7c900c0bbdcb8b16e2f6ddf1eb1fe39c6c8cca6e94844ed3152a8fd"},
572 | {file = "numpy-2.1.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:5889dd24f03ca5a5b1e8a90a33b5a0846d8977565e4ae003a63d22ecddf6782f"},
573 | {file = "numpy-2.1.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:59ca673ad11d4b84ceb385290ed0ebe60266e356641428c845b39cd9df6713ab"},
574 | {file = "numpy-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13ce49a34c44b6de5241f0b38b07e44c1b2dcacd9e36c30f9c2fcb1bb5135db7"},
575 | {file = "numpy-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913cc1d311060b1d409e609947fa1b9753701dac96e6581b58afc36b7ee35af6"},
576 | {file = "numpy-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:caf5d284ddea7462c32b8d4a6b8af030b6c9fd5332afb70e7414d7fdded4bfd0"},
577 | {file = "numpy-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:57eb525e7c2a8fdee02d731f647146ff54ea8c973364f3b850069ffb42799647"},
578 | {file = "numpy-2.1.1-cp310-cp310-win32.whl", hash = "sha256:9a8e06c7a980869ea67bbf551283bbed2856915f0a792dc32dd0f9dd2fb56728"},
579 | {file = "numpy-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d10c39947a2d351d6d466b4ae83dad4c37cd6c3cdd6d5d0fa797da56f710a6ae"},
580 | {file = "numpy-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0d07841fd284718feffe7dd17a63a2e6c78679b2d386d3e82f44f0108c905550"},
581 | {file = "numpy-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b5613cfeb1adfe791e8e681128f5f49f22f3fcaa942255a6124d58ca59d9528f"},
582 | {file = "numpy-2.1.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0b8cc2715a84b7c3b161f9ebbd942740aaed913584cae9cdc7f8ad5ad41943d0"},
583 | {file = "numpy-2.1.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:b49742cdb85f1f81e4dc1b39dcf328244f4d8d1ded95dea725b316bd2cf18c95"},
584 | {file = "numpy-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8d5f8a8e3bc87334f025194c6193e408903d21ebaeb10952264943a985066ca"},
585 | {file = "numpy-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d51fc141ddbe3f919e91a096ec739f49d686df8af254b2053ba21a910ae518bf"},
586 | {file = "numpy-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:98ce7fb5b8063cfdd86596b9c762bf2b5e35a2cdd7e967494ab78a1fa7f8b86e"},
587 | {file = "numpy-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:24c2ad697bd8593887b019817ddd9974a7f429c14a5469d7fad413f28340a6d2"},
588 | {file = "numpy-2.1.1-cp311-cp311-win32.whl", hash = "sha256:397bc5ce62d3fb73f304bec332171535c187e0643e176a6e9421a6e3eacef06d"},
589 | {file = "numpy-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:ae8ce252404cdd4de56dcfce8b11eac3c594a9c16c231d081fb705cf23bd4d9e"},
590 | {file = "numpy-2.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c803b7934a7f59563db459292e6aa078bb38b7ab1446ca38dd138646a38203e"},
591 | {file = "numpy-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6435c48250c12f001920f0751fe50c0348f5f240852cfddc5e2f97e007544cbe"},
592 | {file = "numpy-2.1.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3269c9eb8745e8d975980b3a7411a98976824e1fdef11f0aacf76147f662b15f"},
593 | {file = "numpy-2.1.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:fac6e277a41163d27dfab5f4ec1f7a83fac94e170665a4a50191b545721c6521"},
594 | {file = "numpy-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcd8f556cdc8cfe35e70efb92463082b7f43dd7e547eb071ffc36abc0ca4699b"},
595 | {file = "numpy-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b9cd92c8f8e7b313b80e93cedc12c0112088541dcedd9197b5dee3738c1201"},
596 | {file = "numpy-2.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:afd9c680df4de71cd58582b51e88a61feed4abcc7530bcd3d48483f20fc76f2a"},
597 | {file = "numpy-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8661c94e3aad18e1ea17a11f60f843a4933ccaf1a25a7c6a9182af70610b2313"},
598 | {file = "numpy-2.1.1-cp312-cp312-win32.whl", hash = "sha256:950802d17a33c07cba7fd7c3dcfa7d64705509206be1606f196d179e539111ed"},
599 | {file = "numpy-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:3fc5eabfc720db95d68e6646e88f8b399bfedd235994016351b1d9e062c4b270"},
600 | {file = "numpy-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:046356b19d7ad1890c751b99acad5e82dc4a02232013bd9a9a712fddf8eb60f5"},
601 | {file = "numpy-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e5a9cb2be39350ae6c8f79410744e80154df658d5bea06e06e0ac5bb75480d5"},
602 | {file = "numpy-2.1.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:d4c57b68c8ef5e1ebf47238e99bf27657511ec3f071c465f6b1bccbef12d4136"},
603 | {file = "numpy-2.1.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:8ae0fd135e0b157365ac7cc31fff27f07a5572bdfc38f9c2d43b2aff416cc8b0"},
604 | {file = "numpy-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981707f6b31b59c0c24bcda52e5605f9701cb46da4b86c2e8023656ad3e833cb"},
605 | {file = "numpy-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ca4b53e1e0b279142113b8c5eb7d7a877e967c306edc34f3b58e9be12fda8df"},
606 | {file = "numpy-2.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e097507396c0be4e547ff15b13dc3866f45f3680f789c1a1301b07dadd3fbc78"},
607 | {file = "numpy-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7506387e191fe8cdb267f912469a3cccc538ab108471291636a96a54e599556"},
608 | {file = "numpy-2.1.1-cp313-cp313-win32.whl", hash = "sha256:251105b7c42abe40e3a689881e1793370cc9724ad50d64b30b358bbb3a97553b"},
609 | {file = "numpy-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:f212d4f46b67ff604d11fff7cc62d36b3e8714edf68e44e9760e19be38c03eb0"},
610 | {file = "numpy-2.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:920b0911bb2e4414c50e55bd658baeb78281a47feeb064ab40c2b66ecba85553"},
611 | {file = "numpy-2.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:bab7c09454460a487e631ffc0c42057e3d8f2a9ddccd1e60c7bb8ed774992480"},
612 | {file = "numpy-2.1.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:cea427d1350f3fd0d2818ce7350095c1a2ee33e30961d2f0fef48576ddbbe90f"},
613 | {file = "numpy-2.1.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:e30356d530528a42eeba51420ae8bf6c6c09559051887196599d96ee5f536468"},
614 | {file = "numpy-2.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8dfa9e94fc127c40979c3eacbae1e61fda4fe71d84869cc129e2721973231ef"},
615 | {file = "numpy-2.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910b47a6d0635ec1bd53b88f86120a52bf56dcc27b51f18c7b4a2e2224c29f0f"},
616 | {file = "numpy-2.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:13cc11c00000848702322af4de0147ced365c81d66053a67c2e962a485b3717c"},
617 | {file = "numpy-2.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53e27293b3a2b661c03f79aa51c3987492bd4641ef933e366e0f9f6c9bf257ec"},
618 | {file = "numpy-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7be6a07520b88214ea85d8ac8b7d6d8a1839b0b5cb87412ac9f49fa934eb15d5"},
619 | {file = "numpy-2.1.1-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:52ac2e48f5ad847cd43c4755520a2317f3380213493b9d8a4c5e37f3b87df504"},
620 | {file = "numpy-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50a95ca3560a6058d6ea91d4629a83a897ee27c00630aed9d933dff191f170cd"},
621 | {file = "numpy-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:99f4a9ee60eed1385a86e82288971a51e71df052ed0b2900ed30bc840c0f2e39"},
622 | {file = "numpy-2.1.1.tar.gz", hash = "sha256:d0cf7d55b1051387807405b3898efafa862997b4cba8aa5dbe657be794afeafd"},
623 | ]
624 |
625 | [[package]]
626 | name = "packaging"
627 | version = "24.1"
628 | description = "Core utilities for Python packages"
629 | optional = false
630 | python-versions = ">=3.8"
631 | files = [
632 | {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
633 | {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
634 | ]
635 |
636 | [[package]]
637 | name = "pillow"
638 | version = "10.4.0"
639 | description = "Python Imaging Library (Fork)"
640 | optional = false
641 | python-versions = ">=3.8"
642 | files = [
643 | {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"},
644 | {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"},
645 | {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"},
646 | {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"},
647 | {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"},
648 | {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"},
649 | {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"},
650 | {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"},
651 | {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"},
652 | {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"},
653 | {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"},
654 | {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"},
655 | {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"},
656 | {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"},
657 | {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"},
658 | {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"},
659 | {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"},
660 | {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"},
661 | {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"},
662 | {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"},
663 | {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"},
664 | {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"},
665 | {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"},
666 | {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"},
667 | {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"},
668 | {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"},
669 | {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"},
670 | {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"},
671 | {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"},
672 | {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"},
673 | {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"},
674 | {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"},
675 | {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"},
676 | {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"},
677 | {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"},
678 | {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"},
679 | {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"},
680 | {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"},
681 | {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"},
682 | {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"},
683 | {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"},
684 | {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"},
685 | {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"},
686 | {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"},
687 | {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"},
688 | {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"},
689 | {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"},
690 | {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"},
691 | {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"},
692 | {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"},
693 | {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"},
694 | {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"},
695 | {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"},
696 | {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"},
697 | {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"},
698 | {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"},
699 | {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"},
700 | {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"},
701 | {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"},
702 | {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"},
703 | {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"},
704 | {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"},
705 | {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"},
706 | {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"},
707 | {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"},
708 | {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"},
709 | {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"},
710 | {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"},
711 | {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"},
712 | {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"},
713 | {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"},
714 | {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"},
715 | {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"},
716 | {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"},
717 | {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"},
718 | {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"},
719 | {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"},
720 | {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"},
721 | {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"},
722 | {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"},
723 | ]
724 |
725 | [package.extras]
726 | docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
727 | fpx = ["olefile"]
728 | mic = ["olefile"]
729 | tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
730 | typing = ["typing-extensions"]
731 | xmp = ["defusedxml"]
732 |
733 | [[package]]
734 | name = "platformdirs"
735 | version = "4.3.6"
736 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
737 | optional = false
738 | python-versions = ">=3.8"
739 | files = [
740 | {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
741 | {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
742 | ]
743 |
744 | [package.extras]
745 | docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"]
746 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
747 | type = ["mypy (>=1.11.2)"]
748 |
749 | [[package]]
750 | name = "pyautogui"
751 | version = "0.9.54"
752 | description = "PyAutoGUI lets Python control the mouse and keyboard, and other GUI automation tasks. For Windows, macOS, and Linux, on Python 3 and 2."
753 | optional = false
754 | python-versions = "*"
755 | files = [
756 | {file = "PyAutoGUI-0.9.54.tar.gz", hash = "sha256:dd1d29e8fd118941cb193f74df57e5c6ff8e9253b99c7b04f39cfc69f3ae04b2"},
757 | ]
758 |
759 | [package.dependencies]
760 | mouseinfo = "*"
761 | pygetwindow = ">=0.0.5"
762 | pymsgbox = "*"
763 | pyobjc-core = {version = "*", markers = "platform_system == \"Darwin\""}
764 | pyobjc-framework-quartz = {version = "*", markers = "platform_system == \"Darwin\""}
765 | pyscreeze = ">=0.1.21"
766 | python3-Xlib = {version = "*", markers = "platform_system == \"Linux\" and python_version >= \"3.0\""}
767 | pytweening = ">=1.0.4"
768 |
769 | [[package]]
770 | name = "pygetwindow"
771 | version = "0.0.9"
772 | description = "A simple, cross-platform module for obtaining GUI information on application's windows."
773 | optional = false
774 | python-versions = "*"
775 | files = [
776 | {file = "PyGetWindow-0.0.9.tar.gz", hash = "sha256:17894355e7d2b305cd832d717708384017c1698a90ce24f6f7fbf0242dd0a688"},
777 | ]
778 |
779 | [package.dependencies]
780 | pyrect = "*"
781 |
782 | [[package]]
783 | name = "pygments"
784 | version = "2.18.0"
785 | description = "Pygments is a syntax highlighting package written in Python."
786 | optional = false
787 | python-versions = ">=3.8"
788 | files = [
789 | {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
790 | {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
791 | ]
792 |
793 | [package.extras]
794 | windows-terminal = ["colorama (>=0.4.6)"]
795 |
796 | [[package]]
797 | name = "pyhm"
798 | version = "0.0.7"
799 | description = "Python Human Movement is a python package which imitates human movements"
800 | optional = false
801 | python-versions = "*"
802 | files = [
803 | {file = "pyHM-0.0.7-py3-none-any.whl", hash = "sha256:e5d8000a067b4cf7187728d3ab90b57eb4dc8dd2a022dacfba5fc4443aa1b0e3"},
804 | {file = "pyHM-0.0.7.tar.gz", hash = "sha256:fe4d66a61af30085fe5678d728820d0860738d2ebe3babd318fe7f8052320cd0"},
805 | ]
806 |
807 | [package.dependencies]
808 | numpy = ">=1.20.1"
809 | PyAutoGUI = ">=0.9.52"
810 | scipy = ">=1.6.1"
811 |
812 | [[package]]
813 | name = "pylint"
814 | version = "3.3.1"
815 | description = "python code static checker"
816 | optional = false
817 | python-versions = ">=3.9.0"
818 | files = [
819 | {file = "pylint-3.3.1-py3-none-any.whl", hash = "sha256:2f846a466dd023513240bc140ad2dd73bfc080a5d85a710afdb728c420a5a2b9"},
820 | {file = "pylint-3.3.1.tar.gz", hash = "sha256:9f3dcc87b1203e612b78d91a896407787e708b3f189b5fa0b307712d49ff0c6e"},
821 | ]
822 |
823 | [package.dependencies]
824 | astroid = ">=3.3.4,<=3.4.0-dev0"
825 | colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
826 | dill = [
827 | {version = ">=0.2", markers = "python_version < \"3.11\""},
828 | {version = ">=0.3.7", markers = "python_version >= \"3.12\""},
829 | {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
830 | ]
831 | isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
832 | mccabe = ">=0.6,<0.8"
833 | platformdirs = ">=2.2.0"
834 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
835 | tomlkit = ">=0.10.1"
836 |
837 | [package.extras]
838 | spelling = ["pyenchant (>=3.2,<4.0)"]
839 | testutils = ["gitpython (>3)"]
840 |
841 | [[package]]
842 | name = "pymsgbox"
843 | version = "1.0.9"
844 | description = "A simple, cross-platform, pure Python module for JavaScript-like message boxes."
845 | optional = false
846 | python-versions = "*"
847 | files = [
848 | {file = "PyMsgBox-1.0.9.tar.gz", hash = "sha256:2194227de8bff7a3d6da541848705a155dcbb2a06ee120d9f280a1d7f51263ff"},
849 | ]
850 |
851 | [[package]]
852 | name = "pyobjc-core"
853 | version = "10.3.1"
854 | description = "Python<->ObjC Interoperability Module"
855 | optional = false
856 | python-versions = ">=3.8"
857 | files = [
858 | {file = "pyobjc_core-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ea46d2cda17921e417085ac6286d43ae448113158afcf39e0abe484c58fb3d78"},
859 | {file = "pyobjc_core-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:899d3c84d2933d292c808f385dc881a140cf08632907845043a333a9d7c899f9"},
860 | {file = "pyobjc_core-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6ff5823d13d0a534cdc17fa4ad47cf5bee4846ce0fd27fc40012e12b46db571b"},
861 | {file = "pyobjc_core-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2581e8e68885bcb0e11ec619e81ef28e08ee3fac4de20d8cc83bc5af5bcf4a90"},
862 | {file = "pyobjc_core-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ea98d4c2ec39ca29e62e0327db21418696161fb138ee6278daf2acbedf7ce504"},
863 | {file = "pyobjc_core-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:4c179c26ee2123d0aabffb9dbc60324b62b6f8614fb2c2328b09386ef59ef6d8"},
864 | {file = "pyobjc_core-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cb901fce65c9be420c40d8a6ee6fff5ff27c6945f44fd7191989b982baa66dea"},
865 | {file = "pyobjc_core-10.3.1.tar.gz", hash = "sha256:b204a80ccc070f9ab3f8af423a3a25a6fd787e228508d00c4c30f8ac538ba720"},
866 | ]
867 |
868 | [[package]]
869 | name = "pyobjc-framework-cocoa"
870 | version = "10.3.1"
871 | description = "Wrappers for the Cocoa frameworks on macOS"
872 | optional = false
873 | python-versions = ">=3.8"
874 | files = [
875 | {file = "pyobjc_framework_Cocoa-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4cb4f8491ab4d9b59f5187e42383f819f7a46306a4fa25b84f126776305291d1"},
876 | {file = "pyobjc_framework_Cocoa-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5f31021f4f8fdf873b57a97ee1f3c1620dbe285e0b4eaed73dd0005eb72fd773"},
877 | {file = "pyobjc_framework_Cocoa-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11b4e0bad4bbb44a4edda128612f03cdeab38644bbf174de0c13129715497296"},
878 | {file = "pyobjc_framework_Cocoa-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:de5e62e5ccf2871a94acf3bf79646b20ea893cc9db78afa8d1fe1b0d0f7cbdb0"},
879 | {file = "pyobjc_framework_Cocoa-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c5af24610ab639bd1f521ce4500484b40787f898f691b7a23da3339e6bc8b90"},
880 | {file = "pyobjc_framework_Cocoa-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:a7151186bb7805deea434fae9a4423335e6371d105f29e73cc2036c6779a9dbc"},
881 | {file = "pyobjc_framework_Cocoa-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:743d2a1ac08027fd09eab65814c79002a1d0421d7c0074ffd1217b6560889744"},
882 | {file = "pyobjc_framework_cocoa-10.3.1.tar.gz", hash = "sha256:1cf20714daaa986b488fb62d69713049f635c9d41a60c8da97d835710445281a"},
883 | ]
884 |
885 | [package.dependencies]
886 | pyobjc-core = ">=10.3.1"
887 |
888 | [[package]]
889 | name = "pyobjc-framework-quartz"
890 | version = "10.3.1"
891 | description = "Wrappers for the Quartz frameworks on macOS"
892 | optional = false
893 | python-versions = ">=3.8"
894 | files = [
895 | {file = "pyobjc_framework_Quartz-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5ef4fd315ed2bc42ef77fdeb2bae28a88ec986bd7b8079a87ba3b3475348f96e"},
896 | {file = "pyobjc_framework_Quartz-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:96578d4a3e70164efe44ad7dc320ecd4e211758ffcde5dcd694de1bbdfe090a4"},
897 | {file = "pyobjc_framework_Quartz-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ca35f92486869a41847a1703bb176aab8a53dbfd8e678d1f4d68d8e6e1581c71"},
898 | {file = "pyobjc_framework_Quartz-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:00a0933267e3a46ea4afcc35d117b2efb920f06de797fa66279c52e7057e3590"},
899 | {file = "pyobjc_framework_Quartz-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a161bedb4c5257a02ad56a910cd7eefb28bdb0ea78607df0d70ed4efe4ea54c1"},
900 | {file = "pyobjc_framework_Quartz-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d7a8028e117a94923a511944bfa9daf9744e212f06cf89010c60934a479863a5"},
901 | {file = "pyobjc_framework_Quartz-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:de00c983b3267eb26fa42c6ed9f15e2bf006bde8afa7fe2b390646aa21a5d6fc"},
902 | {file = "pyobjc_framework_quartz-10.3.1.tar.gz", hash = "sha256:b6d7e346d735c9a7f147cd78e6da79eeae416a0b7d3874644c83a23786c6f886"},
903 | ]
904 |
905 | [package.dependencies]
906 | pyobjc-core = ">=10.3.1"
907 | pyobjc-framework-Cocoa = ">=10.3.1"
908 |
909 | [[package]]
910 | name = "pyparsing"
911 | version = "3.1.4"
912 | description = "pyparsing module - Classes and methods to define and execute parsing grammars"
913 | optional = false
914 | python-versions = ">=3.6.8"
915 | files = [
916 | {file = "pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c"},
917 | {file = "pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032"},
918 | ]
919 |
920 | [package.extras]
921 | diagrams = ["jinja2", "railroad-diagrams"]
922 |
923 | [[package]]
924 | name = "pyperclip"
925 | version = "1.9.0"
926 | description = "A cross-platform clipboard module for Python. (Only handles plain text for now.)"
927 | optional = false
928 | python-versions = "*"
929 | files = [
930 | {file = "pyperclip-1.9.0.tar.gz", hash = "sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310"},
931 | ]
932 |
933 | [[package]]
934 | name = "pyrect"
935 | version = "0.2.0"
936 | description = "PyRect is a simple module with a Rect class for Pygame-like rectangular areas."
937 | optional = false
938 | python-versions = "*"
939 | files = [
940 | {file = "PyRect-0.2.0.tar.gz", hash = "sha256:f65155f6df9b929b67caffbd57c0947c5ae5449d3b580d178074bffb47a09b78"},
941 | ]
942 |
943 | [[package]]
944 | name = "pyscreeze"
945 | version = "1.0.1"
946 | description = "A simple, cross-platform screenshot module for Python 2 and 3."
947 | optional = false
948 | python-versions = "*"
949 | files = [
950 | {file = "pyscreeze-1.0.1.tar.gz", hash = "sha256:cf1662710f1b46aa5ff229ee23f367da9e20af4a78e6e365bee973cad0ead4be"},
951 | ]
952 |
953 | [package.dependencies]
954 | Pillow = [
955 | {version = ">=9.2.0", markers = "python_version == \"3.10\""},
956 | {version = ">=9.3.0", markers = "python_version == \"3.11\""},
957 | ]
958 |
959 | [[package]]
960 | name = "python-dateutil"
961 | version = "2.9.0.post0"
962 | description = "Extensions to the standard Python datetime module"
963 | optional = false
964 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
965 | files = [
966 | {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
967 | {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
968 | ]
969 |
970 | [package.dependencies]
971 | six = ">=1.5"
972 |
973 | [[package]]
974 | name = "python3-xlib"
975 | version = "0.15"
976 | description = "Python3 X Library"
977 | optional = false
978 | python-versions = "*"
979 | files = [
980 | {file = "python3-xlib-0.15.tar.gz", hash = "sha256:dc4245f3ae4aa5949c1d112ee4723901ade37a96721ba9645f2bfa56e5b383f8"},
981 | ]
982 |
983 | [[package]]
984 | name = "pytweening"
985 | version = "1.2.0"
986 | description = "A collection of tweening (aka easing) functions."
987 | optional = false
988 | python-versions = "*"
989 | files = [
990 | {file = "pytweening-1.2.0.tar.gz", hash = "sha256:243318b7736698066c5f362ec5c2b6434ecf4297c3c8e7caa8abfe6af4cac71b"},
991 | ]
992 |
993 | [[package]]
994 | name = "rich"
995 | version = "13.8.1"
996 | description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
997 | optional = false
998 | python-versions = ">=3.7.0"
999 | files = [
1000 | {file = "rich-13.8.1-py3-none-any.whl", hash = "sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06"},
1001 | {file = "rich-13.8.1.tar.gz", hash = "sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a"},
1002 | ]
1003 |
1004 | [package.dependencies]
1005 | markdown-it-py = ">=2.2.0"
1006 | pygments = ">=2.13.0,<3.0.0"
1007 |
1008 | [package.extras]
1009 | jupyter = ["ipywidgets (>=7.5.1,<9)"]
1010 |
1011 | [[package]]
1012 | name = "rubicon-objc"
1013 | version = "0.4.9"
1014 | description = "A bridge between an Objective C runtime environment and Python."
1015 | optional = false
1016 | python-versions = ">=3.8"
1017 | files = [
1018 | {file = "rubicon_objc-0.4.9-py3-none-any.whl", hash = "sha256:c351b3800cf74c8c23f7d534f008fd5de46c63818de7a44de96daffdb3ed8b8c"},
1019 | {file = "rubicon_objc-0.4.9.tar.gz", hash = "sha256:3d77a5b2d10cb1e49679aa90b7824b46f67b3fd636229aa4a1b902d24aec6a58"},
1020 | ]
1021 |
1022 | [package.extras]
1023 | dev = ["pre-commit (==3.5.0)", "pre-commit (==3.7.0)", "pytest (==8.2.0)", "pytest-tldr (==0.2.5)", "setuptools-scm (==8.0.4)", "tox (==4.15.0)"]
1024 | docs = ["furo (==2024.4.27)", "pyenchant (==3.2.2)", "sphinx (==7.1.2)", "sphinx (==7.3.7)", "sphinx-autobuild (==2021.3.14)", "sphinx-autobuild (==2024.4.16)", "sphinx-copybutton (==0.5.2)", "sphinx-tabs (==3.4.5)", "sphinxcontrib-spelling (==8.0.0)"]
1025 |
1026 | [[package]]
1027 | name = "ruff"
1028 | version = "0.6.7"
1029 | description = "An extremely fast Python linter and code formatter, written in Rust."
1030 | optional = false
1031 | python-versions = ">=3.7"
1032 | files = [
1033 | {file = "ruff-0.6.7-py3-none-linux_armv6l.whl", hash = "sha256:08277b217534bfdcc2e1377f7f933e1c7957453e8a79764d004e44c40db923f2"},
1034 | {file = "ruff-0.6.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c6707a32e03b791f4448dc0dce24b636cbcdee4dd5607adc24e5ee73fd86c00a"},
1035 | {file = "ruff-0.6.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:533d66b7774ef224e7cf91506a7dafcc9e8ec7c059263ec46629e54e7b1f90ab"},
1036 | {file = "ruff-0.6.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17a86aac6f915932d259f7bec79173e356165518859f94649d8c50b81ff087e9"},
1037 | {file = "ruff-0.6.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b3f8822defd260ae2460ea3832b24d37d203c3577f48b055590a426a722d50ef"},
1038 | {file = "ruff-0.6.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ba4efe5c6dbbb58be58dd83feedb83b5e95c00091bf09987b4baf510fee5c99"},
1039 | {file = "ruff-0.6.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:525201b77f94d2b54868f0cbe5edc018e64c22563da6c5c2e5c107a4e85c1c0d"},
1040 | {file = "ruff-0.6.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8854450839f339e1049fdbe15d875384242b8e85d5c6947bb2faad33c651020b"},
1041 | {file = "ruff-0.6.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f0b62056246234d59cbf2ea66e84812dc9ec4540518e37553513392c171cb18"},
1042 | {file = "ruff-0.6.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b1462fa56c832dc0cea5b4041cfc9c97813505d11cce74ebc6d1aae068de36b"},
1043 | {file = "ruff-0.6.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:02b083770e4cdb1495ed313f5694c62808e71764ec6ee5db84eedd82fd32d8f5"},
1044 | {file = "ruff-0.6.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c05fd37013de36dfa883a3854fae57b3113aaa8abf5dea79202675991d48624"},
1045 | {file = "ruff-0.6.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f49c9caa28d9bbfac4a637ae10327b3db00f47d038f3fbb2195c4d682e925b14"},
1046 | {file = "ruff-0.6.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a0e1655868164e114ba43a908fd2d64a271a23660195017c17691fb6355d59bb"},
1047 | {file = "ruff-0.6.7-py3-none-win32.whl", hash = "sha256:a939ca435b49f6966a7dd64b765c9df16f1faed0ca3b6f16acdf7731969deb35"},
1048 | {file = "ruff-0.6.7-py3-none-win_amd64.whl", hash = "sha256:590445eec5653f36248584579c06252ad2e110a5d1f32db5420de35fb0e1c977"},
1049 | {file = "ruff-0.6.7-py3-none-win_arm64.whl", hash = "sha256:b28f0d5e2f771c1fe3c7a45d3f53916fc74a480698c4b5731f0bea61e52137c8"},
1050 | {file = "ruff-0.6.7.tar.gz", hash = "sha256:44e52129d82266fa59b587e2cd74def5637b730a69c4542525dfdecfaae38bd5"},
1051 | ]
1052 |
1053 | [[package]]
1054 | name = "scipy"
1055 | version = "1.14.1"
1056 | description = "Fundamental algorithms for scientific computing in Python"
1057 | optional = false
1058 | python-versions = ">=3.10"
1059 | files = [
1060 | {file = "scipy-1.14.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:b28d2ca4add7ac16ae8bb6632a3c86e4b9e4d52d3e34267f6e1b0c1f8d87e389"},
1061 | {file = "scipy-1.14.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d0d2821003174de06b69e58cef2316a6622b60ee613121199cb2852a873f8cf3"},
1062 | {file = "scipy-1.14.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8bddf15838ba768bb5f5083c1ea012d64c9a444e16192762bd858f1e126196d0"},
1063 | {file = "scipy-1.14.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:97c5dddd5932bd2a1a31c927ba5e1463a53b87ca96b5c9bdf5dfd6096e27efc3"},
1064 | {file = "scipy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ff0a7e01e422c15739ecd64432743cf7aae2b03f3084288f399affcefe5222d"},
1065 | {file = "scipy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e32dced201274bf96899e6491d9ba3e9a5f6b336708656466ad0522d8528f69"},
1066 | {file = "scipy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8426251ad1e4ad903a4514712d2fa8fdd5382c978010d1c6f5f37ef286a713ad"},
1067 | {file = "scipy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:a49f6ed96f83966f576b33a44257d869756df6cf1ef4934f59dd58b25e0327e5"},
1068 | {file = "scipy-1.14.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:2da0469a4ef0ecd3693761acbdc20f2fdeafb69e6819cc081308cc978153c675"},
1069 | {file = "scipy-1.14.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c0ee987efa6737242745f347835da2cc5bb9f1b42996a4d97d5c7ff7928cb6f2"},
1070 | {file = "scipy-1.14.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3a1b111fac6baec1c1d92f27e76511c9e7218f1695d61b59e05e0fe04dc59617"},
1071 | {file = "scipy-1.14.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8475230e55549ab3f207bff11ebfc91c805dc3463ef62eda3ccf593254524ce8"},
1072 | {file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:278266012eb69f4a720827bdd2dc54b2271c97d84255b2faaa8f161a158c3b37"},
1073 | {file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fef8c87f8abfb884dac04e97824b61299880c43f4ce675dd2cbeadd3c9b466d2"},
1074 | {file = "scipy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b05d43735bb2f07d689f56f7b474788a13ed8adc484a85aa65c0fd931cf9ccd2"},
1075 | {file = "scipy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:716e389b694c4bb564b4fc0c51bc84d381735e0d39d3f26ec1af2556ec6aad94"},
1076 | {file = "scipy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:631f07b3734d34aced009aaf6fedfd0eb3498a97e581c3b1e5f14a04164a456d"},
1077 | {file = "scipy-1.14.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:af29a935803cc707ab2ed7791c44288a682f9c8107bc00f0eccc4f92c08d6e07"},
1078 | {file = "scipy-1.14.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2843f2d527d9eebec9a43e6b406fb7266f3af25a751aa91d62ff416f54170bc5"},
1079 | {file = "scipy-1.14.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:eb58ca0abd96911932f688528977858681a59d61a7ce908ffd355957f7025cfc"},
1080 | {file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac8812c1d2aab7131a79ba62933a2a76f582d5dbbc695192453dae67ad6310"},
1081 | {file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066"},
1082 | {file = "scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1"},
1083 | {file = "scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f"},
1084 | {file = "scipy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1729560c906963fc8389f6aac023739ff3983e727b1a4d87696b7bf108316a79"},
1085 | {file = "scipy-1.14.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:4079b90df244709e675cdc8b93bfd8a395d59af40b72e339c2287c91860deb8e"},
1086 | {file = "scipy-1.14.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e0cf28db0f24a38b2a0ca33a85a54852586e43cf6fd876365c86e0657cfe7d73"},
1087 | {file = "scipy-1.14.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0c2f95de3b04e26f5f3ad5bb05e74ba7f68b837133a4492414b3afd79dfe540e"},
1088 | {file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b99722ea48b7ea25e8e015e8341ae74624f72e5f21fc2abd45f3a93266de4c5d"},
1089 | {file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5149e3fd2d686e42144a093b206aef01932a0059c2a33ddfa67f5f035bdfe13e"},
1090 | {file = "scipy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4f5a7c49323533f9103d4dacf4e4f07078f360743dec7f7596949149efeec06"},
1091 | {file = "scipy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84"},
1092 | {file = "scipy-1.14.1.tar.gz", hash = "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417"},
1093 | ]
1094 |
1095 | [package.dependencies]
1096 | numpy = ">=1.23.5,<2.3"
1097 |
1098 | [package.extras]
1099 | dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"]
1100 | doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.13.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<=7.3.7)", "sphinx-design (>=0.4.0)"]
1101 | test = ["Cython", "array-api-strict (>=2.0)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
1102 |
1103 | [[package]]
1104 | name = "shellingham"
1105 | version = "1.5.4"
1106 | description = "Tool to Detect Surrounding Shell"
1107 | optional = false
1108 | python-versions = ">=3.7"
1109 | files = [
1110 | {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"},
1111 | {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
1112 | ]
1113 |
1114 | [[package]]
1115 | name = "six"
1116 | version = "1.16.0"
1117 | description = "Python 2 and 3 compatibility utilities"
1118 | optional = false
1119 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
1120 | files = [
1121 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
1122 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
1123 | ]
1124 |
1125 | [[package]]
1126 | name = "tomli"
1127 | version = "2.0.1"
1128 | description = "A lil' TOML parser"
1129 | optional = false
1130 | python-versions = ">=3.7"
1131 | files = [
1132 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
1133 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
1134 | ]
1135 |
1136 | [[package]]
1137 | name = "tomlkit"
1138 | version = "0.13.2"
1139 | description = "Style preserving TOML library"
1140 | optional = false
1141 | python-versions = ">=3.8"
1142 | files = [
1143 | {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"},
1144 | {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"},
1145 | ]
1146 |
1147 | [[package]]
1148 | name = "typer"
1149 | version = "0.12.5"
1150 | description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
1151 | optional = false
1152 | python-versions = ">=3.7"
1153 | files = [
1154 | {file = "typer-0.12.5-py3-none-any.whl", hash = "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b"},
1155 | {file = "typer-0.12.5.tar.gz", hash = "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722"},
1156 | ]
1157 |
1158 | [package.dependencies]
1159 | click = ">=8.0.0"
1160 | rich = ">=10.11.0"
1161 | shellingham = ">=1.3.0"
1162 | typing-extensions = ">=3.7.4.3"
1163 |
1164 | [[package]]
1165 | name = "typing-extensions"
1166 | version = "4.12.2"
1167 | description = "Backported and Experimental Type Hints for Python 3.8+"
1168 | optional = false
1169 | python-versions = ">=3.8"
1170 | files = [
1171 | {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
1172 | {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
1173 | ]
1174 |
1175 | [metadata]
1176 | lock-version = "2.0"
1177 | python-versions = "^3.10"
1178 | content-hash = "45d7a96f277099d998cc6e0a77c39e0c23608c4d5bed9077c5fe4b2180359b4d"
1179 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "oxymouse"
3 | version = "1.1.1"
4 | description = "Oxymouse is a tool for generating synthetic mouse movements."
5 | authors = ["Tadas Gedgaudas "]
6 | readme = "README.md"
7 | packages = [{ include = "oxymouse" }]
8 |
9 | [project]
10 | name = "oxymouse"
11 | description = "Oxy®Mouse - algorithms for generating mouse movements!"
12 | readme = "README.md"
13 | requires-python = ">=3.10"
14 | license = "MIT"
15 | authors = [
16 | { name = "Tadas Gedgaudas", email = "tadas.gedgaudas@oxylabs.io" },
17 | ]
18 | dynamic = ["version"]
19 |
20 | [project.urls]
21 | Homepage = "https://oxylabs.io"
22 | Documentation = "https://github.com/oxylabs/OxyMouse/blob/master/README.md"
23 | Repository = "https://github.com/oxylabs/OxyMouse"
24 |
25 | [tool.poetry.dependencies]
26 | python = "^3.10"
27 | pyhm = "~0.0.7"
28 | noise = "~1.2.2"
29 | matplotlib = "~3.9.2"
30 | typer = "^0.12.5"
31 |
32 | [tool.poetry.dev-dependencies]
33 | ruff = "~0.6.7"
34 | pylint = "~3.3.1"
35 | mypy = "~1.11.2"
36 |
37 | [tool.ruff.lint]
38 | select = [
39 | "E", "W", # pycodestyle
40 | "F", # Pyflakes
41 | "UP", # pyupgrade
42 | "SIM", # flake8-simplify
43 | "I", # isort
44 | ]
45 |
46 | [tool.ruff]
47 | line-length = 120
48 |
49 | [tool.mypy]
50 | ignore_missing_imports = true
51 | warn_unused_configs = true
52 | disallow_any_generics = true
53 | disallow_untyped_calls = true
54 | disallow_untyped_defs = true
55 | disallow_incomplete_defs = true
56 | check_untyped_defs = true
57 | disallow_untyped_decorators = true
58 | no_implicit_optional = true
59 | warn_redundant_casts = true
60 | warn_unused_ignores = true
61 | strict_equality = true
62 |
63 | [tool.pylint]
64 | [tool.pylint.'MASTER']
65 | extension-pkg-allow-list='pydantic'
66 |
67 | [tool.pylint.'MESSAGES CONTROL']
68 | disable=[
69 | "missing-docstring"
70 | ]
71 |
72 | [tool.pylint.'FORMAT']
73 | max-line-length = 120
74 |
75 | [tool.pylint.'SIMILARITIES']
76 | ignore-imports = 'yes'
77 | min-similarity-lines = 15
78 |
79 | [tool.pylint.'DESIGN']
80 | max-args=10
81 |
82 | [tool.hatch.version]
83 | path = "oxymouse/__init__.py"
84 |
85 | [build-system]
86 | requires = ["hatchling >= 1.7.0"]
87 | build-backend = "hatchling.build"
88 |
--------------------------------------------------------------------------------
/visualize.py:
--------------------------------------------------------------------------------
1 | import typer
2 | from matplotlib import pyplot as plt
3 |
4 | from oxymouse.config import mouses
5 |
6 | app = typer.Typer()
7 |
8 |
9 | function_names_to_function_map = {
10 | "gc": "generate_coordinates",
11 | "grc": "generate_random_coordinates",
12 | "gsc": "generate_scroll_coordinates",
13 | }
14 |
15 |
16 | @app.command()
17 | def visualize_mouse_movements(algorithm: str, fn: str) -> None:
18 | print(f"Visualizing {algorithm} with {fn} function")
19 |
20 | algorithm_instance = mouses[algorithm]
21 | function_name = function_names_to_function_map[fn]
22 |
23 | coordinates = getattr(algorithm_instance, function_name)()
24 |
25 | x_coordinates = [point[0] for point in coordinates]
26 | y_coordinates = [point[1] for point in coordinates]
27 |
28 | plt.figure(figsize=(16, 9)) # Set the figure size for 1080p
29 | plt.plot(x_coordinates, y_coordinates, marker="o", linestyle="-")
30 | plt.title(f"Simulated mouse movement path - {algorithm_instance} - {function_name}")
31 | plt.xlabel("X")
32 | plt.ylabel("Y")
33 | plt.grid(True)
34 | plt.show()
35 |
36 |
37 | if __name__ == "__main__":
38 | app()
39 |
--------------------------------------------------------------------------------