yapCAD 0.3.0__py2.py3-none-any.whl → 0.3.1__py2.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.
- yapcad/combine.py +82 -376
- yapcad/drawable.py +44 -3
- yapcad/ezdxf_drawable.py +1 -1
- yapcad/geom.py +204 -264
- yapcad/geom3d.py +975 -55
- yapcad/geom3d_util.py +541 -0
- yapcad/geom_util.py +817 -0
- yapcad/geometry.py +441 -49
- yapcad/geometry_checks.py +112 -0
- yapcad/geometry_utils.py +115 -0
- yapcad/io/__init__.py +5 -0
- yapcad/io/stl.py +83 -0
- yapcad/mesh.py +46 -0
- yapcad/metadata.py +109 -0
- yapcad/octtree.py +627 -0
- yapcad/poly.py +153 -299
- yapcad/pyglet_drawable.py +597 -61
- yapcad/triangulator.py +103 -0
- yapcad/xform.py +0 -1
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/METADATA +92 -38
- yapcad-0.3.1.dist-info/RECORD +27 -0
- yapcad-0.3.0.dist-info/RECORD +0 -17
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/WHEEL +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/licenses/LICENSE.txt +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/top_level.txt +0 -0
yapcad/triangulator.py
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
"""Triangulation helpers for yapCAD surfaces.
|
2
|
+
|
3
|
+
We delegate to ``mapbox-earcut`` (the fast ear clipping implementation
|
4
|
+
used by Mapbox GL) to keep the logic compact and reliable. The helper
|
5
|
+
routine in this file simply normalises yapCAD polygon inputs into the
|
6
|
+
format expected by earcut and converts the resulting indices back into
|
7
|
+
triangle vertex tuples.
|
8
|
+
"""
|
9
|
+
|
10
|
+
from __future__ import annotations
|
11
|
+
|
12
|
+
from typing import Iterable, List, Sequence, Tuple
|
13
|
+
|
14
|
+
import numpy as np
|
15
|
+
|
16
|
+
try:
|
17
|
+
import mapbox_earcut as _earcut
|
18
|
+
except ImportError as exc: # pragma: no cover - import guard
|
19
|
+
raise ImportError(
|
20
|
+
"mapbox-earcut must be installed to triangulate polygons with holes"
|
21
|
+
) from exc
|
22
|
+
|
23
|
+
from yapcad.geom import epsilon
|
24
|
+
|
25
|
+
Point2D = Tuple[float, float]
|
26
|
+
|
27
|
+
|
28
|
+
def triangulate_polygon(outer: Sequence[Sequence[float]],
|
29
|
+
holes: Iterable[Sequence[Sequence[float]]] | None = None
|
30
|
+
) -> List[List[Point2D]]:
|
31
|
+
"""Return triangles covering ``outer`` minus any ``holes``.
|
32
|
+
|
33
|
+
``outer`` and each entry in ``holes`` is expected to be a sequence of
|
34
|
+
XY-like points. Degenerate loops (fewer than three distinct points)
|
35
|
+
are ignored. The returned triangles are lists of three ``(x, y)``
|
36
|
+
pairs. Downstream code is responsible for lifting the coordinates
|
37
|
+
into 3D and enforcing winding to match the target surface normal.
|
38
|
+
"""
|
39
|
+
|
40
|
+
if holes is None:
|
41
|
+
holes = []
|
42
|
+
|
43
|
+
outer_loop = _prepare_loop(outer, want_ccw=True)
|
44
|
+
if len(outer_loop) < 3:
|
45
|
+
return []
|
46
|
+
|
47
|
+
point_map: List[Point2D] = []
|
48
|
+
|
49
|
+
ring_ends: List[int] = []
|
50
|
+
|
51
|
+
def _append(loop: Sequence[Point2D]) -> None:
|
52
|
+
for x, y in loop:
|
53
|
+
point_map.append((x, y))
|
54
|
+
ring_ends.append(len(point_map))
|
55
|
+
|
56
|
+
_append(outer_loop)
|
57
|
+
|
58
|
+
for hole in holes:
|
59
|
+
loop = _prepare_loop(hole, want_ccw=False)
|
60
|
+
if len(loop) < 3:
|
61
|
+
continue
|
62
|
+
_append(loop)
|
63
|
+
|
64
|
+
vertices = np.asarray(point_map, dtype=np.float32)
|
65
|
+
ring_array = np.asarray(ring_ends, dtype=np.uint32)
|
66
|
+
indices = _earcut.triangulate_float32(vertices, ring_array)
|
67
|
+
triangles: List[List[Point2D]] = []
|
68
|
+
for i in range(0, len(indices), 3):
|
69
|
+
triangles.append([point_map[indices[i]],
|
70
|
+
point_map[indices[i + 1]],
|
71
|
+
point_map[indices[i + 2]]])
|
72
|
+
return triangles
|
73
|
+
|
74
|
+
|
75
|
+
def _prepare_loop(points: Sequence[Sequence[float]], *, want_ccw: bool) -> List[Point2D]:
|
76
|
+
loop: List[Point2D] = []
|
77
|
+
for pt in points:
|
78
|
+
x, y = float(pt[0]), float(pt[1])
|
79
|
+
if loop and _near(loop[-1], (x, y)):
|
80
|
+
continue
|
81
|
+
loop.append((x, y))
|
82
|
+
if loop and _near(loop[0], loop[-1]):
|
83
|
+
loop.pop()
|
84
|
+
if len(loop) < 3:
|
85
|
+
return loop
|
86
|
+
area = _signed_area(loop)
|
87
|
+
if want_ccw and area < 0:
|
88
|
+
loop.reverse()
|
89
|
+
elif not want_ccw and area > 0:
|
90
|
+
loop.reverse()
|
91
|
+
return loop
|
92
|
+
|
93
|
+
|
94
|
+
def _near(p1: Point2D, p2: Point2D) -> bool:
|
95
|
+
return abs(p1[0] - p2[0]) <= epsilon and abs(p1[1] - p2[1]) <= epsilon
|
96
|
+
|
97
|
+
|
98
|
+
def _signed_area(loop: Sequence[Point2D]) -> float:
|
99
|
+
total = 0.0
|
100
|
+
for i, (x0, y0) in enumerate(loop):
|
101
|
+
x1, y1 = loop[(i + 1) % len(loop)]
|
102
|
+
total += x0 * y1 - x1 * y0
|
103
|
+
return total / 2.0
|
yapcad/xform.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: yapCAD
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.1
|
4
4
|
Summary: yet another procedural CAD and computational geometry system
|
5
5
|
Author-email: Richard DeVaul <richard.devaul@gmail.com>
|
6
6
|
Project-URL: Homepage, https://github.com/rdevaul/yapCAD/
|
@@ -28,12 +28,12 @@ Dynamic: license-file
|
|
28
28
|
==========
|
29
29
|
|
30
30
|
yet another procedural CAD and computational geometry system written in
|
31
|
-
python 3
|
31
|
+
python 3, now with a growing focus on 3D generative design and STL export
|
32
32
|
|
33
|
-
.. figure:: images/
|
34
|
-
:alt: **yapCAD**
|
33
|
+
.. figure:: images/RocketDemoScreenshot.png
|
34
|
+
:alt: **yapCAD** rocket example
|
35
35
|
|
36
|
-
**yapCAD**
|
36
|
+
**yapCAD** rocket example
|
37
37
|
|
38
38
|
what’s **yapCAD** for?
|
39
39
|
----------------------
|
@@ -42,8 +42,10 @@ First and foremost, **yapCAD** is a framework for creating
|
|
42
42
|
`parametric <https://en.wikipedia.org/wiki/Parametric_design>`__,
|
43
43
|
procedural, and
|
44
44
|
`generative <https://en.wikipedia.org/wiki/Parametric_design>`__ design
|
45
|
-
systems.
|
46
|
-
|
45
|
+
systems. Starting with the 0.5 release, the emphasis has shifted toward
|
46
|
+
3D solid workflows, including STL export for downstream slicing and
|
47
|
+
simulation, while retaining support for DXF generation and computational
|
48
|
+
geometry experiments.
|
47
49
|
|
48
50
|
software status
|
49
51
|
---------------
|
@@ -84,28 +86,23 @@ clone the github repository as shown above, and make sure that your
|
|
84
86
|
PYTHONPATH includes the cloned top-level ``yapCAD`` directory. You will
|
85
87
|
find the examples in the ``yapCAD/examples`` directory.
|
86
88
|
|
87
|
-
For a fully worked parametric design system, see the ``boxcut`` example.
|
89
|
+
For a fully worked 2D parametric design system, see the ``boxcut`` example.
|
90
|
+
For a 3D generative example that builds a multi-stage rocket, visualises
|
91
|
+
it, and exports STL, see ``examples/rocket_demo.py``.
|
88
92
|
|
89
93
|
documentation
|
90
94
|
~~~~~~~~~~~~~
|
91
95
|
|
92
96
|
Online **yapCAD** documentation can be found here:
|
93
|
-
https://yapcad.readthedocs.io/en/latest/ —
|
94
|
-
|
95
|
-
|
97
|
+
https://yapcad.readthedocs.io/en/latest/ — some module references lag
|
98
|
+
behind the latest 3D-focused APIs, so you may want to build a local copy
|
99
|
+
as described below to explore ``geometry_utils``, ``geometry_checks``,
|
100
|
+
``metadata``, and ``io.stl``.
|
96
101
|
|
97
|
-
To build the HTML **yapCAD** documentation locally,
|
98
|
-
|
99
|
-
|
100
|
-
::
|
101
|
-
|
102
|
-
pip install sphinx --user
|
103
|
-
|
104
|
-
Then clone the github repository as shown above, ``cd`` to the
|
105
|
-
``yapCAD`` directory, and type
|
106
|
-
|
107
|
-
::
|
102
|
+
To build the HTML **yapCAD** documentation locally, install the
|
103
|
+
documentation dependencies and run Sphinx from the project root::
|
108
104
|
|
105
|
+
python3 -m pip install -r docs/requirements.txt
|
109
106
|
make -C docs html
|
110
107
|
|
111
108
|
This will build the HTML documents in the ``build/sphinx/html``
|
@@ -117,29 +114,77 @@ information.
|
|
117
114
|
running tests
|
118
115
|
~~~~~~~~~~~~~
|
119
116
|
|
120
|
-
The repository includes a
|
121
|
-
geometry primitives
|
122
|
-
|
117
|
+
The repository includes a comprehensive pytest suite that exercises both core
|
118
|
+
geometry primitives and visual rendering capabilities. First, set up the
|
119
|
+
testing environment::
|
123
120
|
|
124
|
-
|
125
|
-
|
121
|
+
# Create and activate virtual environment
|
122
|
+
pyenv local 3.12 # or use python3.12 directly
|
123
|
+
python3 -m venv v_312
|
124
|
+
source v_312/bin/activate
|
126
125
|
|
127
|
-
|
128
|
-
|
129
|
-
|
126
|
+
# Install dependencies
|
127
|
+
pip install -r requirements.txt
|
128
|
+
pip install pytest pytest-cov
|
130
129
|
|
131
|
-
|
130
|
+
Non-Visual Tests (Automated/CI-friendly)
|
131
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
132
|
+
|
133
|
+
Run the core computational geometry tests (including triangle, metadata,
|
134
|
+
validation, and STL exporter checks) without interactive displays::
|
135
|
+
|
136
|
+
# Run all non-visual tests
|
137
|
+
PYTHONPATH=./src pytest tests/ -m "not visual"
|
138
|
+
|
139
|
+
# With coverage reporting (default)
|
140
|
+
PYTHONPATH=./src pytest tests/ -m "not visual" --cov=src
|
141
|
+
|
142
|
+
# Skip coverage for faster execution
|
143
|
+
PYTHONPATH=./src pytest tests/ -m "not visual" --override-ini addopts=
|
144
|
+
|
145
|
+
Visual Tests (Interactive)
|
146
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
147
|
+
|
148
|
+
yapCAD includes visual tests that create interactive 3D renderings to verify
|
149
|
+
geometry generation and display functionality (for example,
|
150
|
+
``tests/test_mesh_view.py::test_mesh_view_visual_normals``). These require a
|
151
|
+
display and user interaction::
|
152
|
+
|
153
|
+
# Run all visual tests (opens interactive windows)
|
154
|
+
./run_visual_tests_venv.sh
|
155
|
+
|
156
|
+
# Run specific visual tests by pattern
|
157
|
+
./run_visual_tests_venv.sh test_geom # Only test_geom* visual tests
|
158
|
+
./run_visual_tests_venv.sh surface # Tests matching "surface"
|
159
|
+
./run_visual_tests_venv.sh Face # Face-related tests
|
160
|
+
|
161
|
+
# Alternative: Manual pytest execution
|
162
|
+
VISUALTEST=true PYTHONPATH=./src pytest tests/ -m visual
|
163
|
+
|
164
|
+
# Or run individual visual tests
|
165
|
+
VISUALTEST=true PYTHONPATH=./src pytest tests/test_geom3d.py::TestSurface::test_surface -s
|
166
|
+
|
167
|
+
**Note:** Visual tests require closing each interactive window to proceed to the next test. Use the dedicated ``run_visual_tests_venv.sh`` script for the best experience, as it runs each test in an isolated subprocess to prevent early termination.
|
132
168
|
|
133
169
|
**yapCAD** goals
|
134
170
|
----------------
|
135
171
|
|
136
172
|
The purpose of **yapCAD** is to support 2D and 3D computational geometry
|
137
173
|
and parametric, procedural, and generative design projects in python3.
|
138
|
-
**yapCAD** is designed to support multiple rendering back-ends, such
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
174
|
+
**yapCAD** is designed to support multiple rendering back-ends, such that
|
175
|
+
only a small amount of code is necessary to add support for a CAD or
|
176
|
+
drawing file format. At present, **yapCAD** supports:
|
177
|
+
|
178
|
+
* AutoCAD DXF output for two-dimensional drawings (via
|
179
|
+
`ezdxf <https://github.com/mozman/ezdxf>`__).
|
180
|
+
* STL export for 3D solids (via the new ``yapcad.io.stl`` module).
|
181
|
+
* OpenGL visualisation for 2D/3D geometries using
|
182
|
+
`pyglet <https://github.com/pyglet/pyglet>`__.
|
183
|
+
|
184
|
+
The 0.5.0 release lays the shared foundations (triangle utilities,
|
185
|
+
metadata, validation checks, and STL export) that pave the way toward STEP
|
186
|
+
support and a packaged, provenance-aware project model targeted for the
|
187
|
+
forthcoming 1.0 release.
|
143
188
|
|
144
189
|
The foundations of **yapCAD** are grounded in decades of the author’s
|
145
190
|
experience with graphics system programming, 3D CAD and simulation.
|
@@ -158,8 +203,8 @@ package, and interactive OpenGL visualization using the amazing
|
|
158
203
|
|
159
204
|
(for a more complete list, see the `examples folder <./examples/>`__)
|
160
205
|
|
161
|
-
It’s pretty easy to make a DXF drawing with **yapCAD**. Here
|
162
|
-
example:
|
206
|
+
It’s pretty easy to make a DXF drawing or a 3D model with **yapCAD**. Here
|
207
|
+
is a DXF example:
|
163
208
|
|
164
209
|
::
|
165
210
|
|
@@ -194,6 +239,15 @@ example:
|
|
194
239
|
# write out the geometry as example1-out.dxf
|
195
240
|
dd.display()
|
196
241
|
|
242
|
+
For a 3D example that generates a complete rocket assembly and exports
|
243
|
+
STL::
|
244
|
+
|
245
|
+
from pathlib import Path
|
246
|
+
from examples.rocket_demo import build_rocket, export_stl
|
247
|
+
|
248
|
+
components, assembly = build_rocket()
|
249
|
+
export_stl(assembly, Path("rocket_demo.stl"))
|
250
|
+
|
197
251
|
The **yapCAD** system isn’t just about rendering, of course, it’s about
|
198
252
|
computational geometry. For example, if you want to calculate the
|
199
253
|
intersection of lines and arcs in a plane, we have you covered:
|
@@ -0,0 +1,27 @@
|
|
1
|
+
yapcad/__init__.py,sha256=CUEd7EOL-ne31ggDprsi4lwLWMV1SRV5KYqkuDTdxrQ,400
|
2
|
+
yapcad/combine.py,sha256=WhI3D9lSZFzu1HD68HGUTbNNrJsT4SeCl1MOcjxsa1k,2932
|
3
|
+
yapcad/drawable.py,sha256=kPYbIhOD5MesmRSeXTiFJoE1UwVQWekoeu19athfH7Y,15843
|
4
|
+
yapcad/ezdxf_drawable.py,sha256=o6Rei044ROkaniHZJwyBGtahaD3BU1927-AkFpPzqwE,5966
|
5
|
+
yapcad/geom.py,sha256=bg_ayg1aovT17HwgFwoJ7HbvI2InEjii9Bvr8PoZ04g,105604
|
6
|
+
yapcad/geom3d.py,sha256=c6MleS-AiCWdju_mtPzUd7vhzkoT5nlJvoz7yimwdwU,33415
|
7
|
+
yapcad/geom3d_util.py,sha256=O-LUVqk2-BmFb-g-2ex44vHwKK_U4xCfqMY5Cevbvi8,15663
|
8
|
+
yapcad/geom_util.py,sha256=GMfgCyXuv9J4mdOfkqxNZT7EZZFEMV_ZpVTfuol8ve8,26370
|
9
|
+
yapcad/geometry.py,sha256=FcIF94a_usw04C0RDJDRDCCi44eya7lyahlU1Vw9wXM,16145
|
10
|
+
yapcad/geometry_checks.py,sha256=ABI0t5kls2HAidyyPp_EdoVqPxJAEtCWysPKvCeSK3s,2975
|
11
|
+
yapcad/geometry_utils.py,sha256=N_073tEV08AKjJRTeuNJMPjPgonFPUeiuh_jY7Xx7mA,3438
|
12
|
+
yapcad/mesh.py,sha256=QmPMeqdToyLztPupY8vSHQfrUz3UEBH1p8Pa9XFVPCg,1329
|
13
|
+
yapcad/metadata.py,sha256=6foSa_4N9-PO4kL8YchbXboXZZFjEcUSG6F1spwGCVE,3096
|
14
|
+
yapcad/octtree.py,sha256=MxyNMgozeLUBK5cC5_IC_9fK4BqSg4VeoKP389AUVmM,19793
|
15
|
+
yapcad/poly.py,sha256=y5cSiCbA-pCbkO5zIa9kVk2_00w7FkWxY380nK14wt4,16549
|
16
|
+
yapcad/pyglet_drawable.py,sha256=etgul99FOywq3rXf9uNu6cd59cECe4OMYX_ht5BcyMw,38424
|
17
|
+
yapcad/triangulator.py,sha256=hwxoxb564wZRYPEYbGiD-SDPu_x_SueYha0Kjmnu3Bo,3210
|
18
|
+
yapcad/xform.py,sha256=Qy_KYqbTcmspmKZfo-OGU_1Z3XRpL7p5buwc5uAzlvo,9537
|
19
|
+
yapcad/io/__init__.py,sha256=EDwSGx-0na9fZabaK57zrq3GwEtkwN5Vo_pTS-ZtuXQ,85
|
20
|
+
yapcad/io/stl.py,sha256=HNICfPz_CXYIbTP7d4spdSkMdmrt3d825MNzYA9ah9w,2596
|
21
|
+
yapcad-0.3.1.dist-info/licenses/AUTHORS.rst,sha256=JzvJA3p1aSIOTaaB3aCtB-ZrUQrVm869gdROUV5bRh8,84
|
22
|
+
yapcad-0.3.1.dist-info/licenses/LICENSE,sha256=NkGvciCD5MEHmCtnivAi2PqcEhBYAkSAarP-bWAoknM,1071
|
23
|
+
yapcad-0.3.1.dist-info/licenses/LICENSE.txt,sha256=FyT_Hxn5USuJ1Mu3-4Ou4T2x-Dzfiy06ZOnWkfdJ33o,1081
|
24
|
+
yapcad-0.3.1.dist-info/METADATA,sha256=HBc4tviyXQPUCGdA3-nueViX7QVaBaNHM7YGbVEqOWU,21588
|
25
|
+
yapcad-0.3.1.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
26
|
+
yapcad-0.3.1.dist-info/top_level.txt,sha256=NAtnfsyeALrvhI63FGS3_TEUh26OKRvnm1_lCOOgjKA,7
|
27
|
+
yapcad-0.3.1.dist-info/RECORD,,
|
yapcad-0.3.0.dist-info/RECORD
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
yapcad/__init__.py,sha256=CUEd7EOL-ne31ggDprsi4lwLWMV1SRV5KYqkuDTdxrQ,400
|
2
|
-
yapcad/combine.py,sha256=uC8QsFRGa198rIkKhNIOm-GhuDvezlGcX3nhEY2N2YE,13993
|
3
|
-
yapcad/drawable.py,sha256=RKG8emMC0E6__-L89zrBVxAB1JiFUPA51cAweCu7zP8,14605
|
4
|
-
yapcad/ezdxf_drawable.py,sha256=pZGLS9Dw108GG6ItahszSkkRopYLtgP9CDVWxHCrMrs,5948
|
5
|
-
yapcad/geom.py,sha256=YSqG-C7Ti9VCkSyIC3VggJImx_tAlyxtN38SNUdGM5Q,108843
|
6
|
-
yapcad/geom3d.py,sha256=W6gmo8UifgFwy3HHQvgvvgp96l2ahMqTVyTmbXqNEd8,2865
|
7
|
-
yapcad/geometry.py,sha256=H-ahJG2nsXvV__6TqWf_ReRWVFZdL4bBPPPTYEnPvi0,2564
|
8
|
-
yapcad/poly.py,sha256=Fku0ynBzYUSb5UZA6WY0yLPmDTc_Eg6BVE3DUKqiJqo,21447
|
9
|
-
yapcad/pyglet_drawable.py,sha256=dV9dcwzZRlPwhx18Dv0CX7wQOCxnxwk4Si_FL9heNs8,18475
|
10
|
-
yapcad/xform.py,sha256=It95Ql9JpMFqk95X8MvAmqYpCQu0VKp-JShmRTC0Ztk,9538
|
11
|
-
yapcad-0.3.0.dist-info/licenses/AUTHORS.rst,sha256=JzvJA3p1aSIOTaaB3aCtB-ZrUQrVm869gdROUV5bRh8,84
|
12
|
-
yapcad-0.3.0.dist-info/licenses/LICENSE,sha256=NkGvciCD5MEHmCtnivAi2PqcEhBYAkSAarP-bWAoknM,1071
|
13
|
-
yapcad-0.3.0.dist-info/licenses/LICENSE.txt,sha256=FyT_Hxn5USuJ1Mu3-4Ou4T2x-Dzfiy06ZOnWkfdJ33o,1081
|
14
|
-
yapcad-0.3.0.dist-info/METADATA,sha256=zfvxqcMOeJJsH2yp5Mw4TJkGeuyIAbeQ507n4f7PTdY,18999
|
15
|
-
yapcad-0.3.0.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
16
|
-
yapcad-0.3.0.dist-info/top_level.txt,sha256=NAtnfsyeALrvhI63FGS3_TEUh26OKRvnm1_lCOOgjKA,7
|
17
|
-
yapcad-0.3.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|