sonolus.py 0.10.5__py3-none-any.whl → 0.10.7__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.
Potentially problematic release.
This version of sonolus.py might be problematic. Click here for more details.
- sonolus/build/dev_server.py +12 -3
- sonolus/script/containers.py +255 -1
- sonolus/script/internal/builtin_impls.py +6 -0
- sonolus/script/vec.py +21 -0
- {sonolus_py-0.10.5.dist-info → sonolus_py-0.10.7.dist-info}/METADATA +1 -1
- {sonolus_py-0.10.5.dist-info → sonolus_py-0.10.7.dist-info}/RECORD +9 -9
- {sonolus_py-0.10.5.dist-info → sonolus_py-0.10.7.dist-info}/WHEEL +0 -0
- {sonolus_py-0.10.5.dist-info → sonolus_py-0.10.7.dist-info}/entry_points.txt +0 -0
- {sonolus_py-0.10.5.dist-info → sonolus_py-0.10.7.dist-info}/licenses/LICENSE +0 -0
sonolus/build/dev_server.py
CHANGED
|
@@ -205,8 +205,16 @@ def parse_dev_command(command_line: str) -> Command | None:
|
|
|
205
205
|
return HelpCommand()
|
|
206
206
|
elif args.cmd in {"quit", "q"}:
|
|
207
207
|
return ExitCommand()
|
|
208
|
+
else:
|
|
209
|
+
# Really, we should not reach here, since argparse would have errored out earlier
|
|
210
|
+
print("Unknown command.\n")
|
|
211
|
+
return None
|
|
212
|
+
except (argparse.ArgumentError, argparse.ArgumentTypeError) as e:
|
|
213
|
+
print(f"Error parsing command: {e}\n")
|
|
208
214
|
return None
|
|
209
|
-
except
|
|
215
|
+
except SystemExit:
|
|
216
|
+
# argparse throws this on some errors, and will print out help automatically
|
|
217
|
+
print()
|
|
210
218
|
return None
|
|
211
219
|
|
|
212
220
|
|
|
@@ -227,7 +235,7 @@ def command_input_thread(command_queue: queue.Queue, prompt_event: threading.Eve
|
|
|
227
235
|
if isinstance(cmd, ExitCommand):
|
|
228
236
|
break
|
|
229
237
|
else:
|
|
230
|
-
print(f"
|
|
238
|
+
print(f"Available commands:\n{HELP_TEXT}")
|
|
231
239
|
# Show prompt again
|
|
232
240
|
prompt_event.set()
|
|
233
241
|
else:
|
|
@@ -236,6 +244,7 @@ def command_input_thread(command_queue: queue.Queue, prompt_event: threading.Eve
|
|
|
236
244
|
break
|
|
237
245
|
except Exception as e:
|
|
238
246
|
print(f"Error reading command: {e}\n")
|
|
247
|
+
prompt_event.set()
|
|
239
248
|
|
|
240
249
|
|
|
241
250
|
def get_local_ips():
|
|
@@ -283,7 +292,7 @@ def run_server(
|
|
|
283
292
|
|
|
284
293
|
def log_message(self, fmt, *args):
|
|
285
294
|
sys.stdout.write("\r\033[K") # Clear line
|
|
286
|
-
sys.stdout.write(f"{self.address_string()}
|
|
295
|
+
sys.stdout.write(f"{self.address_string()} [{self.log_date_time_string()}] {fmt % args}\n")
|
|
287
296
|
if interactive:
|
|
288
297
|
sys.stdout.write("> ")
|
|
289
298
|
sys.stdout.flush()
|
sonolus/script/containers.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from typing import Any, Protocol, Self
|
|
4
5
|
|
|
6
|
+
from sonolus.script.archetype import AnyArchetype, EntityRef
|
|
5
7
|
from sonolus.script.array import Array
|
|
6
8
|
from sonolus.script.array_like import ArrayLike, get_positive_index
|
|
7
9
|
from sonolus.script.debug import error
|
|
@@ -643,3 +645,255 @@ class _ArrayMapEntryIterator[K, V, Capacity](Record, SonolusIterator):
|
|
|
643
645
|
self._index += 1
|
|
644
646
|
return Some(result)
|
|
645
647
|
return Nothing
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
class _LinkedListNodeRef[TKey, TValue](Protocol):
|
|
651
|
+
def get_value(self) -> TValue: ...
|
|
652
|
+
|
|
653
|
+
def get_next(self) -> Self: ...
|
|
654
|
+
|
|
655
|
+
def set_next(self, next_node: Self): ...
|
|
656
|
+
|
|
657
|
+
def set_prev(self, prev_node: Self):
|
|
658
|
+
# No-op for singly linked lists
|
|
659
|
+
return
|
|
660
|
+
|
|
661
|
+
def is_present(self) -> bool: ...
|
|
662
|
+
|
|
663
|
+
def set(self, other: Self): ...
|
|
664
|
+
|
|
665
|
+
def copy(self) -> Self: ...
|
|
666
|
+
|
|
667
|
+
def empty(self) -> Self: ...
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
def _merge_linked_list_nodes[TNode: _LinkedListNodeRef](
|
|
671
|
+
a: TNode,
|
|
672
|
+
b: TNode,
|
|
673
|
+
) -> TNode:
|
|
674
|
+
head = a.empty()
|
|
675
|
+
tail = a.empty()
|
|
676
|
+
left = a.copy()
|
|
677
|
+
right = b.copy()
|
|
678
|
+
|
|
679
|
+
while left.is_present() and right.is_present():
|
|
680
|
+
if left.get_value() <= right.get_value():
|
|
681
|
+
if not head.is_present():
|
|
682
|
+
head.set(left)
|
|
683
|
+
tail.set(left)
|
|
684
|
+
else:
|
|
685
|
+
tail.set_next(left)
|
|
686
|
+
tail.set(left)
|
|
687
|
+
left.set(left.get_next())
|
|
688
|
+
else:
|
|
689
|
+
if not head.is_present():
|
|
690
|
+
head.set(right)
|
|
691
|
+
tail.set(right)
|
|
692
|
+
else:
|
|
693
|
+
tail.set_next(right)
|
|
694
|
+
tail.set(right)
|
|
695
|
+
right.set(right.get_next())
|
|
696
|
+
|
|
697
|
+
while left.is_present():
|
|
698
|
+
if not head.is_present():
|
|
699
|
+
head.set(left)
|
|
700
|
+
tail.set(left)
|
|
701
|
+
else:
|
|
702
|
+
tail.set_next(left)
|
|
703
|
+
tail.set(left)
|
|
704
|
+
left.set(left.get_next())
|
|
705
|
+
|
|
706
|
+
while right.is_present():
|
|
707
|
+
if not head.is_present():
|
|
708
|
+
head.set(right)
|
|
709
|
+
tail.set(right)
|
|
710
|
+
else:
|
|
711
|
+
tail.set_next(right)
|
|
712
|
+
tail.set(right)
|
|
713
|
+
right.set(right.get_next())
|
|
714
|
+
|
|
715
|
+
if tail.is_present():
|
|
716
|
+
tail.set_next(a.empty())
|
|
717
|
+
|
|
718
|
+
return head
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
def _merge_sort_linked_list_nodes[TNode: _LinkedListNodeRef](
|
|
722
|
+
head: TNode,
|
|
723
|
+
) -> TNode:
|
|
724
|
+
# Calculate length
|
|
725
|
+
length = 0
|
|
726
|
+
node = head.copy()
|
|
727
|
+
while node.is_present():
|
|
728
|
+
length += 1
|
|
729
|
+
node.set(node.get_next())
|
|
730
|
+
|
|
731
|
+
# Trivial case
|
|
732
|
+
if length <= 1:
|
|
733
|
+
return head
|
|
734
|
+
|
|
735
|
+
# Bottom-up merge sort: start with sublists of size 1, then 2, 4, 8, etc.
|
|
736
|
+
size = 1
|
|
737
|
+
while size < length:
|
|
738
|
+
current = head.copy()
|
|
739
|
+
new_head = head.empty()
|
|
740
|
+
new_tail = head.empty()
|
|
741
|
+
|
|
742
|
+
# Process all pairs of sublists of the current size
|
|
743
|
+
while current.is_present():
|
|
744
|
+
# Extract the first sublist
|
|
745
|
+
left = current.copy()
|
|
746
|
+
prev = current.empty()
|
|
747
|
+
i = 0
|
|
748
|
+
while i < size and current.is_present():
|
|
749
|
+
prev.set(current)
|
|
750
|
+
current.set(current.get_next())
|
|
751
|
+
i += 1
|
|
752
|
+
if prev.is_present():
|
|
753
|
+
prev.set_next(prev.empty())
|
|
754
|
+
|
|
755
|
+
# We've made it to the end without a second sublist to merge, so just attach it to the end
|
|
756
|
+
if not current.is_present():
|
|
757
|
+
# Since size < length, we know a full iteration must have happened already, so new_tail is valid
|
|
758
|
+
new_tail.set_next(left)
|
|
759
|
+
break
|
|
760
|
+
|
|
761
|
+
# Extract the second sublist
|
|
762
|
+
right = current.copy()
|
|
763
|
+
prev = current.empty()
|
|
764
|
+
i = 0
|
|
765
|
+
while i < size and current.is_present():
|
|
766
|
+
prev.set(current)
|
|
767
|
+
current.set(current.get_next())
|
|
768
|
+
i += 1
|
|
769
|
+
if prev.is_present():
|
|
770
|
+
prev.set_next(prev.empty())
|
|
771
|
+
|
|
772
|
+
merged = _merge_linked_list_nodes(left, right)
|
|
773
|
+
|
|
774
|
+
# Append the merged result
|
|
775
|
+
if not new_head.is_present():
|
|
776
|
+
new_head.set(merged)
|
|
777
|
+
new_tail.set(merged)
|
|
778
|
+
else:
|
|
779
|
+
new_tail.set_next(merged)
|
|
780
|
+
|
|
781
|
+
# Move tail to the end of the merged section
|
|
782
|
+
while new_tail.get_next().is_present():
|
|
783
|
+
new_tail.set(new_tail.get_next())
|
|
784
|
+
|
|
785
|
+
# Update head for the next iteration
|
|
786
|
+
head.set(new_head)
|
|
787
|
+
size *= 2
|
|
788
|
+
|
|
789
|
+
return head
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
class _EntityNodeRef[Archetype, GetValue, GetNextRef, GetPrevRef](Record):
|
|
793
|
+
index: int
|
|
794
|
+
|
|
795
|
+
def get_value(self) -> Any:
|
|
796
|
+
return self.get_value_fn(self.archetype.at(self.index))
|
|
797
|
+
|
|
798
|
+
def get_next(self) -> _EntityNodeRef:
|
|
799
|
+
next_ref = self.get_next_ref_fn(self.archetype.at(self.index))
|
|
800
|
+
return self.with_index(next_ref.index)
|
|
801
|
+
|
|
802
|
+
def set_next(self, next_node: _EntityNodeRef):
|
|
803
|
+
entity = self.archetype.at(self.index)
|
|
804
|
+
next_ref = self.get_next_ref_fn(entity)
|
|
805
|
+
next_ref.index = next_node.index
|
|
806
|
+
|
|
807
|
+
def set_prev(self, prev_node: _EntityNodeRef):
|
|
808
|
+
if self.get_prev_ref_fn is not None:
|
|
809
|
+
entity = self.archetype.at(self.index)
|
|
810
|
+
prev_ref = self.get_prev_ref_fn(entity)
|
|
811
|
+
prev_ref.index = prev_node.index
|
|
812
|
+
|
|
813
|
+
def is_present(self) -> bool:
|
|
814
|
+
return self.index > 0
|
|
815
|
+
|
|
816
|
+
def set(self, other: _EntityNodeRef):
|
|
817
|
+
self.index = other.index
|
|
818
|
+
|
|
819
|
+
def copy(self) -> _EntityNodeRef:
|
|
820
|
+
return self.with_index(self.index)
|
|
821
|
+
|
|
822
|
+
def empty(self) -> _EntityNodeRef:
|
|
823
|
+
return self.with_index(0)
|
|
824
|
+
|
|
825
|
+
def with_index(self, index: int) -> _EntityNodeRef:
|
|
826
|
+
return _EntityNodeRef[
|
|
827
|
+
self.archetype,
|
|
828
|
+
self.get_value_fn,
|
|
829
|
+
self.get_next_ref_fn,
|
|
830
|
+
self.get_prev_ref_fn,
|
|
831
|
+
](index)
|
|
832
|
+
|
|
833
|
+
@property
|
|
834
|
+
def archetype(self):
|
|
835
|
+
return self.type_var_value(Archetype)
|
|
836
|
+
|
|
837
|
+
@property
|
|
838
|
+
def get_value_fn(self):
|
|
839
|
+
return self.type_var_value(GetValue)
|
|
840
|
+
|
|
841
|
+
@property
|
|
842
|
+
def get_next_ref_fn(self):
|
|
843
|
+
return self.type_var_value(GetNextRef)
|
|
844
|
+
|
|
845
|
+
@property
|
|
846
|
+
def get_prev_ref_fn(self):
|
|
847
|
+
return self.type_var_value(GetPrevRef)
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
def sort_linked_entities[T: AnyArchetype](
|
|
851
|
+
head_ref: EntityRef[T],
|
|
852
|
+
/,
|
|
853
|
+
*,
|
|
854
|
+
get_value: Callable[[T], Any],
|
|
855
|
+
get_next_ref: Callable[[T], EntityRef[T]],
|
|
856
|
+
get_prev_ref: Callable[[T], EntityRef[T]] | None = None,
|
|
857
|
+
) -> EntityRef[T]:
|
|
858
|
+
"""Sort a linked list of entities using merge sort.
|
|
859
|
+
|
|
860
|
+
If get_prev_ref is provided, the backward links will be updated as well.
|
|
861
|
+
|
|
862
|
+
Usage:
|
|
863
|
+
```python
|
|
864
|
+
class MyArchetype(PlayArchetype):
|
|
865
|
+
sort_key: int
|
|
866
|
+
next: EntityRef[MyArchetype]
|
|
867
|
+
|
|
868
|
+
def sort_my_archetype(head: EntityRef[MyArchetype]) -> EntityRef[MyArchetype]:
|
|
869
|
+
return sort_linked_entities(
|
|
870
|
+
head,
|
|
871
|
+
get_value=lambda e: e.sort_key,
|
|
872
|
+
get_next_ref=lambda e: e.next,
|
|
873
|
+
)
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
Args:
|
|
877
|
+
head_ref: A reference to the head of the linked list.
|
|
878
|
+
get_value: A function that takes an entity and returns the value to sort by.
|
|
879
|
+
get_next_ref: A function that takes an entity and returns a reference to the next entity.
|
|
880
|
+
get_prev_ref: An optional function that takes an entity and returns a reference to the previous entity.
|
|
881
|
+
|
|
882
|
+
Returns:
|
|
883
|
+
A reference to the head of the sorted linked list.
|
|
884
|
+
"""
|
|
885
|
+
archetype = head_ref.archetype()
|
|
886
|
+
|
|
887
|
+
sorted_head_index = _merge_sort_linked_list_nodes(
|
|
888
|
+
_EntityNodeRef[archetype, get_value, get_next_ref, get_prev_ref](head_ref.index)
|
|
889
|
+
).index
|
|
890
|
+
|
|
891
|
+
if get_prev_ref is not None:
|
|
892
|
+
current_ref = _EntityNodeRef[archetype, get_value, get_next_ref, get_prev_ref](sorted_head_index)
|
|
893
|
+
prev_ref = current_ref.empty()
|
|
894
|
+
while current_ref.is_present():
|
|
895
|
+
current_ref.set_prev(prev_ref)
|
|
896
|
+
prev_ref.set(current_ref)
|
|
897
|
+
current_ref.set(current_ref.get_next())
|
|
898
|
+
|
|
899
|
+
return EntityRef[archetype](sorted_head_index)
|
|
@@ -388,6 +388,11 @@ def _super(*args):
|
|
|
388
388
|
return super(*(arg._as_py_() if arg._is_py_() else arg for arg in args))
|
|
389
389
|
|
|
390
390
|
|
|
391
|
+
@meta_fn
|
|
392
|
+
def _type(value):
|
|
393
|
+
return type(value)
|
|
394
|
+
|
|
395
|
+
|
|
391
396
|
@meta_fn
|
|
392
397
|
def _assert_never(arg: Never, /):
|
|
393
398
|
error("Expected code to be unreachable")
|
|
@@ -416,6 +421,7 @@ BUILTIN_IMPLS = {
|
|
|
416
421
|
id(range): Range,
|
|
417
422
|
id(reversed): _reversed,
|
|
418
423
|
id(super): _super,
|
|
424
|
+
id(type): _type,
|
|
419
425
|
id(zip): _zip,
|
|
420
426
|
id(assert_never): _assert_never,
|
|
421
427
|
**MATH_BUILTIN_IMPLS, # Includes round
|
sonolus/script/vec.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from math import pi
|
|
4
|
+
|
|
3
5
|
from sonolus.script.array import Array
|
|
4
6
|
from sonolus.script.array_like import ArrayLike
|
|
5
7
|
from sonolus.script.debug import assert_true
|
|
@@ -285,3 +287,22 @@ def pnpoly(vertices: ArrayLike[Vec2] | tuple[Vec2, ...], test: Vec2) -> bool:
|
|
|
285
287
|
j = i
|
|
286
288
|
i += 1
|
|
287
289
|
return c
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def angle_diff(a: float, b: float, /) -> float:
|
|
293
|
+
"""Return the smallest absolute difference between two angles in radians.
|
|
294
|
+
|
|
295
|
+
The result is in the range [0, π].
|
|
296
|
+
"""
|
|
297
|
+
return abs((a - b + pi) % (2 * pi) - pi)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def signed_angle_diff(a: float, b: float, /) -> float:
|
|
301
|
+
"""Return the signed smallest difference between two angles in radians.
|
|
302
|
+
|
|
303
|
+
The result is in the range [-π, π). A positive result means a is counter-clockwise from b.
|
|
304
|
+
A negative result means a is clockwise from b.
|
|
305
|
+
|
|
306
|
+
If the two angles are exactly opposite, the result will be -π, but this should not be relied upon.
|
|
307
|
+
"""
|
|
308
|
+
return (a - b + pi) % (2 * pi) - pi
|
|
@@ -29,7 +29,7 @@ sonolus/build/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
29
29
|
sonolus/build/cli.py,sha256=t6oK0SGU6fkxXVbGu6OuRIHDKD6u4SqXAShdPtatZ-8,10060
|
|
30
30
|
sonolus/build/collection.py,sha256=6hniAzriPWBKUeGDkXabNXpbdHiHnqiK9shs6U1OExM,12748
|
|
31
31
|
sonolus/build/compile.py,sha256=KOmncDKmGfgzC_FWB_LTxAl0s9w4wnaDe-luACMlCVs,8397
|
|
32
|
-
sonolus/build/dev_server.py,sha256=
|
|
32
|
+
sonolus/build/dev_server.py,sha256=xe6C2_dpODk51inL02F3xFMjDueCSay7-XzkR56lapY,10560
|
|
33
33
|
sonolus/build/engine.py,sha256=jMymxbBXu-ekv71uU8TF2KbFaHs3yGjyJAztd1SoRDs,14808
|
|
34
34
|
sonolus/build/level.py,sha256=KLqUAtxIuIqrzeFURJA97rdqjA5pcvYSmwNZQhElaMQ,702
|
|
35
35
|
sonolus/build/node.py,sha256=gnX71RYDUOK_gYMpinQi-bLWO4csqcfiG5gFmhxzSec,1330
|
|
@@ -39,7 +39,7 @@ sonolus/script/archetype.py,sha256=ck_LR8z0ipVq3T9b735VwvQI2mxVUyjHylr4BFagXT8,4
|
|
|
39
39
|
sonolus/script/array.py,sha256=EbrNwl_WuJ0JjjkX0s_VJNXWqvYdm_ljTbyrDEMLGUY,13348
|
|
40
40
|
sonolus/script/array_like.py,sha256=E6S4TW2muXgcyVkhUASQVt7JSYUkpvdJPgHz6YiSHNo,14708
|
|
41
41
|
sonolus/script/bucket.py,sha256=yIod3DgX7Hv7RLe-4Cn81FcydvbkbdMt26FzpRj7oUI,7794
|
|
42
|
-
sonolus/script/containers.py,sha256=
|
|
42
|
+
sonolus/script/containers.py,sha256=SnLXflwlX47EMQmTWnSzm9NYCi-as8lWnKzgCIK0PmM,26940
|
|
43
43
|
sonolus/script/debug.py,sha256=yYg6EZt3NUOUeph1pu_5cA_2lxs8SZ91v76eOC1Sw-8,7747
|
|
44
44
|
sonolus/script/easing.py,sha256=2FUJI_nfp990P_armCcRqHm2329O985glJAhSC6tnxs,11379
|
|
45
45
|
sonolus/script/effect.py,sha256=SfJxSNF3RlPCRXnkt62ZlWhCXw3mmmRCsoMsvTErUP0,7960
|
|
@@ -67,9 +67,9 @@ sonolus/script/timing.py,sha256=DklMvuxcFg3MzXsecUo6Yhdk7pScOJ7STwXvAiTvLKM,3067
|
|
|
67
67
|
sonolus/script/transform.py,sha256=4aS7-NNzX0v9KMXZ4gIGOaU1Cd-ok7DO_OvIBca0mGU,21418
|
|
68
68
|
sonolus/script/ui.py,sha256=DYPGWIjHj1IFPxW1zaEuIUQx0b32FJPXtiwCvrtJ6oo,7528
|
|
69
69
|
sonolus/script/values.py,sha256=6iJG6h4IDlbcK8FH4GENSHOQc7C_7fCGa34wM80qToA,1629
|
|
70
|
-
sonolus/script/vec.py,sha256=
|
|
70
|
+
sonolus/script/vec.py,sha256=LueAHrx5pKouHvLaO1nMbl5Plh3UgPn8J7UdJPHWFCM,8840
|
|
71
71
|
sonolus/script/internal/__init__.py,sha256=T6rzLoiOUaiSQtaHMZ88SNO-ijSjSSv33TKtUwu-Ms8,136
|
|
72
|
-
sonolus/script/internal/builtin_impls.py,sha256=
|
|
72
|
+
sonolus/script/internal/builtin_impls.py,sha256=b4gt54JyFoM9mhtxrhfCR8w2u38h4sJ3bzdOB0usNEs,13445
|
|
73
73
|
sonolus/script/internal/callbacks.py,sha256=vWzJG8uiJoEtsNnbeZPqOHogCwoLpz2D1MnHY2wVV8s,2801
|
|
74
74
|
sonolus/script/internal/constant.py,sha256=3ycbGkDJVUwcrCZ96vLjAoAARgsvaqDM8rJ_YCrLrvo,4289
|
|
75
75
|
sonolus/script/internal/context.py,sha256=56pPjiPy8ZaxY3t5iEufsOMEj6BSy31G-5SoYqS6tPo,19694
|
|
@@ -87,8 +87,8 @@ sonolus/script/internal/simulation_context.py,sha256=LGxLTvxbqBIhoe1R-SfwGajNIDw
|
|
|
87
87
|
sonolus/script/internal/transient.py,sha256=y2AWABqF1aoaP6H4_2u4MMpNioC4OsZQCtPyNI0txqo,1634
|
|
88
88
|
sonolus/script/internal/tuple_impl.py,sha256=DPNdmmRmupU8Ah4_XKq6-PdT336l4nt15_uCJKQGkkk,3587
|
|
89
89
|
sonolus/script/internal/value.py,sha256=OngrCdmY_h6mV2Zgwqhuo4eYFad0kTk6263UAxctZcY,6963
|
|
90
|
-
sonolus_py-0.10.
|
|
91
|
-
sonolus_py-0.10.
|
|
92
|
-
sonolus_py-0.10.
|
|
93
|
-
sonolus_py-0.10.
|
|
94
|
-
sonolus_py-0.10.
|
|
90
|
+
sonolus_py-0.10.7.dist-info/METADATA,sha256=sXdmgTuEdNIRF2McqWR7H1c_l-uolUuow8Nt3-ZhYpY,554
|
|
91
|
+
sonolus_py-0.10.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
92
|
+
sonolus_py-0.10.7.dist-info/entry_points.txt,sha256=oTYspY_b7SA8TptEMTDxh4-Aj-ZVPnYC9f1lqH6s9G4,54
|
|
93
|
+
sonolus_py-0.10.7.dist-info/licenses/LICENSE,sha256=JEKpqVhQYfEc7zg3Mj462sKbKYmO1K7WmvX1qvg9IJk,1067
|
|
94
|
+
sonolus_py-0.10.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|