valetudo-map-parser 0.1.9b69__py3-none-any.whl → 0.1.9b70__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- valetudo_map_parser/config/drawable.py +43 -210
- valetudo_map_parser/hypfer_draw.py +1 -2
- valetudo_map_parser/hypfer_handler.py +19 -8
- {valetudo_map_parser-0.1.9b69.dist-info → valetudo_map_parser-0.1.9b70.dist-info}/METADATA +1 -1
- {valetudo_map_parser-0.1.9b69.dist-info → valetudo_map_parser-0.1.9b70.dist-info}/RECORD +8 -8
- {valetudo_map_parser-0.1.9b69.dist-info → valetudo_map_parser-0.1.9b70.dist-info}/LICENSE +0 -0
- {valetudo_map_parser-0.1.9b69.dist-info → valetudo_map_parser-0.1.9b70.dist-info}/NOTICE.txt +0 -0
- {valetudo_map_parser-0.1.9b69.dist-info → valetudo_map_parser-0.1.9b70.dist-info}/WHEEL +0 -0
@@ -12,8 +12,6 @@ from __future__ import annotations
|
|
12
12
|
|
13
13
|
import logging
|
14
14
|
import math
|
15
|
-
import asyncio
|
16
|
-
import inspect
|
17
15
|
|
18
16
|
import numpy as np
|
19
17
|
from PIL import ImageDraw, ImageFont
|
@@ -46,12 +44,8 @@ class Drawable:
|
|
46
44
|
width: int, height: int, background_color: Color
|
47
45
|
) -> NumpyArray:
|
48
46
|
"""Create the empty background image NumPy array.
|
49
|
-
Background color is specified as an RGBA tuple.
|
50
|
-
|
51
|
-
# Use np.empty + broadcast instead of np.full (avoids double initialization)
|
52
|
-
img_array = np.empty((height, width, 4), dtype=np.uint8)
|
53
|
-
img_array[:] = background_color # Broadcast color to all pixels efficiently
|
54
|
-
return img_array
|
47
|
+
Background color is specified as an RGBA tuple."""
|
48
|
+
return np.full((height, width, 4), background_color, dtype=np.uint8)
|
55
49
|
|
56
50
|
@staticmethod
|
57
51
|
async def from_json_to_image(
|
@@ -158,8 +152,6 @@ class Drawable:
|
|
158
152
|
It uses the rotation angle of the image to orient the flag.
|
159
153
|
Includes color blending for better visual integration.
|
160
154
|
"""
|
161
|
-
await asyncio.sleep(0) # Yield control
|
162
|
-
|
163
155
|
# Check if coordinates are within bounds
|
164
156
|
height, width = layer.shape[:2]
|
165
157
|
x, y = center
|
@@ -311,79 +303,6 @@ class Drawable:
|
|
311
303
|
|
312
304
|
return layer
|
313
305
|
|
314
|
-
@staticmethod
|
315
|
-
def draw_lines_batch(
|
316
|
-
layer: NumpyArray,
|
317
|
-
line_segments: list,
|
318
|
-
color: Color,
|
319
|
-
width: int = 3,
|
320
|
-
) -> NumpyArray:
|
321
|
-
"""
|
322
|
-
Draw multiple line segments with batch processing for better performance.
|
323
|
-
|
324
|
-
Args:
|
325
|
-
layer: The numpy array to draw on
|
326
|
-
line_segments: List of tuples [(x1, y1, x2, y2), ...]
|
327
|
-
color: Color to draw with
|
328
|
-
width: Width of the lines
|
329
|
-
"""
|
330
|
-
if not line_segments:
|
331
|
-
return layer
|
332
|
-
|
333
|
-
# Pre-calculate blended color once for the entire batch
|
334
|
-
# Use the first line segment for color sampling
|
335
|
-
x1, y1, x2, y2 = line_segments[0]
|
336
|
-
blended_color = get_blended_color(x1, y1, x2, y2, layer, color)
|
337
|
-
|
338
|
-
# Fast path for fully opaque colors - skip individual blending
|
339
|
-
if color[3] == 255:
|
340
|
-
blended_color = color
|
341
|
-
|
342
|
-
# Process all line segments with the same blended color
|
343
|
-
for x1, y1, x2, y2 in line_segments:
|
344
|
-
# Ensure coordinates are integers
|
345
|
-
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
|
346
|
-
|
347
|
-
# Calculate line length
|
348
|
-
length = max(abs(x2 - x1), abs(y2 - y1))
|
349
|
-
if length == 0: # Handle case of a single point
|
350
|
-
# Draw a dot with the specified width
|
351
|
-
for i in range(-width // 2, (width + 1) // 2):
|
352
|
-
for j in range(-width // 2, (width + 1) // 2):
|
353
|
-
if (
|
354
|
-
0 <= x1 + i < layer.shape[1]
|
355
|
-
and 0 <= y1 + j < layer.shape[0]
|
356
|
-
):
|
357
|
-
layer[y1 + j, x1 + i] = blended_color
|
358
|
-
continue
|
359
|
-
|
360
|
-
# Create parametric points along the line
|
361
|
-
t = np.linspace(0, 1, length + 1) # Reduced from length * 2 to length + 1
|
362
|
-
x_coords = np.round(x1 * (1 - t) + x2 * t).astype(int)
|
363
|
-
y_coords = np.round(y1 * (1 - t) + y2 * t).astype(int)
|
364
|
-
|
365
|
-
# Draw the line with the specified width
|
366
|
-
if width == 1:
|
367
|
-
# Fast path for width=1
|
368
|
-
for x, y in zip(x_coords, y_coords):
|
369
|
-
if 0 <= x < layer.shape[1] and 0 <= y < layer.shape[0]:
|
370
|
-
layer[y, x] = blended_color
|
371
|
-
else:
|
372
|
-
# For thicker lines, draw a rectangle at each point
|
373
|
-
half_width = width // 2
|
374
|
-
for x, y in zip(x_coords, y_coords):
|
375
|
-
for i in range(-half_width, half_width + 1):
|
376
|
-
for j in range(-half_width, half_width + 1):
|
377
|
-
if (
|
378
|
-
i * i + j * j
|
379
|
-
<= half_width * half_width # Make it round
|
380
|
-
and 0 <= x + i < layer.shape[1]
|
381
|
-
and 0 <= y + j < layer.shape[0]
|
382
|
-
):
|
383
|
-
layer[y + j, x + i] = blended_color
|
384
|
-
|
385
|
-
return layer
|
386
|
-
|
387
306
|
@staticmethod
|
388
307
|
async def draw_virtual_walls(
|
389
308
|
layer: NumpyArray, virtual_walls, color: Color
|
@@ -402,15 +321,8 @@ class Drawable:
|
|
402
321
|
async def lines(arr: NumpyArray, coords, width: int, color: Color) -> NumpyArray:
|
403
322
|
"""
|
404
323
|
Join the coordinates creating a continuous line (path).
|
405
|
-
Optimized with
|
324
|
+
Optimized with vectorized operations for better performance.
|
406
325
|
"""
|
407
|
-
|
408
|
-
# Handle case where arr might be a coroutine (shouldn't happen but let's be safe)
|
409
|
-
if inspect.iscoroutine(arr):
|
410
|
-
arr = await arr
|
411
|
-
|
412
|
-
# Collect all line segments for batch processing
|
413
|
-
line_segments = []
|
414
326
|
for coord in coords:
|
415
327
|
x0, y0 = coord[0]
|
416
328
|
try:
|
@@ -422,16 +334,11 @@ class Drawable:
|
|
422
334
|
if x0 == x1 and y0 == y1:
|
423
335
|
continue
|
424
336
|
|
425
|
-
|
337
|
+
# Get blended color for this line segment
|
338
|
+
blended_color = get_blended_color(x0, y0, x1, y1, arr, color)
|
426
339
|
|
427
|
-
|
428
|
-
|
429
|
-
for i in range(0, len(line_segments), batch_size):
|
430
|
-
batch = line_segments[i : i + batch_size]
|
431
|
-
arr = Drawable.draw_lines_batch(arr, batch, color, width)
|
432
|
-
|
433
|
-
# Yield control between batches to prevent blocking
|
434
|
-
await asyncio.sleep(0)
|
340
|
+
# Use the optimized line drawing method
|
341
|
+
arr = Drawable._line(arr, x0, y0, x1, y1, blended_color, width)
|
435
342
|
|
436
343
|
return arr
|
437
344
|
|
@@ -577,130 +484,56 @@ class Drawable:
|
|
577
484
|
async def zones(layers: NumpyArray, coordinates, color: Color) -> NumpyArray:
|
578
485
|
"""
|
579
486
|
Draw the zones on the input layer with color blending.
|
580
|
-
Optimized with
|
487
|
+
Optimized with NumPy vectorized operations for better performance.
|
581
488
|
"""
|
582
|
-
await asyncio.sleep(0) # Yield control
|
583
|
-
|
584
489
|
dot_radius = 1 # Number of pixels for the dot
|
585
490
|
dot_spacing = 4 # Space between dots
|
586
491
|
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
Drawable._process_single_zone(
|
594
|
-
layers.copy(), zone, color, dot_radius, dot_spacing
|
595
|
-
)
|
596
|
-
)
|
597
|
-
|
598
|
-
# Execute all zone processing tasks in parallel
|
599
|
-
zone_results = await asyncio.gather(*zone_tasks, return_exceptions=True)
|
600
|
-
|
601
|
-
# Merge results back into the main layer
|
602
|
-
for result in zone_results:
|
603
|
-
if not isinstance(result, Exception):
|
604
|
-
# Simple overlay - pixels that are different from original get updated
|
605
|
-
mask = result != layers
|
606
|
-
layers[mask] = result[mask]
|
607
|
-
else:
|
608
|
-
# Single zone - process directly
|
609
|
-
for zone in coordinates:
|
610
|
-
points = zone["points"]
|
611
|
-
min_x = max(0, min(points[::2]))
|
612
|
-
max_x = min(layers.shape[1] - 1, max(points[::2]))
|
613
|
-
min_y = max(0, min(points[1::2]))
|
614
|
-
max_y = min(layers.shape[0] - 1, max(points[1::2]))
|
615
|
-
|
616
|
-
# Skip if zone is outside the image
|
617
|
-
if min_x >= max_x or min_y >= max_y:
|
618
|
-
continue
|
619
|
-
|
620
|
-
# Sample a point from the zone to get the background color
|
621
|
-
# Use the center of the zone for sampling
|
622
|
-
sample_x = (min_x + max_x) // 2
|
623
|
-
sample_y = (min_y + max_y) // 2
|
624
|
-
|
625
|
-
# Blend the color with the background color at the sample point
|
626
|
-
if 0 <= sample_y < layers.shape[0] and 0 <= sample_x < layers.shape[1]:
|
627
|
-
blended_color = ColorsManagement.sample_and_blend_color(
|
628
|
-
layers, sample_x, sample_y, color
|
629
|
-
)
|
630
|
-
else:
|
631
|
-
blended_color = color
|
632
|
-
|
633
|
-
# Create a grid of dot centers
|
634
|
-
x_centers = np.arange(min_x, max_x, dot_spacing)
|
635
|
-
y_centers = np.arange(min_y, max_y, dot_spacing)
|
636
|
-
|
637
|
-
# Draw dots at each grid point
|
638
|
-
for y in y_centers:
|
639
|
-
for x in x_centers:
|
640
|
-
# Create a small mask for the dot
|
641
|
-
y_min = max(0, y - dot_radius)
|
642
|
-
y_max = min(layers.shape[0], y + dot_radius + 1)
|
643
|
-
x_min = max(0, x - dot_radius)
|
644
|
-
x_max = min(layers.shape[1], x + dot_radius + 1)
|
645
|
-
|
646
|
-
# Create coordinate arrays for the dot
|
647
|
-
y_indices, x_indices = np.ogrid[y_min:y_max, x_min:x_max]
|
648
|
-
|
649
|
-
# Create a circular mask
|
650
|
-
mask = (y_indices - y) ** 2 + (
|
651
|
-
x_indices - x
|
652
|
-
) ** 2 <= dot_radius**2
|
653
|
-
|
654
|
-
# Apply the color to the masked region
|
655
|
-
layers[y_min:y_max, x_min:x_max][mask] = blended_color
|
492
|
+
for zone in coordinates:
|
493
|
+
points = zone["points"]
|
494
|
+
min_x = max(0, min(points[::2]))
|
495
|
+
max_x = min(layers.shape[1] - 1, max(points[::2]))
|
496
|
+
min_y = max(0, min(points[1::2]))
|
497
|
+
max_y = min(layers.shape[0] - 1, max(points[1::2]))
|
656
498
|
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
async def _process_single_zone(
|
661
|
-
layers: NumpyArray, zone, color: Color, dot_radius: int, dot_spacing: int
|
662
|
-
) -> NumpyArray:
|
663
|
-
"""Process a single zone for parallel execution."""
|
664
|
-
await asyncio.sleep(0) # Yield control
|
665
|
-
|
666
|
-
points = zone["points"]
|
667
|
-
min_x = max(0, min(points[::2]))
|
668
|
-
max_x = min(layers.shape[1] - 1, max(points[::2]))
|
669
|
-
min_y = max(0, min(points[1::2]))
|
670
|
-
max_y = min(layers.shape[0] - 1, max(points[1::2]))
|
499
|
+
# Skip if zone is outside the image
|
500
|
+
if min_x >= max_x or min_y >= max_y:
|
501
|
+
continue
|
671
502
|
|
672
|
-
|
673
|
-
|
674
|
-
|
503
|
+
# Sample a point from the zone to get the background color
|
504
|
+
# Use the center of the zone for sampling
|
505
|
+
sample_x = (min_x + max_x) // 2
|
506
|
+
sample_y = (min_y + max_y) // 2
|
675
507
|
|
676
|
-
|
677
|
-
|
678
|
-
|
508
|
+
# Blend the color with the background color at the sample point
|
509
|
+
if 0 <= sample_y < layers.shape[0] and 0 <= sample_x < layers.shape[1]:
|
510
|
+
blended_color = ColorsManagement.sample_and_blend_color(
|
511
|
+
layers, sample_x, sample_y, color
|
512
|
+
)
|
513
|
+
else:
|
514
|
+
blended_color = color
|
679
515
|
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
layers, sample_x, sample_y, color
|
684
|
-
)
|
685
|
-
else:
|
686
|
-
blended_color = color
|
516
|
+
# Create a grid of dot centers
|
517
|
+
x_centers = np.arange(min_x, max_x, dot_spacing)
|
518
|
+
y_centers = np.arange(min_y, max_y, dot_spacing)
|
687
519
|
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
# Draw a small filled circle (dot) using vectorized operations
|
520
|
+
# Draw dots at each grid point
|
521
|
+
for y in y_centers:
|
522
|
+
for x in x_centers:
|
523
|
+
# Create a small mask for the dot
|
693
524
|
y_min = max(0, y - dot_radius)
|
694
525
|
y_max = min(layers.shape[0], y + dot_radius + 1)
|
695
526
|
x_min = max(0, x - dot_radius)
|
696
527
|
x_max = min(layers.shape[1], x + dot_radius + 1)
|
697
528
|
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
529
|
+
# Create coordinate arrays for the dot
|
530
|
+
y_indices, x_indices = np.ogrid[y_min:y_max, x_min:x_max]
|
531
|
+
|
532
|
+
# Create a circular mask
|
533
|
+
mask = (y_indices - y) ** 2 + (x_indices - x) ** 2 <= dot_radius**2
|
534
|
+
|
535
|
+
# Apply the color to the masked region
|
536
|
+
layers[y_min:y_max, x_min:x_max][mask] = blended_color
|
704
537
|
|
705
538
|
return layers
|
706
539
|
|
@@ -1,12 +1,11 @@
|
|
1
1
|
"""
|
2
2
|
Image Draw Class for Valetudo Hypfer Image Handling.
|
3
3
|
This class is used to simplify the ImageHandler class.
|
4
|
-
Version:
|
4
|
+
Version: 0.1.9
|
5
5
|
"""
|
6
6
|
|
7
7
|
from __future__ import annotations
|
8
8
|
|
9
|
-
import asyncio
|
10
9
|
import logging
|
11
10
|
|
12
11
|
from .config.drawable_elements import DrawableElement
|
@@ -8,6 +8,7 @@ Version: 0.1.9
|
|
8
8
|
from __future__ import annotations
|
9
9
|
|
10
10
|
import asyncio
|
11
|
+
import numpy as np
|
11
12
|
|
12
13
|
from PIL import Image
|
13
14
|
|
@@ -58,6 +59,7 @@ class HypferMapImageHandler(BaseHandler, AutoCrop):
|
|
58
59
|
self.go_to = None # vacuum go to data
|
59
60
|
self.img_hash = None # hash of the image calculated to check differences.
|
60
61
|
self.img_base_layer = None # numpy array store the map base layer.
|
62
|
+
self.img_work_layer = None # persistent working buffer to avoid per-frame allocations
|
61
63
|
self.active_zones = None # vacuum active zones.
|
62
64
|
self.svg_wait = False # SVG image creation wait.
|
63
65
|
self.imd = ImDraw(self) # Image Draw class.
|
@@ -210,14 +212,12 @@ class HypferMapImageHandler(BaseHandler, AutoCrop):
|
|
210
212
|
) % 16 # Increment room_id even if we skip
|
211
213
|
continue
|
212
214
|
|
213
|
-
#
|
215
|
+
# Draw the layer ONLY if enabled
|
214
216
|
is_wall_layer = layer_type == "wall"
|
215
217
|
if is_wall_layer:
|
216
|
-
if
|
217
|
-
|
218
|
-
|
219
|
-
pass
|
220
|
-
|
218
|
+
# Skip walls entirely if disabled
|
219
|
+
if not self.drawing_config.is_enabled(DrawableElement.WALL):
|
220
|
+
continue
|
221
221
|
# Draw the layer
|
222
222
|
(
|
223
223
|
room_id,
|
@@ -273,6 +273,8 @@ class HypferMapImageHandler(BaseHandler, AutoCrop):
|
|
273
273
|
LOGGER.info("%s: Completed base Layers", self.file_name)
|
274
274
|
# Copy the new array in base layer.
|
275
275
|
self.img_base_layer = await self.async_copy_array(img_np_array)
|
276
|
+
|
277
|
+
|
276
278
|
self.shared.frame_number = self.frame_number
|
277
279
|
self.frame_number += 1
|
278
280
|
if (self.frame_number >= self.max_frames) or (
|
@@ -285,8 +287,17 @@ class HypferMapImageHandler(BaseHandler, AutoCrop):
|
|
285
287
|
str(self.json_id),
|
286
288
|
str(self.frame_number),
|
287
289
|
)
|
288
|
-
#
|
289
|
-
|
290
|
+
# Ensure persistent working buffer exists and matches base (allocate only when needed)
|
291
|
+
if (
|
292
|
+
self.img_work_layer is None
|
293
|
+
or self.img_work_layer.shape != self.img_base_layer.shape
|
294
|
+
or self.img_work_layer.dtype != self.img_base_layer.dtype
|
295
|
+
):
|
296
|
+
self.img_work_layer = np.empty_like(self.img_base_layer)
|
297
|
+
|
298
|
+
# Copy the base layer into the persistent working buffer (no new allocation per frame)
|
299
|
+
np.copyto(self.img_work_layer, self.img_base_layer)
|
300
|
+
img_np_array = self.img_work_layer
|
290
301
|
|
291
302
|
# Prepare parallel data extraction tasks
|
292
303
|
data_tasks = []
|
@@ -4,7 +4,7 @@ valetudo_map_parser/config/async_utils.py,sha256=e1j9uTtg4dhPVWvB2_XgqaH4aeSjRAP
|
|
4
4
|
valetudo_map_parser/config/auto_crop.py,sha256=Aes7vfv4z8ihYvGaH5Nryj6Y9mHDerZLIeyvePjf9aQ,19259
|
5
5
|
valetudo_map_parser/config/color_utils.py,sha256=nXD6WeNmdFdoMxPDW-JFpjnxJSaZR1jX-ouNfrx6zvE,4502
|
6
6
|
valetudo_map_parser/config/colors.py,sha256=DG-oPQoN5gsnwDbEsuFr8a0hRCxmbFHObWa4_5pr-70,29910
|
7
|
-
valetudo_map_parser/config/drawable.py,sha256=
|
7
|
+
valetudo_map_parser/config/drawable.py,sha256=2MeVHXqZuVuJk3eerMJYGwo25rVetHx3xB_vxecEFOQ,34168
|
8
8
|
valetudo_map_parser/config/drawable_elements.py,sha256=o-5oiXmfqPwNQLzKIhkEcZD_A47rIU9E0CqKgWipxgc,11516
|
9
9
|
valetudo_map_parser/config/enhanced_drawable.py,sha256=QlGxlUMVgECUXPtFwIslyjubWxQuhIixsRymWV3lEvk,12586
|
10
10
|
valetudo_map_parser/config/optimized_element_map.py,sha256=52BCnkvVv9bre52LeVIfT8nhnEIpc0TuWTv1xcNu0Rk,15744
|
@@ -12,16 +12,16 @@ valetudo_map_parser/config/rand256_parser.py,sha256=LU3y7XvRRQxVen9iwom0dOaDnJJv
|
|
12
12
|
valetudo_map_parser/config/shared.py,sha256=98CgGDY0tbc5BSg2TIHbGcDFZZ2acgIYnoPjAwENmBU,12885
|
13
13
|
valetudo_map_parser/config/types.py,sha256=saL7pULKAdTRQ_ShR2arT8IV472e9MBC_SohTthlGp8,17567
|
14
14
|
valetudo_map_parser/config/utils.py,sha256=lRLvQbqCQ44knnIJr-UAlkEOO1d14mFCmHKDor989VE,35468
|
15
|
-
valetudo_map_parser/hypfer_draw.py,sha256=
|
16
|
-
valetudo_map_parser/hypfer_handler.py,sha256=
|
15
|
+
valetudo_map_parser/hypfer_draw.py,sha256=mMA0MLmV3Man47VUmj823xwyHprJJmb0nXxmutRNK58,28976
|
16
|
+
valetudo_map_parser/hypfer_handler.py,sha256=PRiT7X7U9nbN3uvjSl1HKyBKN38CrM9_Z2Y-RNB3nJ8,23968
|
17
17
|
valetudo_map_parser/hypfer_rooms_handler.py,sha256=NkpOA6Gdq-2D3lLAxvtNuuWMvPXHxeMY2TO5RZLSHlU,22652
|
18
18
|
valetudo_map_parser/map_data.py,sha256=Flq5t9QQQiD5ylObIniHhPP1VB7VhNoMcMeJrOey3Go,17433
|
19
19
|
valetudo_map_parser/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
20
|
valetudo_map_parser/rand256_handler.py,sha256=daaSQ5ktMUYMnYxJkjS75UdBchpXVZ58HIomwHBFivs,27651
|
21
21
|
valetudo_map_parser/reimg_draw.py,sha256=1q8LkNTPHEA9Tsapc_JnVw51kpPYNhaBU-KmHkefCQY,12507
|
22
22
|
valetudo_map_parser/rooms_handler.py,sha256=ovqQtAjauAqwUNPR0aX27P2zhheQmqfaFhDE3_AwYWk,17821
|
23
|
-
valetudo_map_parser-0.1.
|
24
|
-
valetudo_map_parser-0.1.
|
25
|
-
valetudo_map_parser-0.1.
|
26
|
-
valetudo_map_parser-0.1.
|
27
|
-
valetudo_map_parser-0.1.
|
23
|
+
valetudo_map_parser-0.1.9b70.dist-info/LICENSE,sha256=Lh-qBbuRV0-jiCIBhfV7NgdwFxQFOXH3BKOzK865hRs,10480
|
24
|
+
valetudo_map_parser-0.1.9b70.dist-info/METADATA,sha256=oadNkSUgJDO-yswCRC2dow27dI0ntUsKH10Z5OURuic,3353
|
25
|
+
valetudo_map_parser-0.1.9b70.dist-info/NOTICE.txt,sha256=5lTOuWiU9aiEnJ2go8sc7lTJ7ntMBx0g0GFnNrswCY4,2533
|
26
|
+
valetudo_map_parser-0.1.9b70.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
27
|
+
valetudo_map_parser-0.1.9b70.dist-info/RECORD,,
|
File without changes
|
{valetudo_map_parser-0.1.9b69.dist-info → valetudo_map_parser-0.1.9b70.dist-info}/NOTICE.txt
RENAMED
File without changes
|
File without changes
|