gridfinity-rebase 0.1.0__tar.gz
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.
- gridfinity_rebase-0.1.0/LICENSE +23 -0
- gridfinity_rebase-0.1.0/PKG-INFO +172 -0
- gridfinity_rebase-0.1.0/README.md +161 -0
- gridfinity_rebase-0.1.0/docs/benchmark.json +186 -0
- gridfinity_rebase-0.1.0/docs/images/README.md +47 -0
- gridfinity_rebase-0.1.0/docs/images/base-magnet-holes-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/base-plain-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/base-press-fit-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/base-press-fit-screws-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/base-rebuilt-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/base-rebuilt-only-corners-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/base-rebuilt-screws-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/base-rebuilt-screws-thumbscrew-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/base-rebuilt-screws-thumbscrew-only-corners-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/base-rebuilt-thumbscrew-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/base-screws-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/detail-crush-ribs.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/detail-magnet-holes.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/detail-segments-256.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/detail-segments-32.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/detail-segments-64.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/detail-side-loading.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/detail-thumbscrew.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-magnet-holes-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-plain-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-press-fit-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-press-fit-screws-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-only-corners-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-screws-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-screws-thumbscrew-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-screws-thumbscrew-only-corners-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-thumbscrew-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/base-screws-2x3.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-crush-ribs.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-magnet-holes.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-segments-256.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-segments-32.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-segments-64.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-side-loading.png +0 -0
- gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-thumbscrew.png +0 -0
- gridfinity_rebase-0.1.0/docs/performance.md +94 -0
- gridfinity_rebase-0.1.0/docs/presets.md +163 -0
- gridfinity_rebase-0.1.0/docs/segments.md +46 -0
- gridfinity_rebase-0.1.0/pyproject.toml +39 -0
- gridfinity_rebase-0.1.0/pyproject.toml.orig +31 -0
- gridfinity_rebase-0.1.0/scripts/benchmark.py +174 -0
- gridfinity_rebase-0.1.0/scripts/render_readme.py +259 -0
- gridfinity_rebase-0.1.0/scripts/setup-dev.sh +6 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/__init__.py +78 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/__main__.py +5 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/api.py +363 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/catalog.py +86 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/cli.py +377 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/errors.py +19 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/geometry.py +328 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/options.py +97 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/presets.py +253 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/py.typed +0 -0
- gridfinity_rebase-0.1.0/src/gridfinity_rebase/stl.py +127 -0
- gridfinity_rebase-0.1.0/tests/fixtures/README.md +21 -0
- gridfinity_rebase-0.1.0/tests/fixtures/gf_bin_1x1_h6_bin_v01.stl +0 -0
- gridfinity_rebase-0.1.0/tests/fixtures/test-rebased.stl +0 -0
- gridfinity_rebase-0.1.0/tests/fixtures/test.stl +0 -0
- gridfinity_rebase-0.1.0/tests/test_api.py +330 -0
- gridfinity_rebase-0.1.0/tests/test_cli.py +84 -0
- gridfinity_rebase-0.1.0/tests/test_core.py +96 -0
- gridfinity_rebase-0.1.0/tests/test_only_corners.py +161 -0
- gridfinity_rebase-0.1.0/tests/test_options.py +232 -0
- gridfinity_rebase-0.1.0/tests/test_presets.py +263 -0
- gridfinity_rebase-0.1.0/tests/test_side_pocket_height.py +132 -0
- gridfinity_rebase-0.1.0/tests/test_standard_bins.py +166 -0
- gridfinity_rebase-0.1.0/tests/test_thumbscrew.py +137 -0
- gridfinity_rebase-0.1.0/tests/test_validation.py +111 -0
- gridfinity_rebase-0.1.0/uv.lock +774 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Szymon Krajewski
|
|
4
|
+
Copyright (c) 2023 Kenneth Hodson
|
|
5
|
+
Copyright (c) 2023 Zachary Freedman and Voidstar Lab LLC
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gridfinity-rebase
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Fast, validated Gridfinity STL foot replacement
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Dist: numpy>=2.0,<3
|
|
8
|
+
Requires-Dist: manifold3d>=3.5,<4
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# Gridfinity Rebase
|
|
13
|
+
|
|
14
|
+
CLI for replacing Gridfinity bin bases with configurable presets or a base copied from another STL.
|
|
15
|
+
|
|
16
|
+
[](https://buymeacoffee.com/skrajewski)
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
Install Python 3.10+ and [uv](https://docs.astral.sh/uv/), then run this command from the repository:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
uv tool install .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
Pass an STL file to replace its base. You can also use the explicit
|
|
29
|
+
`gridfinity-rebase rebase` subcommand. Run `gridfinity-rebase` without arguments
|
|
30
|
+
to display help.
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
# Create smooth bottom-loading magnet pockets in bin-rebased-magnet-holes.stl.
|
|
34
|
+
gridfinity-rebase bin.stl --preset magnet-holes
|
|
35
|
+
|
|
36
|
+
# Create side-loading magnet pockets in bin-rebased-rebuilt.stl.
|
|
37
|
+
gridfinity-rebase bin.stl --preset rebuilt
|
|
38
|
+
|
|
39
|
+
# Create screw holes without magnet pockets in bin-rebased-screws.stl.
|
|
40
|
+
gridfinity-rebase bin.stl --screws
|
|
41
|
+
|
|
42
|
+
# Add screw holes to bottom-loading press-fit pockets
|
|
43
|
+
gridfinity-rebase bin.stl --preset press-fit --screws
|
|
44
|
+
|
|
45
|
+
# Place magnet pockets and screw holes only at the four outer corners of the bin.
|
|
46
|
+
gridfinity-rebase bin.stl --preset rebuilt --screws --only-corners
|
|
47
|
+
|
|
48
|
+
# Add side-loading magnet pockets and an M15x1.5 thumbscrew hole.
|
|
49
|
+
# The output is bin-rebased-rebuilt-thumbscrew.stl.
|
|
50
|
+
gridfinity-rebase bin.stl --preset rebuilt --thumbscrew
|
|
51
|
+
|
|
52
|
+
# Copy a base from another bin
|
|
53
|
+
gridfinity-rebase bin.stl --base donor.stl -o result.stl
|
|
54
|
+
|
|
55
|
+
# Inspect a model or list presets
|
|
56
|
+
gridfinity-rebase inspect bin.stl
|
|
57
|
+
gridfinity-rebase presets
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Presets
|
|
61
|
+
|
|
62
|
+
Available presets: `plain`, `magnet-holes`, `rebuilt` and `press-fit`.
|
|
63
|
+
`refined` is an alias for `rebuilt`.
|
|
64
|
+
|
|
65
|
+
`magnet-holes` creates smooth bottom-loading Ø6.5 × 2.4 mm pockets without ribs.
|
|
66
|
+
`press-fit` adds eight crush ribs to each pocket. You can also get this geometry
|
|
67
|
+
with `--preset magnet-holes --crush-ribs`.
|
|
68
|
+
|
|
69
|
+
The previews show the same 2×3 example bin from underneath. Click a preview for the full-size image.
|
|
70
|
+
Append the options in each row to `gridfinity-rebase bin.stl`.
|
|
71
|
+
|
|
72
|
+
| Preview | Preset | Options |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| [](docs/images/base-plain-2x3.png) | `plain` creates standard feet without magnet pockets or screw holes. | `--preset plain` |
|
|
75
|
+
| [](docs/images/base-magnet-holes-2x3.png) | `magnet-holes` creates four Ø6.5 mm magnet pockets per foot, 2.4 mm deep, without crush ribs. | `--preset magnet-holes` |
|
|
76
|
+
| [](docs/images/base-rebuilt-2x3.png) | `rebuilt` creates four pockets per foot in a fan pattern, with one opening per edge. Small underside slots let you remove magnets. | `--preset rebuilt` |
|
|
77
|
+
| [](docs/images/base-press-fit-2x3.png) | `press-fit` creates four bottom-loading pockets per foot, each with eight crush ribs. | `--preset press-fit` |
|
|
78
|
+
|
|
79
|
+
### Geometry options
|
|
80
|
+
|
|
81
|
+
The default preset is `plain`. Select another preset or change individual settings:
|
|
82
|
+
|
|
83
|
+
- `--magnets none|side|bottom`: no magnet pockets, side-loading pockets, or bottom-loading pockets.
|
|
84
|
+
- `--side-pocket-height MM`: set the side-loading pocket height. The default is 2.1 mm.
|
|
85
|
+
- `--screws` / `--no-screws`: enable or disable 3 mm screw bores.
|
|
86
|
+
- `--crush-ribs` / `--no-crush-ribs`: enable or disable ribs in bottom-loading pockets.
|
|
87
|
+
- `--only-corners`: limit magnet pockets and 3 mm screw bores to the four outer corners of the whole bin, regardless of grid size. A 1×1 bin keeps all four holes. Central `--thumbscrew` holes still appear in every foot.
|
|
88
|
+
- `--thumbscrew` / `--no-thumbscrew`: enable or disable the central threaded hole.
|
|
89
|
+
|
|
90
|
+
### Examples with geometry options
|
|
91
|
+
|
|
92
|
+
Add flags to a preset to combine magnet pockets, screws and central threads,
|
|
93
|
+
or to place magnet pockets and screw bores only at the outer corners.
|
|
94
|
+
|
|
95
|
+
| Preview | Description | Options |
|
|
96
|
+
| --- | --- | --- |
|
|
97
|
+
| [](docs/images/base-rebuilt-screws-2x3.png) | Each side-loading pocket has a Ø3 mm screw bore. | `--preset rebuilt --screws` |
|
|
98
|
+
| [](docs/images/base-screws-2x3.png) | Each foot has four Ø3 mm screw bores without magnet pockets. | `--screws` |
|
|
99
|
+
| [](docs/images/base-press-fit-screws-2x3.png) | Bottom-loading pockets have crush ribs and screw bores in their floors. | `--preset press-fit --screws` |
|
|
100
|
+
| [](docs/images/base-rebuilt-thumbscrew-2x3.png) | Each foot has side-loading pockets and a central M15×1.5 threaded hole. | `--preset rebuilt --thumbscrew` |
|
|
101
|
+
| [](docs/images/base-rebuilt-only-corners-2x3.png) | The whole bin has four side-loading pockets, one at each outer corner, instead of 24. | `--preset rebuilt --only-corners` |
|
|
102
|
+
| [](docs/images/base-rebuilt-screws-thumbscrew-2x3.png) | The bin has 24 side pockets, 24 screw bores and six central threaded holes. | `--preset rebuilt --screws --thumbscrew` |
|
|
103
|
+
| [](docs/images/base-rebuilt-screws-thumbscrew-only-corners-2x3.png) | The whole bin has four side pockets and four screw bores at its outer corners. All six feet have a central threaded hole. | `--preset rebuilt --screws --thumbscrew --only-corners` |
|
|
104
|
+
|
|
105
|
+
### Close-ups
|
|
106
|
+
|
|
107
|
+
| Preview | Description | Options |
|
|
108
|
+
| --- | --- | --- |
|
|
109
|
+
| [](docs/images/detail-side-loading.png) | The magnet slides through the opening in the edge of the foot. | `--preset rebuilt` |
|
|
110
|
+
| [](docs/images/detail-magnet-holes.png) | Insert the magnet into the circular recess from underneath. | `--preset magnet-holes` |
|
|
111
|
+
| [](docs/images/detail-crush-ribs.png) | Eight ribs narrow the pocket for a press fit. | `--preset press-fit` |
|
|
112
|
+
| [](docs/images/detail-thumbscrew.png) | The M15×1.5 threaded hole is 4.75 mm deep, with a solid bridge above. | `--preset rebuilt --thumbscrew` |
|
|
113
|
+
|
|
114
|
+
The images show geometry generated by the CLI. [Regenerate the graphics](docs/images/README.md).
|
|
115
|
+
|
|
116
|
+
See [curve resolution](docs/segments.md) for `--segments` settings and visual comparisons.
|
|
117
|
+
|
|
118
|
+
## Key details
|
|
119
|
+
|
|
120
|
+
- The CLI supports standard rectangular Gridfinity bins on a 42 mm grid. Use millimeters for STL units, with feet at the bottom and Z pointing up.
|
|
121
|
+
- The CLI detects the base and cut height. It preserves the bin interior and geometry above the cut, and rejects invalid meshes, incompatible bases and ambiguous models.
|
|
122
|
+
- A donor base can match the input grid or have its X/Y dimensions swapped. The CLI can also tile a 1×1 donor base across the input.
|
|
123
|
+
- Unmodified presets write to `bin-rebased-PRESET.stl`. `--thumbscrew` and `--only-corners` append their names to the filename. Modified settings use a descriptive suffix, such as `bin-rebased-magnets-bottom-crush-ribs-screws.stl`. Donor bases use `bin-rebased.stl`. Use `-o` to choose a filename and `--overwrite` to replace an existing output.
|
|
124
|
+
- JSON reports include the resolved `geometry` settings. `base` identifies the starting preset or donor path. The default preset is `plain`. For donor bases, `geometry` is `null`.
|
|
125
|
+
- `--base-height MM` overrides automatic detection for custom models and replaces everything below that height. The minimum is 4.75 mm.
|
|
126
|
+
|
|
127
|
+
Run `gridfinity-rebase --help` for all options.
|
|
128
|
+
|
|
129
|
+
## Performance
|
|
130
|
+
|
|
131
|
+
Run the benchmark from the repository root:
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
uv run --locked --python 3.11 python scripts/benchmark.py --runs 5
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The benchmark generates all test models locally. You do not need to download example STLs.
|
|
138
|
+
See [benchmark instructions, methodology and reference results](docs/performance.md)
|
|
139
|
+
for JSON output and environment details.
|
|
140
|
+
|
|
141
|
+
## AI Disclosure
|
|
142
|
+
|
|
143
|
+
Szymon here. I use AI to build this tool.
|
|
144
|
+
|
|
145
|
+
I needed a way for quick replacement of base of custom Grdifnity bins downloaded from Internet, but I didn't want to spend too much of my free time on this. I collaborated with the AI, describing how it should work, how I want to use it and what's the important from the both code perspective and end-user perspective. It allowed me to iterate and create something that is exactly what I needed. Now I share it with you.
|
|
146
|
+
|
|
147
|
+
Just want you to know.
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
The [MIT license](LICENSE) covers this CLI and its adapted preset implementation.
|
|
152
|
+
|
|
153
|
+
Processing a model does not replace its existing license or attribution
|
|
154
|
+
requirements. When sharing a rebased STL, preserve applicable notices and
|
|
155
|
+
comply with the licenses of the input model and any donor geometry.
|
|
156
|
+
|
|
157
|
+
## Acknowledgements
|
|
158
|
+
|
|
159
|
+
Preset geometry is adapted from the MIT-licensed [Gridfinity Rebuilt implementation](https://github.com/kennetek/gridfinity-rebuilt-openscad/tree/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd)
|
|
160
|
+
by Kenneth Hodson, based on Gridfinity by Zack Freedman. Rebuilt credits
|
|
161
|
+
[Gridfinity Refined](https://www.printables.com/model/413761-gridfinity-refined)
|
|
162
|
+
by grizzie17 as the source of its side-loading magnet pockets.
|
|
163
|
+
|
|
164
|
+
Rebuilt source files at revision `910e22d8607fd7f5f51ad5e5cbc5287a76810bfd`:
|
|
165
|
+
|
|
166
|
+
- [standard.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/standard.scad): mating profile, grid, radii and hole dimensions.
|
|
167
|
+
- [gridfinity-rebuilt-holes.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/gridfinity-rebuilt-holes.scad): side-loading magnet pockets and crush ribs.
|
|
168
|
+
- [base.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/base.scad): fan arrangement of the four pockets and the central threaded hole.
|
|
169
|
+
|
|
170
|
+
The native thumbscrew thread tessellation derives from `ScrewThread()` in
|
|
171
|
+
[threads-scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/external/threads-scad/threads.scad),
|
|
172
|
+
created in 2016 — 2017 by Ryan A. Colyer and released under [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Gridfinity Rebase
|
|
2
|
+
|
|
3
|
+
CLI for replacing Gridfinity bin bases with configurable presets or a base copied from another STL.
|
|
4
|
+
|
|
5
|
+
[](https://buymeacoffee.com/skrajewski)
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Install Python 3.10+ and [uv](https://docs.astral.sh/uv/), then run this command from the repository:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
uv tool install .
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Pass an STL file to replace its base. You can also use the explicit
|
|
18
|
+
`gridfinity-rebase rebase` subcommand. Run `gridfinity-rebase` without arguments
|
|
19
|
+
to display help.
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
# Create smooth bottom-loading magnet pockets in bin-rebased-magnet-holes.stl.
|
|
23
|
+
gridfinity-rebase bin.stl --preset magnet-holes
|
|
24
|
+
|
|
25
|
+
# Create side-loading magnet pockets in bin-rebased-rebuilt.stl.
|
|
26
|
+
gridfinity-rebase bin.stl --preset rebuilt
|
|
27
|
+
|
|
28
|
+
# Create screw holes without magnet pockets in bin-rebased-screws.stl.
|
|
29
|
+
gridfinity-rebase bin.stl --screws
|
|
30
|
+
|
|
31
|
+
# Add screw holes to bottom-loading press-fit pockets
|
|
32
|
+
gridfinity-rebase bin.stl --preset press-fit --screws
|
|
33
|
+
|
|
34
|
+
# Place magnet pockets and screw holes only at the four outer corners of the bin.
|
|
35
|
+
gridfinity-rebase bin.stl --preset rebuilt --screws --only-corners
|
|
36
|
+
|
|
37
|
+
# Add side-loading magnet pockets and an M15x1.5 thumbscrew hole.
|
|
38
|
+
# The output is bin-rebased-rebuilt-thumbscrew.stl.
|
|
39
|
+
gridfinity-rebase bin.stl --preset rebuilt --thumbscrew
|
|
40
|
+
|
|
41
|
+
# Copy a base from another bin
|
|
42
|
+
gridfinity-rebase bin.stl --base donor.stl -o result.stl
|
|
43
|
+
|
|
44
|
+
# Inspect a model or list presets
|
|
45
|
+
gridfinity-rebase inspect bin.stl
|
|
46
|
+
gridfinity-rebase presets
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Presets
|
|
50
|
+
|
|
51
|
+
Available presets: `plain`, `magnet-holes`, `rebuilt` and `press-fit`.
|
|
52
|
+
`refined` is an alias for `rebuilt`.
|
|
53
|
+
|
|
54
|
+
`magnet-holes` creates smooth bottom-loading Ø6.5 × 2.4 mm pockets without ribs.
|
|
55
|
+
`press-fit` adds eight crush ribs to each pocket. You can also get this geometry
|
|
56
|
+
with `--preset magnet-holes --crush-ribs`.
|
|
57
|
+
|
|
58
|
+
The previews show the same 2×3 example bin from underneath. Click a preview for the full-size image.
|
|
59
|
+
Append the options in each row to `gridfinity-rebase bin.stl`.
|
|
60
|
+
|
|
61
|
+
| Preview | Preset | Options |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| [](docs/images/base-plain-2x3.png) | `plain` creates standard feet without magnet pockets or screw holes. | `--preset plain` |
|
|
64
|
+
| [](docs/images/base-magnet-holes-2x3.png) | `magnet-holes` creates four Ø6.5 mm magnet pockets per foot, 2.4 mm deep, without crush ribs. | `--preset magnet-holes` |
|
|
65
|
+
| [](docs/images/base-rebuilt-2x3.png) | `rebuilt` creates four pockets per foot in a fan pattern, with one opening per edge. Small underside slots let you remove magnets. | `--preset rebuilt` |
|
|
66
|
+
| [](docs/images/base-press-fit-2x3.png) | `press-fit` creates four bottom-loading pockets per foot, each with eight crush ribs. | `--preset press-fit` |
|
|
67
|
+
|
|
68
|
+
### Geometry options
|
|
69
|
+
|
|
70
|
+
The default preset is `plain`. Select another preset or change individual settings:
|
|
71
|
+
|
|
72
|
+
- `--magnets none|side|bottom`: no magnet pockets, side-loading pockets, or bottom-loading pockets.
|
|
73
|
+
- `--side-pocket-height MM`: set the side-loading pocket height. The default is 2.1 mm.
|
|
74
|
+
- `--screws` / `--no-screws`: enable or disable 3 mm screw bores.
|
|
75
|
+
- `--crush-ribs` / `--no-crush-ribs`: enable or disable ribs in bottom-loading pockets.
|
|
76
|
+
- `--only-corners`: limit magnet pockets and 3 mm screw bores to the four outer corners of the whole bin, regardless of grid size. A 1×1 bin keeps all four holes. Central `--thumbscrew` holes still appear in every foot.
|
|
77
|
+
- `--thumbscrew` / `--no-thumbscrew`: enable or disable the central threaded hole.
|
|
78
|
+
|
|
79
|
+
### Examples with geometry options
|
|
80
|
+
|
|
81
|
+
Add flags to a preset to combine magnet pockets, screws and central threads,
|
|
82
|
+
or to place magnet pockets and screw bores only at the outer corners.
|
|
83
|
+
|
|
84
|
+
| Preview | Description | Options |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| [](docs/images/base-rebuilt-screws-2x3.png) | Each side-loading pocket has a Ø3 mm screw bore. | `--preset rebuilt --screws` |
|
|
87
|
+
| [](docs/images/base-screws-2x3.png) | Each foot has four Ø3 mm screw bores without magnet pockets. | `--screws` |
|
|
88
|
+
| [](docs/images/base-press-fit-screws-2x3.png) | Bottom-loading pockets have crush ribs and screw bores in their floors. | `--preset press-fit --screws` |
|
|
89
|
+
| [](docs/images/base-rebuilt-thumbscrew-2x3.png) | Each foot has side-loading pockets and a central M15×1.5 threaded hole. | `--preset rebuilt --thumbscrew` |
|
|
90
|
+
| [](docs/images/base-rebuilt-only-corners-2x3.png) | The whole bin has four side-loading pockets, one at each outer corner, instead of 24. | `--preset rebuilt --only-corners` |
|
|
91
|
+
| [](docs/images/base-rebuilt-screws-thumbscrew-2x3.png) | The bin has 24 side pockets, 24 screw bores and six central threaded holes. | `--preset rebuilt --screws --thumbscrew` |
|
|
92
|
+
| [](docs/images/base-rebuilt-screws-thumbscrew-only-corners-2x3.png) | The whole bin has four side pockets and four screw bores at its outer corners. All six feet have a central threaded hole. | `--preset rebuilt --screws --thumbscrew --only-corners` |
|
|
93
|
+
|
|
94
|
+
### Close-ups
|
|
95
|
+
|
|
96
|
+
| Preview | Description | Options |
|
|
97
|
+
| --- | --- | --- |
|
|
98
|
+
| [](docs/images/detail-side-loading.png) | The magnet slides through the opening in the edge of the foot. | `--preset rebuilt` |
|
|
99
|
+
| [](docs/images/detail-magnet-holes.png) | Insert the magnet into the circular recess from underneath. | `--preset magnet-holes` |
|
|
100
|
+
| [](docs/images/detail-crush-ribs.png) | Eight ribs narrow the pocket for a press fit. | `--preset press-fit` |
|
|
101
|
+
| [](docs/images/detail-thumbscrew.png) | The M15×1.5 threaded hole is 4.75 mm deep, with a solid bridge above. | `--preset rebuilt --thumbscrew` |
|
|
102
|
+
|
|
103
|
+
The images show geometry generated by the CLI. [Regenerate the graphics](docs/images/README.md).
|
|
104
|
+
|
|
105
|
+
See [curve resolution](docs/segments.md) for `--segments` settings and visual comparisons.
|
|
106
|
+
|
|
107
|
+
## Key details
|
|
108
|
+
|
|
109
|
+
- The CLI supports standard rectangular Gridfinity bins on a 42 mm grid. Use millimeters for STL units, with feet at the bottom and Z pointing up.
|
|
110
|
+
- The CLI detects the base and cut height. It preserves the bin interior and geometry above the cut, and rejects invalid meshes, incompatible bases and ambiguous models.
|
|
111
|
+
- A donor base can match the input grid or have its X/Y dimensions swapped. The CLI can also tile a 1×1 donor base across the input.
|
|
112
|
+
- Unmodified presets write to `bin-rebased-PRESET.stl`. `--thumbscrew` and `--only-corners` append their names to the filename. Modified settings use a descriptive suffix, such as `bin-rebased-magnets-bottom-crush-ribs-screws.stl`. Donor bases use `bin-rebased.stl`. Use `-o` to choose a filename and `--overwrite` to replace an existing output.
|
|
113
|
+
- JSON reports include the resolved `geometry` settings. `base` identifies the starting preset or donor path. The default preset is `plain`. For donor bases, `geometry` is `null`.
|
|
114
|
+
- `--base-height MM` overrides automatic detection for custom models and replaces everything below that height. The minimum is 4.75 mm.
|
|
115
|
+
|
|
116
|
+
Run `gridfinity-rebase --help` for all options.
|
|
117
|
+
|
|
118
|
+
## Performance
|
|
119
|
+
|
|
120
|
+
Run the benchmark from the repository root:
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
uv run --locked --python 3.11 python scripts/benchmark.py --runs 5
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The benchmark generates all test models locally. You do not need to download example STLs.
|
|
127
|
+
See [benchmark instructions, methodology and reference results](docs/performance.md)
|
|
128
|
+
for JSON output and environment details.
|
|
129
|
+
|
|
130
|
+
## AI Disclosure
|
|
131
|
+
|
|
132
|
+
Szymon here. I use AI to build this tool.
|
|
133
|
+
|
|
134
|
+
I needed a way for quick replacement of base of custom Grdifnity bins downloaded from Internet, but I didn't want to spend too much of my free time on this. I collaborated with the AI, describing how it should work, how I want to use it and what's the important from the both code perspective and end-user perspective. It allowed me to iterate and create something that is exactly what I needed. Now I share it with you.
|
|
135
|
+
|
|
136
|
+
Just want you to know.
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
The [MIT license](LICENSE) covers this CLI and its adapted preset implementation.
|
|
141
|
+
|
|
142
|
+
Processing a model does not replace its existing license or attribution
|
|
143
|
+
requirements. When sharing a rebased STL, preserve applicable notices and
|
|
144
|
+
comply with the licenses of the input model and any donor geometry.
|
|
145
|
+
|
|
146
|
+
## Acknowledgements
|
|
147
|
+
|
|
148
|
+
Preset geometry is adapted from the MIT-licensed [Gridfinity Rebuilt implementation](https://github.com/kennetek/gridfinity-rebuilt-openscad/tree/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd)
|
|
149
|
+
by Kenneth Hodson, based on Gridfinity by Zack Freedman. Rebuilt credits
|
|
150
|
+
[Gridfinity Refined](https://www.printables.com/model/413761-gridfinity-refined)
|
|
151
|
+
by grizzie17 as the source of its side-loading magnet pockets.
|
|
152
|
+
|
|
153
|
+
Rebuilt source files at revision `910e22d8607fd7f5f51ad5e5cbc5287a76810bfd`:
|
|
154
|
+
|
|
155
|
+
- [standard.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/standard.scad): mating profile, grid, radii and hole dimensions.
|
|
156
|
+
- [gridfinity-rebuilt-holes.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/gridfinity-rebuilt-holes.scad): side-loading magnet pockets and crush ribs.
|
|
157
|
+
- [base.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/base.scad): fan arrangement of the four pockets and the central threaded hole.
|
|
158
|
+
|
|
159
|
+
The native thumbscrew thread tessellation derives from `ScrewThread()` in
|
|
160
|
+
[threads-scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/external/threads-scad/threads.scad),
|
|
161
|
+
created in 2016 — 2017 by Ryan A. Colyer and released under [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
{
|
|
2
|
+
"measured_at_utc": "2026-10-13T21:57:46.970337+00:00",
|
|
3
|
+
"platform": "macOS-26.2-arm64-arm-64bit",
|
|
4
|
+
"machine": "arm64",
|
|
5
|
+
"processor": "arm",
|
|
6
|
+
"logical_cpus": 12,
|
|
7
|
+
"python": "3.11.14",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"gridfinity-rebase": "0.2.1",
|
|
10
|
+
"manifold3d": "3.5.4",
|
|
11
|
+
"numpy": "2.4.6"
|
|
12
|
+
},
|
|
13
|
+
"runs": 5,
|
|
14
|
+
"warmups_per_scenario": 1,
|
|
15
|
+
"segments": 64,
|
|
16
|
+
"inputs": {
|
|
17
|
+
"1x1": {
|
|
18
|
+
"sha256": "b3b6c2ad78f0e541e5e90331b669c8eaff3a692773903fc71c41b03e225bf184",
|
|
19
|
+
"triangles": 1894
|
|
20
|
+
},
|
|
21
|
+
"donor": {
|
|
22
|
+
"sha256": "b3b6c2ad78f0e541e5e90331b669c8eaff3a692773903fc71c41b03e225bf184",
|
|
23
|
+
"triangles": 1894
|
|
24
|
+
},
|
|
25
|
+
"6x6": {
|
|
26
|
+
"sha256": "c65ebe2a72559086b1a7fa85df1fdde08dccaef808ebc5581f53459b682f24d9",
|
|
27
|
+
"triangles": 58246
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"results": [
|
|
31
|
+
{
|
|
32
|
+
"scenario": "1x1/plain",
|
|
33
|
+
"input_triangles": 1894,
|
|
34
|
+
"process_median_ms": 94.51,
|
|
35
|
+
"process_min_ms": 89.43,
|
|
36
|
+
"process_max_ms": 95.4,
|
|
37
|
+
"warm_engine_median_ms": 12.46,
|
|
38
|
+
"process_samples_ms": [
|
|
39
|
+
94.5103750564158,
|
|
40
|
+
89.4317920319736,
|
|
41
|
+
89.57604202441871,
|
|
42
|
+
95.39591695647687,
|
|
43
|
+
94.918749993667
|
|
44
|
+
],
|
|
45
|
+
"warm_engine_samples_ms": [
|
|
46
|
+
12.875832966528833,
|
|
47
|
+
12.11520901415497,
|
|
48
|
+
12.394832912832499,
|
|
49
|
+
12.613541912287474,
|
|
50
|
+
12.457333039492369
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"scenario": "1x1/rebuilt",
|
|
55
|
+
"input_triangles": 1894,
|
|
56
|
+
"process_median_ms": 94.41,
|
|
57
|
+
"process_min_ms": 93.3,
|
|
58
|
+
"process_max_ms": 97.89,
|
|
59
|
+
"warm_engine_median_ms": 14.64,
|
|
60
|
+
"process_samples_ms": [
|
|
61
|
+
94.40787509083748,
|
|
62
|
+
97.88887505419552,
|
|
63
|
+
93.29600003547966,
|
|
64
|
+
94.29145907051861,
|
|
65
|
+
97.07208396866918
|
|
66
|
+
],
|
|
67
|
+
"warm_engine_samples_ms": [
|
|
68
|
+
15.291957999579608,
|
|
69
|
+
14.654417056590319,
|
|
70
|
+
14.159000013023615,
|
|
71
|
+
14.640958048403263,
|
|
72
|
+
14.112790930084884
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"scenario": "1x1/rebuilt-screws",
|
|
77
|
+
"input_triangles": 1894,
|
|
78
|
+
"process_median_ms": 112.18,
|
|
79
|
+
"process_min_ms": 110.47,
|
|
80
|
+
"process_max_ms": 115.48,
|
|
81
|
+
"warm_engine_median_ms": 28.16,
|
|
82
|
+
"process_samples_ms": [
|
|
83
|
+
115.48470810521394,
|
|
84
|
+
111.7373340530321,
|
|
85
|
+
112.17912496067584,
|
|
86
|
+
110.46716605778784,
|
|
87
|
+
115.03658397123218
|
|
88
|
+
],
|
|
89
|
+
"warm_engine_samples_ms": [
|
|
90
|
+
27.97850000206381,
|
|
91
|
+
28.1615830026567,
|
|
92
|
+
27.632666984573007,
|
|
93
|
+
28.340917080640793,
|
|
94
|
+
28.18029106128961
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"scenario": "1x1/refined",
|
|
99
|
+
"input_triangles": 1894,
|
|
100
|
+
"process_median_ms": 87.83,
|
|
101
|
+
"process_min_ms": 87.02,
|
|
102
|
+
"process_max_ms": 89.51,
|
|
103
|
+
"warm_engine_median_ms": 14.14,
|
|
104
|
+
"process_samples_ms": [
|
|
105
|
+
87.8272500121966,
|
|
106
|
+
87.02079206705093,
|
|
107
|
+
89.35604197904468,
|
|
108
|
+
87.70487492438406,
|
|
109
|
+
89.51008401345462
|
|
110
|
+
],
|
|
111
|
+
"warm_engine_samples_ms": [
|
|
112
|
+
14.215333969332278,
|
|
113
|
+
13.873500050976872,
|
|
114
|
+
14.188083005137742,
|
|
115
|
+
13.950416934676468,
|
|
116
|
+
14.141583000309765
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"scenario": "1x1/press-fit",
|
|
121
|
+
"input_triangles": 1894,
|
|
122
|
+
"process_median_ms": 87.83,
|
|
123
|
+
"process_min_ms": 86.86,
|
|
124
|
+
"process_max_ms": 90.24,
|
|
125
|
+
"warm_engine_median_ms": 13.72,
|
|
126
|
+
"process_samples_ms": [
|
|
127
|
+
87.73008291609585,
|
|
128
|
+
88.37041701190174,
|
|
129
|
+
90.24062496609986,
|
|
130
|
+
86.86333289369941,
|
|
131
|
+
87.8282500198111
|
|
132
|
+
],
|
|
133
|
+
"warm_engine_samples_ms": [
|
|
134
|
+
13.611625065095723,
|
|
135
|
+
13.737166998907924,
|
|
136
|
+
13.724167016334832,
|
|
137
|
+
13.462667004205287,
|
|
138
|
+
14.19558294583112
|
|
139
|
+
]
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"scenario": "1x1/donor",
|
|
143
|
+
"input_triangles": 1894,
|
|
144
|
+
"process_median_ms": 89.76,
|
|
145
|
+
"process_min_ms": 89.11,
|
|
146
|
+
"process_max_ms": 91.82,
|
|
147
|
+
"warm_engine_median_ms": 18.54,
|
|
148
|
+
"process_samples_ms": [
|
|
149
|
+
90.0000830879435,
|
|
150
|
+
89.24408291932195,
|
|
151
|
+
89.1148749506101,
|
|
152
|
+
89.76320794317871,
|
|
153
|
+
91.8165419716388
|
|
154
|
+
],
|
|
155
|
+
"warm_engine_samples_ms": [
|
|
156
|
+
18.746749963611364,
|
|
157
|
+
18.00991699565202,
|
|
158
|
+
18.890125094912946,
|
|
159
|
+
18.205416039563715,
|
|
160
|
+
18.536541028879583
|
|
161
|
+
]
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"scenario": "6x6/refined",
|
|
165
|
+
"input_triangles": 58246,
|
|
166
|
+
"process_median_ms": 260.88,
|
|
167
|
+
"process_min_ms": 257.67,
|
|
168
|
+
"process_max_ms": 270.68,
|
|
169
|
+
"warm_engine_median_ms": 178.35,
|
|
170
|
+
"process_samples_ms": [
|
|
171
|
+
264.94266698136926,
|
|
172
|
+
260.8814589912072,
|
|
173
|
+
257.6676660683006,
|
|
174
|
+
260.19500009715557,
|
|
175
|
+
270.68120893090963
|
|
176
|
+
],
|
|
177
|
+
"warm_engine_samples_ms": [
|
|
178
|
+
179.92949998006225,
|
|
179
|
+
178.08800004422665,
|
|
180
|
+
178.34912496618927,
|
|
181
|
+
178.3229160355404,
|
|
182
|
+
179.09554205834866
|
|
183
|
+
]
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# README graphics
|
|
2
|
+
|
|
3
|
+
Each PNG contains one model or one close-up, without embedded text. The main
|
|
4
|
+
README places the images in tables with descriptions and the corresponding CLI
|
|
5
|
+
options. Clicking a thumbnail opens the full-size image.
|
|
6
|
+
The `thumbnails/` directory contains 260 px previews, so the README can use
|
|
7
|
+
standard Markdown image links without HTML sizing attributes.
|
|
8
|
+
|
|
9
|
+
The `base-*-2x3.png` images show the underside of the same synthetic 2×3 example
|
|
10
|
+
bin, using `generate_base()` and the CLI's resolved geometry options. They use
|
|
11
|
+
the same body, camera, orthographic scale and lighting. The `detail-*.png` images
|
|
12
|
+
show crops of those same models. Magnification varies between details.
|
|
13
|
+
|
|
14
|
+
The four preset images are `base-plain-2x3.png`,
|
|
15
|
+
`base-magnet-holes-2x3.png`, `base-rebuilt-2x3.png` and
|
|
16
|
+
`base-press-fit-2x3.png`. `refined` shares the `rebuilt` image because it is
|
|
17
|
+
an alias. Other base images illustrate combinations of geometry flags,
|
|
18
|
+
such as `rebuilt` with `--screws`.
|
|
19
|
+
The `detail-magnet-holes.png` and `detail-crush-ribs.png` close-ups show
|
|
20
|
+
the difference between smooth magnet pockets and `press-fit`.
|
|
21
|
+
|
|
22
|
+
The `detail-segments-{32,64,256}.png` images compare a central threaded
|
|
23
|
+
hole in a generated 1×1 base at three curve resolutions. All three use the same
|
|
24
|
+
camera, scale and lighting. Only the base's segment count changes.
|
|
25
|
+
|
|
26
|
+
Regenerate from the repository root:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
uv run --with pillow python scripts/render_readme.py
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Regenerate only the three resolution comparisons and their thumbnails:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
uv run --with pillow python scripts/render_readme.py --segments-only
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The renderer uses NumPy and Pillow with a triangle depth buffer. It needs no
|
|
39
|
+
display, GPU or external CAD renderer. The command installs Pillow as a temporary
|
|
40
|
+
dependency. Preset and geometry option illustrations use 256 segments by default
|
|
41
|
+
for close-ups, independently of the CLI's default of 64. The resolution
|
|
42
|
+
comparisons always use 32, 64 and 256, regardless of the renderer's `--segments`
|
|
43
|
+
argument. Edit descriptions and options in the README.
|
|
44
|
+
|
|
45
|
+
The shared example body is 21 mm high, with a cavity starting at 8 mm. Its base
|
|
46
|
+
extends to 7 mm. The body has no stacking lip because these illustrations
|
|
47
|
+
focus on the feet and mounting options.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|