[User]
Hey, I'm working on a design that needs a rounded plate, like a rounded rectangle but 3D. I found some code that seems to do the trick, but I'd like it to be a bit more robust and flexible. It seems to rely on a `hull()` function, but I don't know what the underlying method is. The code is included below. Can you generate a parametric OpenSCAD module that creates a rounded plate with adjustable dimensions, corner rounding, and number of facets? The module should be usable in other designs, so make sure the module takes parameters for size (x, y, and z), rounding radius, and facets. Please don't use `minkowski()`, as the code mentions it's slower, so I'm trying to avoid it.

I'm not going to be using the Thingiverse customizer, so feel free to leave out any variable declarations designed for it. Also, it would be nice if the module could handle a zero or very small rounding radius without error, i.e. it will produce a rectangle or a plate with nearly square corners if the rounding radius is set to zero or close to it.

```
//Rounded plate module - faster than minkowski!
//variables with "customizer" in them are only for the Thingiverse customizer and are not essential.

customizer_x=15;
customizer_y=10;
customizer_z=1;

customizer_facets=32;
customizer_rounding_radius=1;

module rounded_plate(size_x,size_y,size_z,facets,rounding_radius)
{
	hull()
	{
		translate([rounding_radius,rounding_radius,0]) cylinder (h=size_z, r=rounding_radius,$fn=facets);
		translate([size_x-rounding_radius,rounding_radius,0]) cylinder (h=size_z,r=rounding_radius,$fn=facets);
		translate([rounding_radius,size_y-rounding_radius,0]) cylinder (h=size_z,r=rounding_radius,$fn=facets);
		translate([size_x-rounding_radius,size_y-rounding_radius,0]) cylinder (h=size_z,r=rounding_radius,$fn=facets);
	}
}

rounded_plate(customizer_x,customizer_y,customizer_z,customizer_facets,customizer_rounding_radius);
```

[Assistant]
rounded_plate.scad:
```
//Rounded plate module - faster than minkowski!
//variables with "customizer" in them are only for the Thingiverse customizer and are not essential.

customizer_x=15;
customizer_y=10;
customizer_z=1;

customizer_facets=32;
customizer_rounding_radius=1;

module rounded_plate(size_x,size_y,size_z,facets,rounding_radius)
{
	hull()
	{
		translate([rounding_radius,rounding_radius,0]) cylinder (h=size_z, r=rounding_radius,$fn=facets);
		translate([size_x-rounding_radius,rounding_radius,0]) cylinder (h=size_z,r=rounding_radius,$fn=facets);
		translate([rounding_radius,size_y-rounding_radius,0]) cylinder (h=size_z,r=rounding_radius,$fn=facets);
		translate([size_x-rounding_radius,size_y-rounding_radius,0]) cylinder (h=size_z,r=rounding_radius,$fn=facets);
	}
}

rounded_plate(customizer_x,customizer_y,customizer_z,customizer_facets,customizer_rounding_radius);

```


[User]
Hey, I'm looking to design a tie hanger, specifically for bolo ties, and I need it to be parametric so I can adjust it easily. I've seen some great scarf hangers out there, and I'm thinking I can adapt that kind of design.

Here's what I'm picturing. I need a main bar with slots cut into it, which will hold the ties. The slots should be evenly spaced along the bar, and I should be able to adjust both the length of the bar and the width of the slots. I would also need to adjust the width/thickness of the bar to ensure it is stable. The ends of the bar should have a bit of extra material on them to keep the ties from sliding off. I'll need a central hanger part that goes up and curves around to hang on a rod, like a clothes hanger, but fairly small - the existing model uses eighths of a ring, with an overlapping ring at the top for strength, that would be ideal.

I'd like to be able to control these parameters:

*   `hanger_length`: The overall length of the main bar (in cm, maybe range from 15 to 35).
*   `width_of_bar`: The width of the main bar and the slots (in mm, maybe range from 5 to 15).
*   `gap`: The space between the slots, but this can be fixed. Let's say 15mm.

The central hanger part should be centered at the length of the main bar, and the ring should have a fixed radius of 20mm. I want to use a similar construction to what is in the attached file, with a central bar and the ring piece intersecting to provide strength. Please also include some "ears" at the end of the main bar, like in the provided SCAD, for extra support to keep the ties from sliding off.

I'm not familiar with libraries outside of the basics, so if you can do this with vanilla OpenSCAD, I would be very happy.

[Assistant]
tie-hanger.scad:
```
// Hanger length in cm
hanger_length = 25 ;	// [15:35]

// Width bar/loop in mm
width_of_bar = 10  ;	// [5:15]

// rotate([0, 0, 45])
translate([-10 * hanger_length / 2 - width_of_bar / 2, 54.5, 0])
tie_hanger(hanger_length * 10, width_of_bar) ;

module tie_hanger(length, width) {
    gap = 15 ;	// gap between slots
    r = width / 2 ;
    s = sin(45) ;

    // The main bar
    difference() {
        cube(size=[length, width * 2, width]) ;
        for (i = [gap + r:gap + width:(length - width - gap) / 2]) {
            translate([length / 2 + i - r, -1, -1])
            cube(size=[width, width + 1, width + 2]) ;
            translate([length / 2 - i - r, -1, -1])
            cube(size=[width, width + 1, width + 2]) ;
        }
    }

    // tips on the end
    translate([0, -r * 4, 0]) cube(size=[width, width * 2, width]) ;
    translate([length - r * 2, -r * 4, 0]) cube(size=[width, width * 4, width]) ;

    // The center hanger part
    color("red")
    union() {
        translate([length / 2 - r, -20, 0]) cube(size=[width, 20, width]) ;
        translate([length / 2 - 20 - r, -20, 0]) rotate([0, 0, -90]) eigth(width) ;

        translate([length / 2 - 20 - r + (40 + width) * s,
                   -20 - (40 + width) * s, 0])
        rotate([0, 0, 90]) eigth(width) ;

        translate([length / 2 - 20  - r + (40 + width) * s,
                   -20 - 2 * (20 + r) * s, 0])
        rotate([0, 0, 180])
        intersection() {
            ring(width) ;
            translate([-21 - width, -1, -1])
            cube(size=[42 + 2 * width, 22 + width, width + 2]) ;
        }
    }
}

module eigth(w) {
    $fn = 120 ;
    r = 20 ;
    intersection() {
        ring(w, r) ;
        cube(size=[r + w, r + w, w + 2]) ;
        rotate([0, 0, 45]) cube(size=[r + w, r + w, w + 2]) ;
    }
}

module ring(w) {
    rotate_extrude() translate([20, 0, 0]) square([w, w]) ;
}
```


[User]
Hey, I'm looking to design a model of the Chestahedron, specifically using the kite shapes that form its quadrilateral faces. I've got a basic starting point in OpenSCAD (attached, named `chestahedron-kites-net.scad`), which generates three kite shapes that I want to use.

Ultimately, I want to generate a printable model where all the kite pieces are arranged in a net pattern ready to be folded and glued together. I’d like to be able to parametrically adjust the overall size of the Chestahedron. I am not worried about the triangular faces for this print, only the kites.

Here's a more detailed breakdown of what I'd like:

1.  **Parametric Size:** The design should allow me to specify the overall size of the Chestahedron using a single parameter, let's say `size`. This will control the overall scale of the kite shapes. The current code shows `size = 30;`, but I want to make this a parameter I can change.

2.  **Kite Definition:** The code I have already defines a 'kite' module but I'd like for this to remain editable. The key is the use of the Golden Ratio to define the inner points and I don't want to re-write this functionality. I'd like the `kite` module itself to be parametric, as it is in the example.

3.  **Net Layout:** I need the three kite shapes to be arranged in a way that they form a net layout. Ideally, the kites should be connected along their edges, ready for folding. I want to preserve the orientation that each kite has in the current code, just connected to each other. Specifically, it seems like in my example they are already rotated properly and only need to have their joining edge line up.

4.  **Connected:** The current code has a tiny dot connecting the kites, but I don’t want the dot to be a separate piece, it should be integrated into the net. I don't need the dot from the current file.

5.  **Library Usage:** It would be good to be sure the output is easy to read. Please use the `BOSL2` library where possible. I think I will use that in the future, so it would be great to have this be a good example.

Could you generate an OpenSCAD file that accomplishes this?

[Assistant]
chestahedron-kites-net.scad:
```
//
// Net for the Chestahedron, kites only.
// *** Alpha software 20140530 by bobnet
// Ugly but it works...
//

// size
size = 30;

module kite (radius)
{
	fifth = 360/5;			// angle
	phi = (1+sqrt(5))/2;	// the golden ratio
	innerRadius = (radius/phi)/phi;

   hull() {
	polygon (points = [
		[0,0],
		[cos(2.5*fifth)*innerRadius, sin(2.5*fifth)*innerRadius],
		[cos(2*fifth)*radius, sin(2*fifth)*radius]
	], convexity = N);

	mirror([0,1,0])
	polygon (points = [
		[0,0],
		[cos(3*fifth)*radius, sin(3*fifth)*radius],
		[cos(3.5*fifth)*innerRadius, sin(3.5*fifth)*innerRadius]
	], convexity = N);
   }
}

// 3 kite shapes

linear_extrude(height = 1, center = true, convexity = 10, twist = 0)
rotate (a=90, v=0,1,0) color("Turquoise") kite (size);
linear_extrude(height = 1, center = true, convexity = 10, twist = 0)
rotate (a=-360/5) color("Turquoise") kite(size);
linear_extrude(height = 1, center = true, convexity = 10, twist = 0)
rotate (a=-(360/5)*2) color("Turquoise") kite(size);

// one dot to join them!!!
linear_extrude(height = 1, center = true, convexity = 10, twist = 0)
circle (r = 0.01);
```


[User]
Hey, I'm looking to get a parametric LiPo battery holder designed. I've got a few different sized batteries I want to be able to use and I'd like to be able to tweak the design to fit them perfectly, and I'd like to use OpenSCAD.

Basically, I need a rectangular box-like holder that snugly fits a LiPo battery. I need to be able to specify the battery's length, width, and height. The holder should have a lip or wall around the top to keep the battery from sliding out, and I’d also like some optional features like holes for cable ties, slots for a strap, optional thick edges to route wires, and mounting holes to attach the holder to something. I want some options for extra protection for the battery, including an optional full hard case, and I need to be able to turn the various features on and off.

Here are the things I want to be able to control via parameters:

*   `battery_length`: The length of the LiPo battery.
*   `battery_width`: The width of the LiPo battery.
*   `battery_height`: The height of the LiPo battery.
*   `wall_height`: The height of the wall around the battery. I want options for "low", "medium" or "!high!" which should map to 3, 2 and 1.5, respectively.
*   `thickness`: The thickness of the holder's walls. Should allow for a range between 1 and 3.
*   `hole`: The diameter of the mounting holes (range 0-8, with 0 meaning no hole).
*    `sunk_screws`: Yes or No, for the mounting holes to be sunk to accommodate countersunk screws.
*   `hole_distance`: The distance between the centers of the two mounting holes, set to 0 for one hole.
*   `light`: A boolean (0/1) to control a cutout in the base of the case, not sure what this is for, but if it's enabled, it should be cut out.
*   `cable_tie_hole`: Boolean (0/1) to control cable tie holes. I want them near the corners of the base, and some horizontal ones at the ends.
*   `band_hole`: Boolean (0/1) to control a strap slot on the base.
*   `thick_edge`: Boolean (0/1) to control thick edges for wire routing. I want these to be on the sides, running the length of the case.
*   `hard_case`: Boolean (0/1) that disables the wall height and band hole and creates a hard-case top.

I don't need any fancy libraries, just the built-in OpenSCAD primitives are fine. It would be awesome if you could generate a fully parametric `*.scad` file for this. Thanks!

[Assistant]
Customize_LiPo_multi_fix_holderV4.1.scad:
```
battery_length=102;
battery_height=24;
battery_width=37;
// high is not be tested it can be it will not fit in!
wall_height=2; // [3:low,2:medium,1.5:!high!]
thickness=2; // [1:3]
hole= 3; // [0:8]
sunk_screws=0; // [0:NO, 1:YES]
// set this to 0 for one hole.
hole_distance=50;
light=1; // [0:NO, 1:YES]
cable_tie_hole=1;// [0:NO, 1:YES]
band_hole=1; // [0:NO, 1:YES]
thick_edge=0; // [0:NO, 1:YES]
//This will only disable wall height and band hole!
hard_case=0; // [0:NO, 1:YES]

module Akku(){
cube([battery_length,battery_width,battery_height],center=true);
}

module Case(L,B,H)
{
difference(){
cube([L,B,H],center=true);
Akku();

if (hard_case==0)
{
if(battery_length > 100)
{
translate([25,0,thickness+battery_height/wall_height]){
cube([L,B+0.5,H],center=true);
}
} else {
translate([battery_length/4,0,thickness+battery_height/wall_height]){
cube([L,B+0.5,H],center=true);
}
}
}

if(light==1)
{
translate([-L/2,0,0])
{
cube([L,battery_width-thickness*4,battery_height-thickness*4],center=true);
}
}

if (hard_case==1)
{
translate([L/2,0,0])
{
cube([L,battery_width,battery_height],center=true);
}
}
translate([L/2,battery_width/2-thickness*1.5,0])
{
cube([L,thickness*3,battery_height-thickness*2],center=true);
}
translate([L/2,-battery_width/2+thickness*1.5,0])
{
cube([L,thickness*3,battery_height-thickness*2],center=true);
}

if(cable_tie_hole==1)
{
translate([battery_length/2-thickness*3,battery_width/2-1.5,-battery_height/2-0.1])
{
cube([5.5,3,thickness*2],center=true);
}
translate([battery_length/2-thickness*3,-battery_width/2+1.5,-battery_height/2-0.1])
{
cube([5.5,3,thickness*2],center=true);
}
translate([-battery_length/3,battery_width/2-1.5,-battery_height/2-0.1])
{
cube([5.5,3,thickness*2],center=true);
}
translate([-battery_length/3,-battery_width/2+1.5,-battery_height/2-0.1])
{
cube([5.5,3,thickness*2],center=true);
}

translate([battery_length/2-thickness*3,0,-battery_height/2])
{
cube([5.5,battery_width,thickness],center=true);
}
translate([-battery_length/3,0,-battery_height/2])
{
cube([5.5,battery_width,thickness],center=true);
}
}

if(thick_edge==1)
{
if(battery_length/5 > 20)
{
translate([battery_length,battery_width/2,0])
{
cube([battery_length+20,thickness*3,battery_height-thickness*2],center=true);
}
translate([battery_length,-battery_width/2,0])
{
cube([battery_length+20,thickness*3,battery_height-thickness*2],center=true);
}
} else{
translate([battery_length,battery_width/2,0])
{
cube([battery_length+battery_length/5,thickness*3,battery_height-thickness*2],center=true);
}
translate([battery_length,-battery_width/2,0])
{
cube([battery_length+battery_length/5,thickness*3,battery_height-thickness*2],center=true);
}
}
}

if (hard_case==0)
{
if(band_hole==1)
{
translate([battery_length/5,0,-battery_height/2+1.5])
{
if(battery_length > 60)
{
cube([20,battery_width+thickness*2+1,3],center=true);
} else {
cube([battery_length/3,battery_width+thickness*2+1,3],center=true);
}
}
}
}

if (hard_case==1)
{
translate([battery_length/2-thickness*3,0,0])
{
cube([3,20,battery_height+20],center=true);
}
}

if(light==1)
{
translate([battery_length/5,battery_width/4,-battery_height/2-0.1])
{
cube([battery_length/3,battery_width/3,thickness*2],center=true);
}
translate([-battery_length/6,-battery_width/4,-battery_height/2-0.1])
{
cube([battery_length/4,battery_width/3,thickness*2],center=true);
}
translate([battery_length/5,-battery_width/4,-battery_height/2-0.1])
{
cube([battery_length/3,battery_width/3,thickness*2],center=true);
}
translate([-battery_length/6,battery_width/4,-battery_height/2-0.1])
{
cube([battery_length/4,battery_width/3,thickness*2],center=true);
}
}

translate([hole_distance/2,0,-battery_height/2-thickness-0.1])
{
cylinder(d=hole,h=thickness+0.5,$fn=20);
}
if(sunk_screws==1)
{
translate([hole_distance/2,0,-battery_height/2-hole/2])
{
cylinder(d1=hole,d2=hole*2,h=hole/2,$fn=20);
}
}
translate([-hole_distance/2,0,-battery_height/2-thickness-0.1])
{
cylinder(d=hole,h=thickness+0.5,$fn=20);
}
if(sunk_screws==1)
{
translate([-hole_distance/2,0,-battery_height/2-hole/2])
{
cylinder(d1=hole,d2=hole*2,h=hole/2,$fn=20);
}
}
}
}

if(hole!=0)
{
difference(){
translate([hole_distance/2,0,-battery_height/2-thickness])
{
cylinder(d=hole+6,h=thickness,$fn=50);
}
translate([hole_distance/2,0,-battery_height/2-thickness-0.1])
{
cylinder(d=hole,h=thickness+0.5,$fn=20);
}
translate([battery_length/2-thickness*3,0,-battery_height/2])
{
cube([5.5,battery_width,thickness],center=true);
}
if(sunk_screws==1)
{
translate([hole_distance/2,0,-battery_height/2-hole/2])
{
cylinder(d1=hole,d2=hole*2,h=hole/2,$fn=20);
}
}
}

difference(){
translate([-hole_distance/2,0,-battery_height/2-thickness])
{
cylinder(d=hole+6,h=thickness,$fn=50);
}
translate([-hole_distance/2,0,-battery_height/2-thickness-0.1])
{
cylinder(d=hole,h=thickness+0.5,$fn=20);
}
translate([-battery_length/3,0,-battery_height/2])
{
cube([5.5,battery_width,thickness],center=true);
}
if(sunk_screws==1)
{
translate([-hole_distance/2,0,-battery_height/2-hole/2])
{
cylinder(d1=hole,d2=hole*2,h=hole/2,$fn=20);
}
}
}
}

Case(battery_length+thickness*2,battery_width+thickness*2,battery_height+thickness*2);

```


[User]
I'd like to be able to create a tapered cone, like a lampshade. The current code is pretty simple: it takes a height, a radius for the base, and a radius for the top, and then creates a cylinder with those dimensions. The top radius is smaller than the bottom, of course, to create a tapered cone.

I'd like to add some more features to this. I'd like the cone to be hollow, so I'll need a variable to specify the wall thickness. I'd also like to be able to add a series of evenly-spaced rectangular cutouts around the base of the cone. I think I'd need parameters for the number of cutouts, and then the width and height of the cutouts themselves. Finally, let's add one more parameter for how far up the cone the cutouts extend. So, rather than starting at the bottom of the cone and ending at some specified height, the cutouts will start at the base and extend up for a specific vertical distance.

I'm not using any libraries right now, but it would be fine if you wanted to use any common ones in your solution like BOSL or MCAD.

[Assistant]
cone.scad:
```
//Enter height of cone.
height =75; // [10:150]

//Enter the first radius.
radius =20; // [5:75]

//Enter the second radius.
radius2 =5; // [0:75]

cylinder ( h=height, r1=radius, r2=radius2, $fn=100 ) ;

```


[User]
I'd like a drinking glass, but with some fun features, please! I'd like it to be parametric so I can easily change its size and look later.

First, the main body should be a truncated cone, like the current code. However, instead of using a `difference()` to make the wall, I'd like a `linear_extrude` of a 2D shape, where the 2D shape is just a ring. This will let me vary the wall thickness a bit more easily.

The key parameters I want are:
*   `height`: the overall height of the glass
*   `radius_bottom`: the radius of the bottom of the glass
*   `radius_top`: the radius of the top of the glass
*   `wall_thickness`: the thickness of the glass walls
*   `lip_height`: the height of a small lip at the top of the glass
* `lip_thickness`: the thickness of that lip

I'd also like a few extra features.

I'd like an optional spiral twist to the glass. This would be controlled by a `twist_angle` parameter. If the angle is 0, there should be no twist. If the angle is positive, it should twist clockwise from bottom to top, and if negative, it should twist counter-clockwise.

Finally, let's add some optional dimples to the outside surface of the glass. This should be controlled by a few parameters: `dimple_radius`, `dimple_depth`, and `dimple_count`, the radius of the dimples, how deep they are, and how many of them are on the circumference of the glass.

I'd like the code to be well-commented and use the `rotate_extrude` and `linear_extrude` features to construct most of the glass, with the understanding that `rotate_extrude` can produce a full circle when supplied a two-dimensional path to rotate around a central axis of revolution (in this case, the Z axis).

I'm looking forward to what you come up with! Thanks!

[Assistant]
gobelet.scad:
```
// Move the height of  the glass.
height =90; // [10:150]

// Move the first radius (bottom).
radius_bottom =27; // [5:75]

// Move the second radius (top).
radius_top =38; // [0:75]

// Move the thickness percent
thickness_percent=5; // [5:100]

thickness = radius_top*thickness_percent/100;

difference() {
cylinder ( h=height, r1=radius_bottom, r2=radius_top, $fn=100 ) ;
translate(v = [0, 0, 3])

cylinder ( h=height+thickness*1.5, r1=radius_bottom-thickness, r2=radius_top-thickness, $fn=100 ) ;
 }

```


[User]
Hi, I'm looking for some help designing a parametric OpenSCAD model for a regolith-shielded dugout structure. I'm envisioning a series of angled struts that form the roof, which are then covered with Martian regolith for radiation shielding.

Here are the basic parameters I'd like to be able to control:

*   **`width`**: The width of a single strut (like the beam width).
*   **`length`**: The longest outside length of a strut - essentially the length from where it starts on the ground up to the apex of the roof.
*  **`thickness`**: The transverse thickness of a strut.
*   **`bin_width`**: The width of the bins (the compartments that hold the regolith) along the length of the strut.
*   **`wall_thickness`**: The thickness of the walls of the bins.
*   **`theta`**: The angle the roof makes with the ground.
*   **`num`**: The number of struts in the roof.

I'd like to be able to choose between a few different assembly modes:

*   **`model`**: This would generate a full model, including the struts and simplified representations of the front and back of the dug out.
*  **`tent`**: This option would generate just the angled strut roof without the dugout ends.
*   **`sheet`**: This should output all of the struts laid flat next to one another for easy printing.
*   **`struts`**: This should output individual struts, spaced slightly apart, for printing.

I also want the design to calculate some useful info, like the minimum digging depth required to acquire the necessary regolith to fill the bins on the struts, and the depth needed to create the angled berms of regolith at the front and back of the dugout. So I need the design to calculate:

* **`strut_depth`**: minimum depth required to dig to get enough soil to fill a pair of struts.
* **`cone_depth`**: The depth you need to dig to get enough earth for the mounds at the front and back of the structure.

It would be really helpful if you could generate all of the code (all of the necessary SCAD files), and let me know if you're using any external libraries so I can download them. Thanks!

[Assistant]
mars_challenge_-_for_customizer_1.2.scad:
```
//Customizable struts for regolith-shielded dugout houses
//Ari M. Diacou - June 2014
//Published at: http://www.thingiverse.com/thing:348765
//Shared under Creative Commons License: Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
//see http://creativecommons.org/licenses/by-sa/3.0/

// preview[view:south west, tilt:top diagonal]

//Width of a strut
width=6;
//Longest outside length of a strut
length=30;
//Transvers thickness of a strut
thickness=4;
//How wide should the bins be in the length direction
bin_width=4;
//How thick should the walls of the bins be
wall_thickness=.3;
//What is the angle the roof makes with the ground
theta=35;
//Do you want to print a a model, assembeled roof, a sheet of struts, or individual struts?
assembly="model"; // [model, tent, sheet, struts]
//How many struts to print?
num=10;

/*[Hidden]*/

///// Derived Scalars /////
epsilon=0+0.001;//Used to ensure manifoldness
base=length*cos(theta); //edge of roof to roof ridge
height=length*sin(theta); //height of roof ridge from surface
ep=epsilon; //Who actually likes typing all those characters?
inter_strut_distance = sqrt((3*wall_thickness)*(width/10)); //geometric mean used to automatically space the struts a small distance, using 2 definitions of small.
strut_area_approx=thickness*(length-thickness/2);//An approximation of the area of a strut
strut_depth=strut_area_approx/(2*base);//The minimum depth you need to dig to get enough soil to fill a pair of struts
cone_depth=(3.1415/6)*(base*height)/(width*num);//The depth you need to dig to get enough earth for the mounds at the front and back of the structure
echo("You will need to dig down at least ",(strut_depth+cone_depth)," units to have enough earth for this structure");

/////// MAIN() ///////////

if(assembly=="model"){
	tent(num);
	back();
	front();
	}
if(assembly=="tent"){
	tent(num);
	}
if(assembly=="struts"){
	lineupx(num,inter_strut_distance+width)
		printable_strut();
	}
if(assembly=="sheet"){
	lineupx(num,width-ep)
		printable_strut();
	}

///// FUNCTIONS /////////

module front(){
	difference(){
		cylinder(h=height,r1=base,r2=0,center=false);
		translate([-base-ep,-base-ep,-ep])
			cube([base+ep,2*(base+ep),height+2*ep],center=false);
		}
	}

module back(){
	translate([-num*width,0,0]){
		difference(){
			cylinder(h=height,r1=base,r2=0,center=false);
			translate([0,-base-ep,-ep])
				cube([base+ep,2*(base+ep),height+2*ep],center=false);
		scale([1,.5,1])
			rotate([0,90,0])
				cylinder(h=2*(base+ep),r=.8*(height-thickness/cos(theta)),center=true);
			}
		}
	}

module tent(num){
	lineupx(num,width-ep) pair();
	}

module printable_strut(){
	translate([0,0,thickness])
		rotate([-theta,0,0])
			translate([2*width,base/2,-height/2])
				left();
	}

//module copy_printable_strut(){
//	translate([
//		2*width,
//		length*(-0.5+cos(theta))-2*thickness*sin(theta),
//		-height*sin(theta)+(-1+sin(theta))*thickness])
//			rotate([-theta,0,0])
//				left();
//	}

//module bottom(){
//	delta=thickness-wall_thickness;
//	intersection(){
//		preform();
//		translate([0,delta*cos(theta),-delta*sin(theta)]) preform();
//		}
//	}

module bottom2(){
	delta=thickness-wall_thickness;
	difference(){
		preform();
		translate([0,-wall_thickness*cos(theta),wall_thickness]) preform();
		}
	}

module pair(){
	translate([0,ep,0]) left();
	translate([0,-ep,0])right();
	}

module left(){
	union(){
		bottom2();
		difference(){
			preform();
			bins();
			}
		}
	}

module right(){
	mirror([0,1,0])
		left();
	}

module lineupy(num, space) {
   for (i = [1 : num])
     translate([ 0, -space*i, 0 ]) child();
 }

module lineupx(num, space) {
   for (i = [1 : num])
     translate([-space*i,0,0]) child();
 }

module show_regolith(){
	intersection(){
		preform();
		bins();
		}
	}

module bins(){
	num_bins=floor(base/(bin_width+wall_thickness));
	diff=base-num_bins*(bin_width+wall_thickness);
	lineupy(num_bins, bin_width+wall_thickness)
		//color("DarkRed")
			translate([wall_thickness,-diff/2,0])
				cube([width-2*wall_thickness,bin_width,height]);
	}

module preform(){
	difference(){
		translate([0,-length*cos(theta)+thickness*sin(theta),-thickness*cos(theta)])
			rotate([theta,0,0])
				cube([width,length,thickness],center=false);

		//color("blue")
			translate([-ep,-length-ep,-thickness])
				rotate([0,0,0])
					cube([width+2*ep,2*length,thickness],center=false);

		//color("red")
			translate([-ep,thickness,-length])
				rotate([90,0,0])
					cube([width+2*ep,2*length,thickness],center=false);
		}
	}
```


[User]
I'd like to design a customizable "ball in a cage" type of structure, but with a twist (literally!). I saw this cool design online, and it uses OpenSCAD, which I'm trying to learn.

Basically, I want a cage made of four vertical columns that are twisted, with one or more spherical balls trapped inside. The user should be able to adjust the following things:

*   **Ball Diameter:** I need to be able to specify the diameter of the ball, or balls, in millimeters. I'd like to be able to pick from a dropdown of 10, 15, 20, 25, or 30 mm.
*   **Number of Balls:** I'd like to control how many balls there are, with a dropdown to select 1, 2, 3, 4, or 5 balls.
*   **Twist Angle:** I want to be able to set the total twist angle in the vertical columns, in degrees. I'm thinking options like 0, 90, 180, 270, and 360.
*   **Twist Direction:** I should be able to pick whether the twist is right-handed or left-handed. Maybe a dropdown with "Right Hand" and "Left Hand" labels.
*   **Top and Bottom Size:** I need to set the size of the top and bottom of the cage. It should be a multiple of the column width, with a range of 1 to 20 times the column width.
*   **Print Resolution:** Finally, a way to control the detail, probably just three options, "Low", "Standard", and "High", corresponding to 0.30, 0.20, and 0.10 respectively (likely used for `slices` in the `linear_extrude` function).

The columns should be square in cross section. I suppose the width of the columns should scale with the ball size (maybe 40% of the ball radius). The distance between the columns and the balls needs a little bit of clearance, say, 5% of the ball radius. The vertical spacing between the balls should also account for this clearance, and there should be some extra empty space at the top and bottom of the cage.

The top and bottom should be square and match the dimensions of the columns, I think, with the twist matched to the columns at their respective heights. I'd expect the top and bottom pieces to also have the column width as a base for their sizing.

I think the design would be much more usable if all the user-adjustable parameters were exposed as customizer options.

[Assistant]
custom_ball_cage.scad:
```
//
//	Customized Ball(s) in a Cage with a Twist
//		Steve Medwin
//		May 31, 2014
//
$fn=100*1;	// set overall resolution
//
//	Customizing

//How big are the balls (in mm)?
Diameter=20;	//	[10,15,20,25,30]
//How many balls?
Balls=2;	//	[1,2,3,4,5]
//How many degrees of twist in center section?
Twist=90;	//	[0,90,180,270,360]
//Which twist direction?
Direction=-1;	//[-1:Right Hand,1:Left Hand]
//Size of top (multiple of column width)
Top=4;		//	[1:20]
//Size of botton (multiple of column width)
Bottom=4;	//	[1:20]
//Detail in print
Resolution=0.20;	//[0.30:Low,0.20:Standard,0.10:High]

Radius=Diameter/2;
Clearance=Radius*0.05;	// between ball and columns
Width=Radius*0.4;	// column side scales with ball size
Height=Diameter*(Balls+2);	// height of center section

Side=2*cos(45)*(Radius+Clearance+Width/sin(45));
Column=Side/2-Width/2;	//position of column center relative to 0,0
Gap=(Height-(Diameter*Balls+Clearance*(Balls-1)))/2; // center balls

// Define 2D columns
module columns(){
	translate([ Column, Column,0]) square([Width,Width],center = true);
	translate([ Column,-Column,0]) square([Width,Width],center = true);
	translate([-Column, Column,0]) square([Width,Width],center = true);
	translate([-Column,-Column,0]) square([Width,Width],center = true);
	}

//	Make 3D columns
linear_extrude(height = Height, center = false, convexity = 10, twist = Direction*Twist, slices=Height/Resolution)
	columns();

//	Add balls
for (i=[1:Balls])
	{
	    translate([0,0,Gap+Radius+(i-1)*(Diameter+Clearance)]) sphere(r=Radius);
	}

//	Add bottom
rotate(a=[0,180,0])
linear_extrude(height = Width*Bottom, center = false, convexity = 10, twist = Direction*Twist*Width*Bottom/Height, slices=(Width*Bottom)/Resolution)
	square([Side,Side],center=true);

//	Add top
translate([0,0,Height])
linear_extrude(height = Width*Top, center = false, convexity = 10, twist = Direction*Twist*Width*Top/Height, slices=(Width*Top)/Resolution)
	square([Side,Side],center=true);

```


[User]
I want to design a GoPro mount that attaches to a standard microphone clip, like the kind you'd find on a mic stand. I've seen a design that uses a specific Musician's Gear mic clip, but I want something a bit more flexible. I'd like to be able to use different mic clips and also adjust how far the GoPro mount sticks out from the base.

Here are my requirements:

1.  **Mic Clip Interface:** The mount should have a circular base that fits inside a mic clip, but the size of that base should be adjustable to accommodate different mic clip inner diameters. I need to be able to specify the outer diameter of the base, the diameter of the hole for the mic stand screw, and the thickness of the insert.

2.  **GoPro Mount:** It needs a female GoPro mount, like the one from Thingiverse thing:6154. However, instead of importing an STL file like the linked design does, could we please use a parametric 3-finger style mount using the BOSL library, as I'd like to tweak dimensions down the road.

3.  **Adjustable Height:** The height of the GoPro mount *above* the mic clip base should be adjustable so I can fine-tune how far the GoPro sticks out.

4.  **Material:**  I'll be 3D printing this, so the design should be printable without support material, with the mount standing on its end.

5.  **Orientation Flexibility:** It would also be great if the GoPro mount could be oriented so that the rotation axis of the GoPro and the rotation axis of the mic clip are perpendicular to one another. I'm not sure how to make it printable without support, but perhaps the design could be in two pieces or even include a ball joint. Could you explore a couple of options?

6.  **Parametric:**  Everything should be parametric; I want to be able to change all of the dimensions using the customizer in OpenSCAD. I need parameters for:
    *   `baseOD`: the outer diameter of the circular insert that goes into the mic clip.
    *   `holeID`: the diameter of the hole for the mic stand screw.
    *   `thickness`: the thickness of the insert.
    *   `height`: the height of the GoPro mount above the mic clip base.
    *   `mount_orientation`: variable to specify if the GoPro mount is parallel to the mic clip or perpendicular. If perpendicular, explore options using the two-piece and ball joint solutions I mentioned.
    * `mount_type`: let the user select from "standard" or "extended" to vary the mount's length

I'd also like to make sure to include a variable for `$fn` to make circles more detailed, and the default value should be 96. I don't think I need any other external libraries.

Could you generate the OpenSCAD code for me?

[Assistant]
GoPro_mic_stand_mount.scad:
```
//
// A mount for a GoPro using a mic clip
// designed by James Brown (JAMESdotBROWNatBLDESIGNdotCOM)
//

// Musician's Gear Heavy Duty Basic Mic Clip
// Manufacturer part #: MS103-MG
// $2 each on Amazon w/ free shipping

// incorporates thing 6154 GoProHD Mount (Female)
// see http://www.thingiverse.com/thing:6154

// license: creative commons, attribution - non-commercial - share alike

// printed at 0.3mm layer height w/ no support on Solidoodle 2

//
// The following values are adjustable in the customizer
//

// Outside diameter of the base mic clip insert (measured) default:24
baseOD = 24;

// Diameter of the hole in the mic clip (measured; okay to be a little big) default:8
holeID = 8;

// Thickness of the mic clip insert (measured) default:5.5
thickness = 5.5;

// Height from the center of the hole to the base of the GoPro mount (allow clearance for mount to rotate around the mic clip base) default:18
height = 18;

//
// End customizer
//

//
// the following values are constants and should not be adjusted
// they have a +0 on the end so the customizer will not allow
// the user to set them
//

mountLen = 46 +0;	// the length of thing 6154, the GoPro mount

$fn=96 +0;		// how detailed to make circles

// needs to stand on end to have a hope of printing w/o supports
rotate([90,0,0])
{
	// import the existing GoPro mount
	// and position it correctly to mate with the other piece
	translate([height, (mountLen-baseOD)/2, thickness/2])
		rotate([0,90,0])
		import("GoProHD_mount.STL");	// thing 6154 GoProHD Mount (Female)

	difference()
	{
		// the hull call creates the roughly triangular piece that
		// gets inserted into the mic clip base

		// if you are not using hull, learn about it!
		// hull is an awesome tool for creating complex joined
		// shapes from two (or more) basic shapes
		hull()
		{
			// use the '#' prefix on one (or both) of the cylinder
			// calls below to see what hull is doing behind the scenes

			// the bottom round part of the insert
			cylinder(h=thickness, r=baseOD/2);

			// a cylinder as long as the GoPro mount
			translate([height, (mountLen-baseOD)/2, thickness/2])
				rotate([90,0,0])
				cylinder(h=mountLen, r=thickness/2, center=true);
		}

		// hole for mounting screw
		translate([0,0,-1])
			cylinder(h=thickness+2, r=holeID/2);

	}
}

```


[User]
Okay, I'm looking to design a custom quick release plate for a Manfrotto 484rc2 ball head, and I'd like to be able to generate it using OpenSCAD. I've seen a design for a similar plate but it wasn't parametric enough for my needs, I would like the plate to be generated from scratch.

Here's what I need:

**Base Plate:**
*   The base needs to have a specific tapered profile that interfaces with the ball head, much like the original plate. The width of the plate at the top (where it fits into the head) should be around 37.5mm, while the base needs to be around 42.6 mm wide. The overall depth of the plate should be 52.3mm, and the total height should be 9.8mm. I need to be able to adjust these base dimensions so they can be updated if the physical dimensions of the head change, or if I'd like to change the dimensions to test out a different design.
*   I need to be able to specify extra width on either side of the base plate, which will extend past the original 52.3mm depth. I would like separate variables for the extra width on the left and right sides, and I want to be able to set those to 0 if no extra width is needed. I need this extra width to be adjustable from 0 to 150 mm on each side. I need the variable names to be `extra_left` and `extra_right`.

**Holes:**
*   I'll need to be able to add holes to the plate, and I need to be able to control the type, diameter, and position of these holes. There should be at least three hole positions that I can specify, one for the middle of the original plate, one for the extra width on the left side, and one for the extra width on the right side.
*   Each hole position should have the following options:
    *   **Standard:** A counterbored hole suitable for a Manfrotto 200PL thumbscrew. The counterbore should be 16mm diameter and 1 mm deep, with a through hole of 10mm.
    *   **3/8 tap:** A pilot hole suitable for tapping a 3/8" thread.
    *   **1/4 tap:** A pilot hole suitable for tapping a 1/4" thread.
    *   **Prosilica:** A pair of 1.7mm holes spaced 26mm apart, centered 9mm to the left of the plate center, to mount an Allied/Prosilica GC650 camera (and similar cameras). This needs to be *two* holes, with appropriate placement.
    *   **Custom:** A hole where I can specify a diameter and offset from the center for the hole.
    *   **None:** No hole at that position.
*   I need to be able to independently specify the hole style for each of the three positions (left, middle, right).
*   For the custom hole style, I need to specify the hole diameter and offset from the plate center in x and y.

**General Requirements:**

*   I need the code to be parametric, so I can easily adjust the dimensions and hole configurations through variables.
*   I'd prefer if you didn't include comments about the variables that aren't shown in the user interface. I'd also prefer if the variables could be grouped, or categorized in some way, to make it easier to browse and understand the customization options.
*   I don't need any special positioning to make it printable as I can handle that myself. The primary concern is generating the correctly dimensioned object.
*   I'm not looking for a specific library, so please don't add any library dependencies.

I think that covers everything. Let me know if you have any questions.

[Assistant]
manfrotto484rc2-plate-wide.scad:
```
//
// manfrotto 484rc2 quick plate replacement, with variable width
//
// Copyright 2013-2014 Sébastien Roy (roys@iro.umontreal.ca)
// Licence: public domain
//

/* [General] */

// Extra width on one side
extra_left=120; // [0:150]

// Extra width on the other side
extra_right=80; // [0:150]

/* [Left Hole] */

left_hole_style="standard"; // [standard,3/8 tap, 1/4 tap,prosilica,custom,none]
// (used if style is "custom")
left_hole_diameter=20;
left_hole_x_offset=0;
left_hole_y_offset=0;

/* [Middle Hole] */

middle_hole_style="standard"; // [standard,3/8 tap,1/4 tap,prosilica,customm,none]
// (used if style is "custom")
middle_hole_diameter=20;
middle_hole_x_offset=0;
middle_hole_y_offset=0;

/* [Right Hole] */

right_hole_style="standard"; // [standard,3/8 tap,1/4 tap,prosilica,custom,none]
// (used if style is "custom")
right_hole_diameter=20;
right_hole_x_offset=0;
right_hole_y_offset=0;

// to stop customizer
module nop() { }

length = 2; //[1:32]
width = 2; //[1:32]
type = 9.6; //[9.6:Brick, 3.2:Tile, 19.2:Double Brick]
flat = 0; //[0:No, 1.9:Yes]
/* [Hidden] */

//
// General dimensions of the plate
//
// "largeur" determines how well the plate will attach to the head.
// "profondeur" is the width of the plate.
//
largeur=42.6;
largeurtop=37.5;
profondeur=52.3;
hauteur=9.8;

//
// un solide "tappered" en x,
// de dimension largeur x prodondeur x hauteur
//
module tappered(largeur=30,largeurtop=20,profondeur=40,hauteur=10,head=2,base=3) {
      off=(largeur-largeurtop)/2;
	translate([0,profondeur,0])
	rotate([90,0,0])
	linear_extrude(height=profondeur)
		polygon(points=[
			[0,0],
			[largeur,0],
			[largeur,base],
			[largeurtop+off,hauteur-head],
			[largeurtop+off,hauteur],
			[off,hauteur],
			[off,hauteur-head],
			[0,base]
		]);
}

//
// solid plate
//
module m_base(extra1=0,extra2=0) {
	translate([0,-extra2,0]) tappered(largeur,largeurtop,profondeur+extra1+extra2,hauteur);
}

//
// inside material to remove from plate
//
module m_interieur(extra1=0,extra2=0) {
	translate([4,3,-1]) tappered(largeur-8,largeurtop-6,profondeur-6,hauteur-3,0,0);
	translate([4,profondeur,-1]) tappered(largeur-8,largeurtop-6,extra1-3,hauteur-3,0,0);
	translate([4,0*profondeur-extra2+3,-1]) tappered(largeur-8,largeurtop-6,extra2-3,hauteur-3,0,0);
}

//
// side material to be removed from the plate
//
module m_notch(extra1=0) {
	w=3;
	translate([-5,-5,-4]) cube([largeur-17.6+5,10+extra1,hauteur]);
}

//
// one hole in the plate. r is the radius,
// pos is the (x,y) position on the plate (leave z at 0).
// the (0,0) position is the center of the plate.
//
module m_trou(r=5,pos=[0,0,0]) {
	translate([largeur/2,profondeur/2,0]+pos) cylinder(h=hauteur*2,r=r,$fn=64);
}

module m_trou_counter(r=5,rr=16/2,hh=1,pos=[0,0,0]) {
	translate([largeur/2,profondeur/2,0]+pos) cylinder(h=hauteur*2,r=r,$fn=64);
	translate([largeur/2,profondeur/2,0]+pos) cylinder(h=hauteur-4+hh,r=rr,$fn=64);
}

module m_holes(style="standard",offset=[0,0,0],dia) {
	if( style=="standard" ) {
		m_trou_counter(10/2,16/2,1,offset);
	} else if( style=="3/8 tap" ) {
		m_trou(5/16*25.4/2,offset);
	} else if( style=="1/4 tap" ) {
		m_trou(13/64*25.4/2,offset);
	} else if( style=="prosilica" ) {
		m_trou(1.7,[-9,-13,0]+offset);
		m_trou(1.7,[-9,13,0]+offset);
	} else if( style=="custom" ) {
		m_trou(dia/2,offset);
	}
}

//
// position the following model to make it printable
// this is set for up=z-axis printing (ex: mendelmax)
// Change it for your printer...
//
module m_printable() {
	translate([-largeur/2,profondeur/2,hauteur])
	rotate([180,0,0])
	child(0);
};

//
// Basic complete plate, without holes
//
module m_manfrotto484() {
	difference() {
		m_base(extra_left,extra_right);
		m_interieur(extra_left,extra_right);
		m_notch(0);
		translate([0,profondeur,0]) m_notch(0/*extraprof*/);
/*
		if( extra_left>20 ) {
			m_trou(r=5,pos=[0,extra_left,0]);
		}
		if( extra_right>20 ) {
			m_trou(r=5,pos=[0,-extra_right,0]);
		}
*/
	}
}

//
// example of a plate with 4 holes.
// Change as needed.
//
module m_manfrotto484_generic() {
	difference() {
		m_manfrotto484();
		m_holes(middle_hole_style,[middle_hole_x_offset,middle_hole_y_offset,0],middle_hole_diameter);
		if( extra_left>20 ) m_holes(left_hole_style,[left_hole_x_offset,left_hole_y_offset+extra_left,0],left_hole_diameter);
		if( extra_right>20 ) m_holes(right_hole_style,[right_hole_x_offset,right_hole_y_offset-extra_right,0],right_hole_diameter);
		//m_trou(2.5,[10,0,0]);
		//m_trou(2.5,[0,15,0]);
		//m_trou(2.5,[0,-15,0]);
	}
}

//
// plate made for Allied/Prosilica GC650 (and similar cameras)
// the holes separation is 26mm.
//
module m_manfrotto484_prosilica() {
	difference() {
		m_manfrotto484();
		m_trou(1.7,[-9,-13,0]);
		m_trou(1.7,[-9,13,0]);
	}
}

m_printable()  m_manfrotto484_generic();

```


[User]
Hey, so I'm trying to make a customizable S-hook for my shower, and I'd like it to be parametric.  I have a basic design I made, but I'd like to get something a bit more polished with some more options.

My current version uses two partial circles, or rather, 3/4ths circles, connected by a bar. Here are the basic parameters I want to be able to set: the diameter of the first hook, the diameter of the second hook, and the diameter of the bar connecting them. I was using `hook_1_diameter`, `hook_2_diameter`, and `bar_diameter` as variables for those. I was hoping I could make that bar cylindrical instead of square, like on most of the customizable s-hooks out there.

I was also using `thick` to determine the thickness of the hook. This is technically the diameter of the cylinder that sweeps along the curve to form the hooks in the code I have, which is a little bit confusing, so maybe it would be better to just call that `thickness`.

I'd like to be able to set the `fn` variable as well for the smoothness of the curve.

Could you write an OpenSCAD file that generates this for me using those parameters? I'd also like to see if you could use the BOSL2 library to make the code a bit cleaner, if that's alright.

[Assistant]
s-hook.scad:
```
hook_1_diameter = 32 ; // [10:100]
hook_2_diameter = 20 ; // [10:100]
bar_diameter = 5 ;     // [3:12]

$fn = 20 ;	      //  [20:120]

SHook(hook_1_diameter / 2, hook_2_diameter / 2, bar_diameter) ;

module SHook(r1, r2, thick) {
    three_quarter_circle(r1, thick) ;

    translate([(r1 + r2 + thick) *  -sin(45), (r1 + r2 + thick) * sin(45), thick])
    rotate([180, 0, -45])
    three_quarter_circle(r2, thick) ;
}

module three_quarter_circle(radius, thick) {
    difference() {
        translate([0, 0, thick/2])
        rotate_extrude()
        translate([radius + thick/2, 0, 0])
        circle(r=thick/2) ;

        translate([0, 0, -1])
        cube([radius + thick + 1, radius + thick + 1, thick + 2]) ;

        rotate([0, 0, 45])
        translate([0, 0, -1])
        cube([radius + thick + 1, radius + thick + 1, thick + 2]) ;
    }
}
```


[User]
Hey there, I'm looking to get a customizable wire loom clip designed in OpenSCAD. I've got some specific requirements and I'd like it to be parametric so I can easily adjust it later. Basically, I need a clip that can hold a variable number of wires, with a configurable wire diameter and spacing.

The basic structure will be a rectangular body with circular cutouts for each wire. The number of cutouts should be an adjustable parameter, along with the wire diameter and the distance between the wires. On each end, there will be a sort of tab or eye that has a rectangular cutout in the middle. The wire should extend a certain percentage past the clip body, which should also be adjustable. Finally, the overall thickness of the part should also be a parameter. I'm thinking a few mm of thickness will be fine, maybe 2.5 to start, but I'd like to be able to change that.

I'd also like to be able to adjust the size of the tabs on the ends as well. I was thinking of calling these "border" and "reveal". So the tab size should be computed based on wire diameter, reveal, and border. The hole in the tab, I was thinking, would be derived based on `border`.

I need this to be a single SCAD file ideally, but if it needs to be broken into multiple files that's okay. If you use a library, I'd prefer something popular like BOSL, BOSL2, or MCAD, but I'm not too picky. It's not a complicated design, so it could probably be done with just core OpenSCAD.

Here are the initial parameters I was thinking of:

*   `dia`: Wire diameter (e.g., 7.85mm)
*   `count`: Number of wires (e.g., 4)
*   `spacing`: Spacing between wires (e.g., 1.2mm)
*  `border`: Border thickness around the tabs, (e.g., 2mm)
*   `reveal`: Percentage of wire extending beyond the clip (e.g., 18%)
*   `thickness`: Overall thickness of the clip (e.g., 2.5mm)

Let me know what you think!

[Assistant]
sparkplug_cable_clip.scad:
```
// in mm
dia=7.85;

count=4;

// in mm
spacing=1.2;

// in mm
border=2;

// percent of wire that extends beyond clip
reveal=18;

// in mm

// in mm
thickness=2.5;

/* [hidden] */
tab_size=(dia*(100-reveal)/100)+border;
tab_hole=tab_size-(border*2);

module clip_thing() {
	tab_thickness=thickness;//border;
	difference() {
		cube([tab_size,tab_size,tab_thickness]);
		translate([tab_hole/2,border,-1]) cube([tab_hole,tab_hole,tab_thickness+2]);
	}
}

union() {
	translate([-tab_size,0,0]) clip_thing();
	translate([(count*dia)+((count-1)*spacing)+(border*2),0,0]) clip_thing();

	difference() { // the clip
		cube([(count*dia)+((count-1)*spacing)+(border*2),(dia*(100-reveal)/100)+(border),thickness]); // the body
		translate([(border+(dia/2)),((dia/2)*(100-reveal)/100),0]) for(x=[0:count-1]){ // the wires
			translate([x*(dia+spacing),0,-1]) cylinder(r=dia/2,h=thickness+2,$fn=16); // a wire
			echo("wire min clip width=",(dia*(100-reveal)/100));
			translate([(x*(dia+spacing))-((dia*(100-reveal)/100)/2),-dia,-1]) cube([(dia*(100-reveal)/100),dia,thickness+2]); // cut off sharp edges
		}
	}
}
```


[User]
Hi, I need help creating an OpenSCAD design for some pegs I need to print. I've attached my current attempt, but it's not very flexible and I'd like a more parametric design, including some features I'm missing.

Essentially, I need a peg that fits into a hole in the side of a piece of furniture, like a wardrobe or bookcase. The peg should have a cylindrical portion that goes into the hole, a wider head to prevent it from going all the way through, and a little "tail" that I can grab.

Here are the key dimensions I need to be able to adjust:

*   **`hole_diameter`**: The diameter of the hole the peg will fit into.
*   **`hole_deep`**: The depth of that hole.
*   **`peg_length`**: The length of the main cylindrical section that goes into the hole.
*   **`head_diameter`**: The diameter of the head of the peg (the part that stops it from going through). I want this to be slightly larger than the hole diameter.
*   **`head_thickness`**: The thickness of the peg head.
*   **`tail_length`**: The length of the "tail" section that you can grip to remove the peg.
*   **`tail_width`**: The width of the tail (should be less than head_diameter)
* **`tail_thickness`**: Thickness of the tail. Should be similar to `head_thickness`

I'd like the tail to extend on one side of the peg only.

I would also like to have the option of adding a slightly tapered or rounded edge to the end of the cylindrical section that goes into the hole, to make it easier to insert.

Also, I'd like to be able to adjust the amount of tolerance, that is how much smaller the cylindrical section is relative to the hole it goes in, for a good friction fit.

Can you help me create an OpenSCAD file (or files) using parameters so I can easily customize the peg for various furniture? I'm not familiar with many OpenSCAD libraries other than the basic functions. Thanks!

[Assistant]
peg.scad:
```
// Diameter of hole in side board of bookcase or wardrobe
hole_diameter = 7;

// Deep of hole
hole_deep = 10;

// Length of outer part of peg
length = 12;

intersection() {
	union() {
		translate([-hole_deep+1,0,0]) rotate([0,-90,0]) cylinder(r1=hole_diameter/2, r2=hole_diameter/2-1, h=1);
		rotate([0,-90,0]) cylinder(r=hole_diameter/2, h=hole_deep-1);
		difference() {
			translate([0,-hole_diameter/2,-hole_diameter/2]) cube([length,length,hole_diameter]);
			translate([length*0.7+0.5,0,0]) rotate([0,0,45]) translate([0,-50,-50]) cube([100,100,100]);
		}
		translate([0,-hole_diameter/2-2,-hole_diameter/2]) cube([1,length,hole_diameter]);
	}
	cube([100,100,hole_diameter-0.2], center=true);
}

```


[User]
I'm looking to create a cup-like structure with some sensor mounting features and wiring channels. I've got some specific dimensions in mind, and I'd like it to be parametric so I can easily adjust things later.

The main body of the cup should consist of a base cylinder with a height of `Base_Height` and a radius of `Base_Radius`. I need to put three wings around the side of the base, equally spaced. Each wing needs to have a height of `Wing_Height`, a length of `Wing_Length`, and a width of `Wing_Width`. They should all sit on top of the base cylinder and be connected at the base cylinder's outer edge.

Inside the cup, I need to have an interior cylinder to define the inside space with a height equal to `Wing_Height`, a bottom radius of `Bot_Inner_Radius`, and a top radius of `Top_Inner_Radius`. This inner cylinder should start at the same height as the wings. Also, add a very thin disk, 1 unit thick, at the top of the inner cylinder.

On the floor of the cup, I need to mount a sensor. It should be a cylinder with a `Sensor_Height` and a radius of `Sensor_Area_Radius`, also centered on the base.

To fit the sensor into the base I need to remove a cube with dimensions `Sensor_Width` x `Sensor_Width` x `Sensor_Height+1` from the sensor platform, centered on the base, that extends down to the base plane.

For wiring I need a couple of different holes. First, there need to be four small mounting holes for the sensor board. These should be located at `Sensor_Hole_X` and `Sensor_Hole_Y` away from the origin of the base. The holes should have radius `Sensor_Hole_R` and extend through the base. Then, I need three wire channels to pass the wires outside of the base. These should be located around the sensor platform at the same distance from the center of the base as the sensor platform itself, and have a radius of `Wire_Hole_R`. They also need to extend through the base. The three wiring channels should be spaced 120 degrees apart.

I want all of this to be generated by a single OpenSCAD file. Let's start with these parameters:

`Base_Height=2.5;`
`Base_Radius=25;`
`Wing_Height=2.5;`
`Wing_Length=20;`
`Wing_Width=5;`
`Sensor_Width=8;`
`Sensor_Height=4;`

`Top_Inner_Radius=20;`
`Bot_Inner_Radius=15;`
`Sensor_Area_Radius=10;`

`Sensor_Hole_X=3.25;`
`Sensor_Hole_Y=2.25;`
`Sensor_Hole_R=.5;`

`Wire_Hole_R=1.25;`

[Assistant]
CupBot.scad:
```
Base_Height=2.5;
Base_Radius=25;
Wing_Height=2.5;
Wing_Length=20;
Wing_Width=5;
Sensor_Width=8;
Sensor_Height=4;

Top_Inner_Radius=20;
Bot_Inner_Radius=15;
Sensor_Area_Radius=10;

Sensor_Hole_X=3.25;
Sensor_Hole_Y=2.25;
Sensor_Hole_R=.5;

Wire_Hole_R=1.25;

difference(){

difference(){

union(){

difference(){

union(){

rotate([0,0,240])translate([Base_Radius-Wing_Width,-Wing_Width/2,Base_Height])cube([Wing_Length,Wing_Width,Wing_Height]);

rotate([0,0,120])translate([Base_Radius-Wing_Width,-Wing_Width/2,Base_Height])cube([Wing_Length,Wing_Width,Wing_Height]);

translate([Base_Radius-Wing_Width,-Wing_Width/2,Base_Height])cube([Wing_Length,Wing_Width,Wing_Height]);

cylinder(Base_Height+Wing_Height,Base_Radius,Base_Radius);

}

union(){

translate([0,0,Base_Height])cylinder(Wing_Height,Bot_Inner_Radius,Top_Inner_Radius);

translate([0,0,Base_Height+Wing_Height])cylinder(1,Top_Inner_Radius,Top_Inner_Radius);

}

}

translate([0,0,Base_Height])cylinder(Sensor_Height,Sensor_Area_Radius,Sensor_Area_Radius);

}

translate([-Sensor_Width/2,-Sensor_Width/2,Base_Height])cube([Sensor_Width,Sensor_Width,Sensor_Height+1]);

}

union(){

translate([Sensor_Hole_X,Sensor_Hole_Y,-1])cylinder(Base_Height+2,Sensor_Hole_R,Sensor_Hole_R);

translate([Sensor_Hole_X,-Sensor_Hole_Y,-1])cylinder(Base_Height+2,Sensor_Hole_R,Sensor_Hole_R);

translate([-Sensor_Hole_X,Sensor_Hole_Y,-1])cylinder(Base_Height+2,Sensor_Hole_R,Sensor_Hole_R);

translate([-Sensor_Hole_X,-Sensor_Hole_Y,-1])cylinder(Base_Height+2,Sensor_Hole_R,Sensor_Hole_R);

rotate([0,0,240])translate([Bot_Inner_Radius/2+Sensor_Area_Radius/2,0,-1])cylinder(Base_Height+2,Wire_Hole_R,Wire_Hole_R);

rotate([0,0,120])translate([Bot_Inner_Radius/2+Sensor_Area_Radius/2,0,-1])cylinder(Base_Height+2,Wire_Hole_R,Wire_Hole_R);

translate([Bot_Inner_Radius/2+Sensor_Area_Radius/2,0,-1])cylinder(Base_Height+2,Wire_Hole_R,Wire_Hole_R);

}

}
```


[User]
I need an OpenSCAD design for a poker chip rack. I want to be able to customize it for different chip sizes and quantities. Here's what I'm thinking:

The rack should hold stacks of poker chips in rows. I need to be able to specify:

*   The diameter of one poker chip.
*   The thickness of one poker chip.
*   The number of chips I want in each row.
*   The number of rows in the rack.
*   The thickness of the rack's base material.
*   A fudge factor (or tolerance) in millimeters to adjust how snug the fit is - so if my chips don't quite match the specified size, I can still get them to fit in the rack.

The design should create individual cylinders to hold each stack of chips, and I'd like to be able to remove the chips easily, so the design should take this into consideration somehow - perhaps with a thumb cutout or some other method to allow for easy access?

I don't think I need any special libraries for this, but you'll know best. I want it to be parametric so I can easily change the dimensions without needing to modify the code directly.

[Assistant]
mathgrrl_pokertray_customizer.scad:
```
// mathgrrl customizable poker chip rack

////////////////////////////////////////////////////////////////////////////
// parameters //////////////////////////////////////////////////////////////

// Diameter of one poker chip (in millimeters)
Chip_Diameter = 20;

// Thickness of one poker chip (in millimeters)
Chip_Thickness = 3.35;

// Number of chips you want in each row of the rack
Number_of_Chips = 20;

// Number of rows you want in the rack
Number_of_Rows = 3;

// Thickness of the rack itself
Rack_Thickness = 2;

// Enter a tolerance (more if your chips are too tight, less if they are too loose)
Fudge = 1;

// Parameters invisible to the user
$fn = 96*1;
radius = Chip_Diameter/2 + Fudge;
height = Chip_Thickness*Number_of_Chips + Fudge;
thickness = Rack_Thickness*1;
rows = Number_of_Rows*1;
shift = 2*1; 		// to make clean holes and/or holes with edges

////////////////////////////////////////////////////////////////////////////
// renders /////////////////////////////////////////////////////////////////

for (i = [1:1:rows]){
	translate([0,(i-1)*(2*radius+thickness),0]) chipstack();
}

////////////////////////////////////////////////////////////////////////////
// module for holding one stack of chips ///////////////////////////////////

module chipstack(){
	// shift down to platform
	translate([0,0,-.5])
		difference(){
			// outside cylinder
			translate([0,0,radius+thickness])
				rotate(90,[0,1,0])
					cylinder(h=height+2*thickness,r=radius+thickness);
			// take away chip cylinder
			translate([thickness,0,radius+thickness])
				rotate(90,[0,1,0])
					cylinder(h=height,r=radius);
			// take away thumb cylinder
			translate([-shift,0,radius+thickness])
				rotate(90,[0,1,0])
					cylinder(h=height+2*thickness+2*shift,r=radius-3*thickness);
			// take away top
			translate([-shift,-.5*(height+2*shift),radius+thickness])
				cube(height+2*thickness+2*shift);
			// flatten bottom
			translate([-shift,-5,-10+.5])
				cube([height+2*thickness+2*shift,10,10]);
		}
}

```


[User]
I'm looking to create a parametric adapter for using smaller driver bits in a larger driver. I've been using one I made with hardcoded dimensions but I want to be able to customize it easily.

The adapter itself will be a hexagonal prism. There will be a hexagonal hole in the prism to fit the smaller bit, which will go partway through the prism. The top (the end that goes into the larger driver) will be a hexagonal prism of the same outer dimension as the driver.

Here are the key parameters I want to control:

*   `adapter_length`: The total length of the adapter.
*   `hole_depth`: The depth of the smaller bit hole.
*    `hole_wall_thickness`: The wall thickness around the hole.
*   `plug_od`: The outer diameter of the larger bit driver, measured across the flats.
*   `hole_diameter`: The diameter of the smaller bit, measured across the flats.
*   `clearance`: A small amount of extra space to ensure parts fit together well.

I'd like to use the `sqrt(3)` calculation to derive the radii for the hex cylinders. I also want the final object to be a difference, subtracting the hexagonal hole from a combined hexagonal prism. The hole should be slightly longer than the specified `hole_depth` to make sure it goes all the way through when printed. I'd like to use the `$fn = 6` parameter for all the cylinders to keep everything hex-shaped.

I'd like the generated code to be an OpenSCAD file, I don't think I need to have it depend on any other libraries.

[Assistant]
bit-adapter.scad:
```
adapter_length = 30;
hole_depth = 10;
hole_wall_thickness = 2;
// outer diameter of plug across the flats: 5/16 * 25.4
plug_od = 7.9375;
// diameter of hole across the flats: 1/4 * 25.4
hole_diameter = 6.35;
clearance = 0.1;

difference() {
  union() {
    cylinder(h=adapter_length, r=plug_od/sqrt(3) - clearance, $fn = 6);
    cylinder(h=hole_depth + hole_wall_thickness, r=hole_diameter/sqrt(3) + clearance + hole_wall_thickness, $fn = 6);
  }
  translate([0, 0, -clearance]) cylinder(h=hole_depth + 2*clearance, r=hole_diameter/sqrt(3) + clearance, $fn = 6);
}

```


[User]
Okay, I'm looking to create a system for attaching an air duct to a desk or other surface. I've got a couple of preliminary SCAD files, but I'd like you to generate a fully parametric design for both the duct and a clamp mechanism, preferably as separate files. I don't need any build plate stuff included.

Here's a breakdown of what I need for the air duct:

*   **Duct Geometry:** The duct should have a curved profile, basically a section of a torus. I need to be able to control the inner and outer curvature radii, the thickness, and the overall height of the duct section. The inner diameter also needs to be a configurable parameter.
*   **Support Structure:** I need to include a support ring that attaches inside the duct. The support needs to be adjustable for radius, thickness, and its vertical location along the duct. It should basically be a section of a sphere with some supporting beams.
*  **Connection Point:** The duct should also feature a connection point that would allow for more air ducts to be attached. This connection point should be a cylinder with a rounded end, and should have a configurable length.

And for the clamp mechanism, here's what I have in mind:

*   **Clamp Shape:** The clamp should have a kind of angled, "C" shape that will grip an edge. The main body of the clamp should be designed with a couple of intersecting cubes and some rotation. The parameters of these shapes need to be fully configurable so I can adjust the "grip" and size of the clamp.
*   **Mounting Hole:** There needs to be a hole through the clamp that will fit a bolt or screw. I would like this hole to be parametrically adjustable for radius. The hole should also feature a countersink (or a spot for a screw head to fit). The countersink should be an adjustable radius and depth as well. I would like this hole to be duplicated on the opposite side.
*   **Edge Grips:** The clamp also needs to have a sort of "gripping edge" that would allow it to securely stay on the side of a table or other surface. I'd like to be able to configure these parts.

Essentially I need these two parts to be fully adjustable via parameters in OpenSCAD. I am not sure if this is complex enough to warrant libraries being used, but if it simplifies the design process, I'm not opposed to using one. I'm also unsure if the designs are complex enough to warrant multiple files, but please split the files up if you deem it useful.

[Assistant]
Airduct.scad:
```
//CUSTOMIZER VARIABLES

// The inner diameter of the duct
cowl_Innerdiameter = 85; // [10:100]
// The thickness of the duct
cowl_Thickness = 4; // [1:20]
// The inside curvature of the duct
cowl_Inner_Curvature = 500; // [100:10000]
// The outside curvature of the duct
cowl_Outer_Curvature = 150; // [100:10000]
// The height of the duct
cowl_Height = 48; // [10:250]

// Thickness of the support beams
support_Thickness = 3; // [1:10]
// The radius of the support cone
support_Radius = 17; // [2:30]
// The vertical location of the support in the duct
support_Location = 0; // [-50:50]

// Connection length
connection_Length = 40; // [10:100]

//	This section is creates the build plates for scale
//	for display only, doesn't contribute to final object
build_plate_selector = 3; //[0:Replicator 2,1: Replicator,2:Thingomatic,3:Manual]

//	when Build Plate Selector is set to "manual" this controls the build plate x dimension
build_plate_manual_x = 100; //[100:400]

//	when Build Plate Selector is set to "manual" this controls the build plate y dimension
build_plate_manual_y = 100; //[100:400]

//CUSTOMIZER VARIABLES END

//	This is just a Build Plate for scale
build_plate(build_plate_selector,build_plate_manual_x,build_plate_manual_y);

$fs=1;
$fa=1;

module shape(inner_Curvature,outer_Curvature,thickness,height) {
	rotate([90,0,0]) {
		difference() {
			intersection() {
				translate([inner_Curvature-thickness/2,0,0]) {
					circle(inner_Curvature);
				}
				translate([-outer_Curvature+thickness/2,0,0]) {
					circle(outer_Curvature);
				}
			}
			translate([-50,height/2,0]) {
					square([100,100]);
			}
			translate([-50,-100-height/2,0]) {
					square([100,100]);
			}

		}
	}
}

module cowl(inner_Curvature,outer_Curvature,thickness,innerDiameter,height) {
	rotate_extrude() {
		translate([(innerDiameter/2)+(thickness/2),0,0]) {

					shape(inner_Curvature,outer_Curvature,thickness,height);

		}
	}
}

module support(radius,thickness,size) {
	difference() {
		union() {
			translate([0,0,-thickness]) {
				scale([1,1,3]) {
					rotate([90,0,0]) {
						cylinder(r=thickness/2,h=size,center = true, $fn=30);
					}
					rotate([0,90,0]) {
						cylinder(r=thickness/2,h=size,center = true, $fn=30);
					}
				}
			}
			scale([1,1,1.3]) {
				sphere(r=radius);
			}
		}
		translate([0,0,(thickness/2)+250.1]) {
			cube([1000,1000,500],center = true);
		}
	}
}

module housing(cowl_Innerdiameter,cowl_Thickness,cowl_Inner_Curvature,cowl_Outer_Curvature,cowl_Height,support_Thickness,support_Radius,support_Location){

	union(){
		cowl(cowl_Inner_Curvature, cowl_Outer_Curvature, cowl_Thickness, cowl_Innerdiameter, cowl_Height);
		translate([0,0,support_Location]) {
			support(support_Radius,support_Thickness,cowl_Innerdiameter+cowl_Thickness);
		}
		connection(cowl_Innerdiameter,connection_Length);
	}
}

module connection(position,length) {
	translate([0,-position/2,0]) {
		rotate([90,0,0]) {
			union() {
				cylinder(r1=7,r2=4,h=length);
				translate([0,0,length]) {
					sphere(r=7);
				}
			}
		}
	}
}

*shape(600,500,5);
*cowl(500,600,5,50,50);
*support(12,3,25);

housing(cowl_Innerdiameter,cowl_Thickness,cowl_Inner_Curvature,cowl_Outer_Curvature,cowl_Height,support_Thickness,support_Radius,support_Location);

```
holder.scad:
```
$fs=.5;
$fa=1;

module clamp() {
	intersection() {
		difference() {
			union() {
				translate([0,0,-32]) {
					rotate([45,0,0]) {
						difference() {
							cube([20,40,40],center=true);
							cube([40,36,36],center=true);
						}
					}
				}
				difference() {
					translate([0,0,-12]) {
						cube([20,30,32],center=true);
					}
					translate([0,0,-32]) {
						rotate([45,0,0]) {
							cube([30,37,37],center=true);
						}
					}
				}
			}
			union() {
				sphere(r=7.25);
				cube([8,60,20], center = true);
				translate([7,10,-2]){
					rotate([0,90,0]) {
						cylinder(r=1.25,h=50,center=true);
						cylinder(r=3.2,$fn=6,h=10);
						translate([0,0,-24.5]) {
							cylinder(r=3.5,h=10);
						}
					}
				}
				translate([7,-10,-2]){
					rotate([0,90,0]) {
						cylinder(r=1.25,h=50,center=true);
						cylinder(r=3.2,$fn=6,h=10);
						translate([0,0,-24.5]) {
							cylinder(r=3.5,h=10);
						}
					}
				}
			}
		}
		translate([0,0,20]) {
			rotate([45,0,0]){
				cube([100,100,100],center=true);
			}
		}
	}
}
clamp();
```


[User]
I'm looking to design a headphone cord keeper with two clips that connect magnetically behind the neck. The design should be parametric, allowing me to adjust dimensions.

Specifically, I need the design to handle both rectangular and round headphone cords. The main parts are:

1.  **Cord Clip:** This part attaches to the headphone cord and has a cylindrical form with a cutout for the cord itself.
2.  **Headphone Holder:** This is the part that connects to the cord clip and comes in two variants: one for rectangular cords, and one for round cords.
3.  **Magnetic Connection:** This is the magnetic section located on the back of the holder. I'm not concerned about the magnet geometry itself, but rather the space to accommodate them behind the holder and the corresponding mating surface for connection.

I need the following parameters to be adjustable:

*   **Cord Type:** A boolean to switch between rectangular (0) and round (1) headphone holders.
*   **Wall Thickness:** The thickness of all walls.
*   **Height:** The overall height of the clips
*   **Cord Diameter (Round):** The diameter of the cord for the cylindrical cutout in the clip part.
*   **Cord Thickness (Rectangular):** The thickness of the rectangular cord.
*   **Cord Width (Rectangular):** The width of the rectangular cord.
*   **Corner Radius (Rectangular):** The corner radius for the rectangular holder part.
*   **Headphone Cord Diameter (Round):** The diameter of the round headphone cord.
*   **Overage:**  This is a small value to be added to cutouts to prevent z-fighting.

For the rectangular holder I need it to have an opening slot on the side, to allow for the cord to snap in place.

The design should use the `MCAD/boxes.scad` library to assist with the rectangular holders.

Finally, I need two complete assembled parts, offset from each other, in the generated SCAD file.

[Assistant]
hp_keepersV2.scad:
```
//Magnetic Headphone Keeper
include <MCAD/boxes.scad>

/* [Global] */
//Type of Headphone Cord
type=1; //[0:Rectangular, 1:Round]
//Wall Thickness
wallTh=1.3;
//Height
height=6;
//Facets
$fn=36;

/* [Cord Dimensions] */
//Cord Diameter
cordDia=2;

/* [Headphone Holder Dimensions] */
//Cord Thickness (rectangular)
xDim=4.4;
//Cord Width (rectangular)
yDim=1.5;
//Corner Radius (rectangular)
corner=2;
//Headphone Cord Diameter (round)
headPhDia=2;

/* [Hidden] */
//overage for cutting and joining
ovr=0.001;
//cord radius
cordR=cordDia/2;
//headphone cord radius
headPhR=headPhDia/2;

module cordHolder() {
  difference() {
    cylinder(r=cordR+wallTh, h=height, center=true);
    cylinder(r=cordR, h=height+ovr, center=true);
  } //end diff
} //end cordHolder

module rectHolder() {
  difference() {
    //outter box
    roundedBox([xDim+wallTh*2, yDim+wallTh*2, height], corner, sidesonly=1);
    //cutout
    cube([xDim, yDim, height+ovr], center=true);
    //opening slot
    translate([0, -xDim/2, 0]) cube([yDim, xDim, height+ovr], center=true);

  } // end diff
} //end rect holder

module roundHolder() {
  difference() {
    cylinder(r=headPhR+wallTh, h=height, center=true);
    cylinder(r=headPhR, h=height+ovr, center=true);
    translate([0, -headPhR, 0]) cube([headPhR*1.3, headPhR*3, height+ovr], center=true);
  }
} //end round holder

module joinParts(type=0) {
  union() {
    cordHolder();
    if (type==0) {
      translate([cordR+wallTh+(xDim+wallTh*2)/2.5, 0, 0]) rectHolder();
    } //end rectangular

    if (type==1) {
      translate([cordR+wallTh+(cordR+wallTh*2)/2.5, 0, 0]) roundHolder();
    } //end round
  } //end union
} //end join parts

joinParts(type);
translate([0, (cordDia+wallTh)*2, 0]) joinParts(type);

```


[User]
Hey, I'm looking for a design that I can customize for a finger toy with moving eyes. I want the design to have a ring that goes around the finger, and then pairs of eyes that are attached to this ring. The eyes should be spherical with a visible iris inside them, and they should be able to rotate within their sockets.

Here's what I need to be able to configure:

*   **Number of Eye Pairs:** I'd like to be able to choose how many pairs of eyes are stacked on top of each other.
*   **Ring Radius:** I need to be able to set the radius of the finger ring (it should be between 5 and 20 mm).
*   **Ring Thickness:** I also need to control the thickness of the ring.
*   **Print Distance:** There should be a small gap between the eyeball and the outer shell that holds it, so that the eyeball can move freely. I want to be able to adjust that gap.

Additionally, I'd like to have some options for cutaways. This is just for visualization during the design process, it shouldn't affect the final STL file unless I choose to use them. I'd like to be able to specify if the model should have:

*   No cutaway (just the solid model, ready for printing)
*   A cutaway on the side to see the internal structure
*   A cutaway on the top to see the internal structure

The design should use a sphere for the eyeball, a cylinder for the iris and pupil, and other cylinders for the ring and eye socket. I don't need any external libraries for this. Could you generate the OpenSCAD code for me?

[Assistant]
augen_V13.scad:
```
//Want more eye pairs? Just select the number here...
Num_Eye_Pairs=1;//[1,2,3,4,5,6]

//The ring radius in mm, please stay beteween 5mm and maximum 20mm.
ring_r=9;

//Select the ring thickness in mm
ring_thick=5;

//The distance between the eyeball and the outer shell in mm. Adjust it so the two dont touch. Recommended is to stay between 0.1 and 0.6 mm.
print_dist=0.4;

//For printing, select "Basic". For fun, select "CustSide" or "CutTop" to cut into the model to see the inside.
part = "Basic"; // [Basic,CutSide,CutTop]

/* [Hidden] */

/*
Eye Toy for your finger
Version 13, March 2019
Written by MC Geisler (mcgenki at gmail dot com)

The eyes mooove!

Have fun!

License: Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
You are free to:
    Share - copy and redistribute the material in any medium or format
    Adapt - remix, transform, and build upon the material
Under the following terms:
    Attribution - You must give appropriate credit, provide a link to the license, and indicate if changes were made.
    You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
    NonCommercial - You may not use the material for commercial purposes.
    ShareAlike - If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
*/

$fs=1;

ring_width=2;

eye_r=10;
eye_dist=4; //correct for ring_r=9 only!
//    eye_shiftside = ring_r/sqrt(2)+eyering_r/sqrt(2) == eye_r+eye_dist/2
// => eyering_r/sqrt(2) = eye_r+eye_dist/2-ring_r/sqrt(2)
eyering_r=(eye_r+eye_dist/2)*sqrt(2)-9;//ring_r; //better to move the eyes together than to change the eyes radius

openring_shiftdown=ring_r/sqrt(2)+eyering_r/sqrt(2);
eye_shiftside=openring_shiftdown;

openring_shiftbottom=-eye_r+ring_thick/2 +  eye_r*.35;

//iris
eyeball_r=eye_r-ring_width-print_dist;
iris_r=eyeball_r/2;
iris_bottom=eyeball_r/sqrt(2);
iris_bottomheight=iris_r+2;
iris_linew=0.55;
pupil_r=iris_r/1.9;
iris_width=iris_r-pupil_r;

module eyeball()
{
	difference()
	{
		sphere(eyeball_r);
		translate([0,0,iris_bottomheight])
			cylinder(r=iris_r,h=2*eyeball_r,center=true);
	}

	translate([0,0,openring_shiftbottom-ring_thick/2+iris_bottomheight/2])
			cylinder(r=iris_bottom,h=iris_bottomheight,center=true);

	//iris
	for (i=[0:360/16:360])
	rotate([0,0,i])
		translate([pupil_r+iris_width/2,0,0])
			cube([iris_width,iris_linew,2*eyeball_r-iris_r/2-.5],center=true);
}

module ringouter(radius,width,thick)
{
	cylinder(r=radius+width/2,h=thick,center=true);
}
module ringinner(radius,width,thick)
{
	cylinder(r=radius-width/2,h=2*thick,center=true);
}
module ring(radius,width,thick)
{
	difference()
	{
		ringouter(radius,width,thick);
		ringinner(radius,width,thick);
	}
}

module openring()
{
	translate([0,-openring_shiftdown,openring_shiftbottom])
	difference()
	{
		ring(ring_r,ring_width,ring_thick);
		translate([0,ring_r*2+(ring_r-ring_width/2)/sqrt(2),0])
			cube([ring_r*4,ring_r*4,ring_r*4],center=true);
	}
}

module openringhalf()
{
	difference()
	{
		openring();
		translate([-ring_r*4-.2,0,0])
			cube([ring_r*8,ring_r*8,ring_r*8],center=true);
	}
}

module eye(doIt)
{
	translate([eye_shiftside,0,0])
	{
		difference()
		{
			union()
			{
				sphere(eye_r);
				translate([0,0,openring_shiftbottom])
					 ringouter(eyering_r,ring_width,ring_thick);

				//only the first eye pair needs a ring
				if (doIt=="withRing")
					translate([-eye_shiftside,0,0])
						openringhalf();
			}

			sphere(eye_r-ring_width);

			cylinder(r=eye_r/1.5,h=ring_r*4,center=true);

			translate([0,0,openring_shiftbottom])
				ringinner(eyering_r,ring_width,ring_thick);
		}

		eyeball();

		//translate([0,0,openring_shiftbottom])
		//	ring(eyering_r,ring_width,ring_thick);
	}
}

module TwoEyes(doIt)
{
	eye(doIt);
	mirror([1,0,0])
		eye(doIt);
}

difference()
{
	union()
	{
		//TwoEyes();

		for (i=[0:Num_Eye_Pairs-1])
			translate([0,(eye_r*2-ring_width)*i,0])
				TwoEyes( (i==0?"withRing":"") );
	}

	//top cutoff
	translate([0,0,eye_r*3-openring_shiftbottom+ring_thick*.6])
		cube(eye_r*6,center=true);

	//bottom cutoff
	translate([0,0,-eye_r*20+openring_shiftbottom-ring_thick/2])
		cube(eye_r*40,center=true);

	//look into the side
	if (part=="CutSide")
		translate([20+eye_shiftside,0,0]) cube([40,40*Num_Eye_Pairs,40],center=true);
   if (part=="CutTop")
		translate([20,20,0]) cube(40,center=true);
}

```


[User]
I'd like a parametric OpenSCAD file to generate standoffs, please. I need the following features:

*   **Standoff Style:** I want to be able to generate either a single standoff or an array of standoffs.
*   **Body Shape:** The main body of the standoff can be round, square, or hexagonal.
*   **Body Height:** The height should be customizable, with a range of 3 to 45 mm.
*   **Body Diameter:** I need to be able to specify the diameter of the body.
*   **Top Style:** The top of the standoff can be male (protruding cylinder), female (a recessed hole), or flat.
*   **Thread Diameter:** The diameter of the threaded portion (either male or female) should be customizable.
*   **Thread Height/Depth:** I need to control the height of the male thread or depth of the female thread.
*   **Base Thickness:**  The thickness of any base should be customizable.

For single standoffs I need:

*   **Base Type:** I need the option to have a bottom clearance hole, a rectangular base, both, or neither.
*   **Bottom Hole Diameter:** If there is a hole, its diameter should be customizable.
*   **Base Dimensions:** The x and y dimensions of the rectangular base should be customizable.

For arrays of standoffs, I need:
*   **Columns/Rows:** The number of columns and rows in the array should be customizable.
*   **Column/Row Offset:** The center-to-center distance between standoffs in the x and y directions needs to be customizable.
*   **Base Extension:** The amount the base extends beyond the edges of the standoffs should be customizable.

I'm not using any specific libraries, so please do not include any library code.

[Assistant]
StandoffCreator1-0.scad:
```
//Standoff Customizer v0.0.8
//by eriqjo February 20, 2015

//REVISION HISTORY
//v1.0  Fix issues with customizer
//v0.0.8 Increased max height to 45, added option for hole/flat top
//V0.0.7 A different approach to making an array of standoffs
//v0.0.6 Added option for array of standoffs
//v0.0.5 Added feature for rectangular foot on bottom of standoff
//v0.0.4 Changed all cylinders to radius based
//v0.0.1 Initial release of standoff customizer

//CUSTOMIZER VARIABLES

/* [Body Parameters] */

//Type of standoff(s) to create
Style = 2; // [1:Single, 2:Array]

//Choose shape of the main body
Body_Shape = 3; // [1:Round, 2:Square, 3:Hex]

//Define the height of the body, mm
Body_Height = 25; // [3:45]

//Define the diameter of the body, mm
Body_Diameter = 6;

//Choose the style of the top section
Top_Style = 2; //[1:Male, 2:Female, 3:Flat]

//Outer diameter of threaded portion, mm
Thread_Dia = 3;

//Define the height/depth of the top feature, mm
Thread_Height = 15;

//Define thickness of the base, mm
Base_Thickness = 2;

/* [Single Options] */

//Features to include on base
Base_Type = 3; // [1:Hole Only, 2:Rectangular Base Only, 3:Base and Hole, 4:Neither]

//Define the diameter of the bottom clearance hole, mm
Bottom_Hole_Dia = 3;

//Define length in x-direction, mm
Base_X = 12;

//Define length in y-direction, mm
Base_Y = 35;

/* [Array Options] */

//Number of columns, x-direction
Columns = 3;

//Center-to-Center distance for columns, mm
X_Offset = 45;

//Number of rows, y-direction
Rows = 2;

//Center-to-Center distance for rows, mm
Y_Offset = 30;

//How far past the edge of the standoffs the base extends, mm
Added_Base = 3;

//CUSTOMIZER VARIABLES END

bodyR = Body_Diameter/2;
bottomR = Bottom_Hole_Dia/2;
threadR = Thread_Dia/2;

module makeBody(shape) {

//round************************************************************************************************
	if(shape == 1) {	//round
		if(Top_Style == 1){   //male
			union(){
				translate([0, 0, Body_Height/2])
					cylinder(Body_Height, r = bodyR, center = true, $fn = 12);
				translate([0,0, Body_Height + Thread_Height/2 - 0.1])
					cylinder(Thread_Height + 0.1, r = threadR, $fn = 12, center = true);
			} //u
		}// if topstyle = 1

				if(Top_Style == 2){   //female
			difference(){
				translate([0, 0, Body_Height/2])
					cylinder(Body_Height, r = bodyR, center = true, $fn = 12);
				translate([0,0, Body_Height - Thread_Height/2 + 0.1])
					cylinder(Thread_Height + 0.1, r = threadR, $fn = 12, center = true);
			} //d
		}// if topstyle = 2

		if(Top_Style == 3){   //flat
			translate([0, 0, Body_Height/2])
				cylinder(Body_Height, r = bodyR, center = true, $fn = 12);
		}// if topstyle = 3

	} //if

//square****************************************************************************************************
	if(shape == 2) {	//square
		if(Top_Style == 1){  //male
			union(){
				translate([0,0, Body_Height + Thread_Height/2 - 0.1])
					cylinder(h = Thread_Height + 0.1, r = threadR, $fn = 12, center = true);
				translate([0,0, Body_Height/2])
					cube([Body_Diameter, Body_Diameter, Body_Height], center = true);
			} //u
		} //if topstyle = 1

		if(Top_Style == 2){  //female
			difference(){
				translate([0,0, Body_Height/2])
					cube([Body_Diameter, Body_Diameter, Body_Height], center = true);
				translate([0,0, Body_Height - Thread_Height/2 + 0.1])
					cylinder(h = Thread_Height + 0.1, r = threadR, $fn = 12, center = true);
			} //d
		} //if topstyle = 2

		if(Top_Style == 3){  //flat
			translate([0,0, Body_Height/2])
				cube([Body_Diameter, Body_Diameter, Body_Height], center = true);
		} //if topstyle = 3

	} //if square

//hex**********************************************************************************************************
	if(shape == 3) {	//hex
		if(Top_Style == 1){  //male
			union(){
				translate([0,0, Body_Height + Thread_Height/2 - 0.1])
					cylinder(h = Thread_Height + 0.1, r = threadR, $fn = 12, center = true);
				cylinder(h = Body_Height, r = bodyR, center = false, $fn = 6);
			} //u
		} // if topstyle = 1

		if(Top_Style == 2){  //female
			difference(){
				cylinder(h = Body_Height, r = bodyR, center = false, $fn = 6);
				translate([0,0, Body_Height - Thread_Height/2 + 0.1])
					cylinder(h = Thread_Height + 0.1, r = threadR, $fn = 12, center = true);
			} //u
		} // if topstyle = 2

		if(Top_Style == 3){ // flat
			cylinder(h = Body_Height, r = bodyR, center = false, $fn = 6);
		}//if topstyle = 3
	} //if hex

} //module

module makeBase(){
	if(Base_Type == 2 || Base_Type == 3){
	 translate([0, 0, Base_Thickness/2])
		cube([Base_X, Base_Y, Base_Thickness], center = true);
	} //if
} //module

module makeHole(){
	if(Base_Type == 1 || Base_Type == 3){
		translate([0, 0, (Body_Height - 1)/2])
			cylinder(h = Body_Height - 0.9, r = bottomR, $fn = 12, center = true);
	} //if
} //module

//Runtime
if (Style == 1){   //single standoff
	difference(){
		union(){
			makeBody(Body_Shape);
			makeBase();
		} //u
		makeHole();
	} //d
} //if

//The new way

baseShift = Body_Diameter/2 + Added_Base;
baseX = (Columns - 1) * X_Offset + Body_Diameter + (2 * Added_Base);
baseY = (Rows - 1) * Y_Offset + Body_Diameter + (2 * Added_Base);

if (Style == 2){  //array

	union(){
		for (j = [0 : Rows - 1]){     //replace 3 with Rows
			translate([0,j * Y_Offset,0])
				for( i = [0 : Columns - 1]){   //replace 4 with Columns
					translate([i * X_Offset,0,0])
						makeBody(Body_Shape);
				}//for
		}//for
		translate([-baseShift, -baseShift, -Base_Thickness + 0.1])
			cube(size = [baseX, baseY, Base_Thickness], center = false);
	} //union
}//if

```


[User]
I'm looking to design a parametric, disposable sink strainer using OpenSCAD. I'd like it to be customizable to fit different sink sizes, so parameters are crucial.

The strainer should have a few main parts: a main cylindrical tube with a bottom filter, a gradient section connecting the tube to a head flange, and a small cylindrical knob on top for easy removal. I'd like to make sure it can be printed with a variety of 3D printers.

Here are the key dimensions and features that should be adjustable:

*   **Inner diameter of the main tube:** This is the diameter that actually sits in the sink drain. I'll need to be able to adjust this to fit different drains.
*   **Outer diameter of the main tube:** This determines the wall thickness of the tube and should be adjustable.
*   **Diameter of the head flange:** This is the flat part that sits on the sink, larger than the main tube. This will be another key parameter.
*   **Height of the main tube, including the filter:**  The total length of the cylindrical body.
*   **Gradient height:** The length of the tapered section between the main tube and the head.
*   **Height of the head flange:** The thickness of the head.

For the bottom filter, I need to specify:

*   **Filter height:** How thick the filter is.
*   **Distance between the centers of the filter slits:** How often the slits are placed, this will effectively make the openings larger or smaller.
*   **Filter opening ratio:** This will determine the width of each filter slit and will be specified as a ratio of the filter slit spacing.
*   **Filter beam aspect ratio:**  This will determine the width of the beams relative to the filter thickness, these beams should span in both directions across the filter.

For the side filters, which will be on the main cylindrical tube, I'll need:
*   **Distance between the centers of the side slits** similar to the bottom filter.
*   **Side slit opening ratio:** Also a ratio of the side slit spacing like the bottom filter.
*  **Opaque wall height above side filter:** Distance between the top of the side slits and the end of the tube.
*  **Opaque wall height below side filter:** Distance between the bottom of the side slits and the filter bottom.

Finally, the center knob needs these parameters:
*  **Handle height:** the length of the handle extending from the top of the strainer
*  **Handle lower diameter:** the diameter where the handle meets the top of the strainer
*  **Handle upper diameter:** the diameter of the top of the handle.

Also, please use comments throughout the code to explain the purpose of each section, and please try to make the code readable. I don't have a preference of libraries, but if you choose to use one please note that. Thanks!

[Assistant]
sink_strainer_140615.scad:
```
// sink strainer
//  ver.20140615 by junnno

// The diameter of the inside
inner_diamter = 66;
// The diameter of the outside of main tube
outer_diameter = 71;
// The diameter of the head flange
head_diameter = 79;

// The height of the main tube including bottom filter
main_cylinder_height = 15;
// The gradient length between the head and the main tube
gradient_height = 4;
// The height of the head
head_cylinder_height = 1.2;

// The thickness of the bottom filter
filter_height = 2.4;
// The length between the centers of the bottom filter slits
filter_periodic_length = 4;
// The opening area over the bottom filter area
filter_opening_ratio = 0.5;
// The bottom beam width over the filter thickness
filter_beam_aspect_ratio = 2;

// The length between the centers of side filter slits
side_slit_periodic_length = 4;
// The opening area over the side filter area
side_slit_opening_ratio = 0.5;
// The opaque wall height above the side filter
side_slit_top_margin = 2.4;
// The opaque wall height below the side filter
side_slit_bottom_margin = 1.2;

handle_height = 16;
handle_lower_diameter = 10;
handle_upper_diameter = 16;

//echo(version());
//echo(PI);

module test01()
{
	// head
	difference(){
		translate([0,0,main_cylinder_height+gradient_height])
			cylinder(h=head_cylinder_height, r=head_diameter/2);
		translate([0,0,main_cylinder_height+gradient_height-1])
			cylinder(h=head_cylinder_height+2, r=inner_diamter/2);
	}
	// gradient under the head
	difference(){
		translate([0,0,main_cylinder_height])
			cylinder(h=gradient_height, r1=outer_diameter/2, r2=head_diameter/2);
		translate([0,0,main_cylinder_height-1])
			cylinder(h=main_cylinder_height+2, r=inner_diamter/2);
	}
	// main tube with side slit pattern
	slit_angles = floor((inner_diamter*PI/2)/side_slit_periodic_length);
	slit_angle_step = 180/slit_angles;
	difference(){
		cylinder(h=main_cylinder_height, r=outer_diameter/2);
		translate([0,0,-1])
			cylinder(h=main_cylinder_height+2, r=inner_diamter/2);
		translate([0,0,filter_height+side_slit_bottom_margin+(main_cylinder_height-side_slit_top_margin-filter_height-side_slit_bottom_margin)/2])
			for(i=[0 : slit_angle_step : 180]){
				rotate(i,[0,0,1])
				cube([outer_diameter+1,side_slit_periodic_length*side_slit_opening_ratio,(main_cylinder_height-filter_height-side_slit_bottom_margin-side_slit_top_margin)],center=true);
			}
	}

	// bottom filter pattern
	final_ring = floor((outer_diameter/2)/filter_periodic_length)-1;
	for(i=[0:final_ring]){
		difference(){
			cylinder(h=filter_height, r=(i+1)*filter_periodic_length);
			translate([0,0,-1])
				cylinder(
				 h=filter_height+2,
				 r=(i+filter_opening_ratio)*filter_periodic_length);
		}
	}

	// bottom filter beam
	translate([0,0,filter_height/2]){
		cube([
		 (outer_diameter+inner_diamter)/2,
		 filter_height*filter_beam_aspect_ratio,
		 filter_height],
		 center=true);
		cube([
		 filter_height*filter_beam_aspect_ratio,
		 (outer_diameter+inner_diamter)/2,
		 filter_height],
		 center=true);
	}

	// center handle
	cylinder(r=handle_lower_diameter/2,h=filter_height);
	translate([0,0,filter_height])
		cylinder(r1=handle_lower_diameter/2, r2=handle_upper_diameter/2, h=handle_height);

}
test01();
```


[User]
I want to design a custom grill for a box, like a vent, and I'd like it to be parametric so I can easily adjust the size, depth, and image used for the grill pattern. I've already got a design in mind, and I'd like you to generate a new OpenSCAD file that recreates the design, while also allowing for easy customization.

The grill should consist of a rectangular base with an inset pattern and an overhanging lip that's raised above the base itself. The overall shape is a rectangular prism, or a box with most of the top, and a bit of the sides removed, leaving just a frame. The dimensions should be parameterized, of course.

Specifically, there are a few key parameters I'd like to control:

*   `x`: The overall width of the rectangular base.
*   `y`: The overall height of the rectangular base.
*   `z`: The overall depth/thickness of the base.
*   `lip`: How far the lip should overhang the base on all sides.
*   `thickness`: The thickness of the lip itself.
*  `grill_img`: A string that specifies the name of the .dat file that is loaded for the grill pattern. This will use the `surface()` function.
* `pixils`: The number of pixels in the image along its largest dimension.

The base of the grill should be a rectangular prism defined by `x`, `y`, and `z`. Inside this base, there is a recessed area defined by subtracting a slightly smaller rectangular prism from the center.

The lip is a rectangular prism that extends beyond the base by `lip` on all sides, and sits atop it. The lip has a height, or thickness, determined by the `thickness` parameter. The lip is flush with the top of the base. It's important that we're able to specify both the overhang distance and the thickness of this lip.

The grill pattern is created using the OpenSCAD `surface()` function, which needs to read in a `.dat` file with an array of numbers that can specify the depth of the surface. For now, it's okay to assume the file will be in the same directory. This surface is inset within the lip. The `surface()` function takes a heightmap and uses it to create a 3D shape, but we will want to scale it appropriately. The dimensions of the surface (heightmap) is determined by `pixils` but must be scaled to fit within the lip.

I am not concerned about the `convexity` setting for the `surface()` function.

The result should be a parametric module that I can use in other OpenSCAD designs, or use directly to generate an STL of the grill.

I don't think I need any external libraries for this, but if you think there's something that might be useful, please let me know.

[Assistant]
Box_Grill.scad:
```
//Created by Ari M. Diacou, June 2014
//Shared under Creative Commons License: Attribution-ShareAlike 4.0 Unported (CC BY-SA 4.0)
//see http://creativecommons.org/licenses/by-sa/4.0/

/*To get this to work offline, any image must be converted to a .dat file using the tool at http://customizer.makerbot.com/image_surface. That will output an array of values from 0-1 corresponding to the greyscale values 0-255 of the image. Inverting the colors of the image will ensure that the recessed image gets subracted from other objects properly. Copy the array to a text file. IMPORTANT: be sure that your file is actually a dat file and not e.g. foo.dat.txt. Some operating systems (like Windows 7 by default) hide the actual extension. Once the dat files are in the same directory as the .scad file, and are named properly the surface() function should work.

The way I prepared my image files was to:
	1	Import the image into gimp.
	2	Crop the image as tightly as possible
	3	Right click on the image: Image>Scale Image
	4	With the aspect ratio locked, change the Higher of the width and height to 100 pixils.
	5	Right click on the image: Image>Canvas Size
	6	With the aspect ratio UNlocked, change the Lower of the width and height to 100 pixils. Click "Center". Click "Resize".
	7	Right click on the image: Colors>Brightness-Contrast
	8	Increase the contrast to remove the effects of the resize, and get sharper edges.
	9	Export the file to jpg/gif/bmp/png (it doesnt really matter as long as the customizer tool can read the file).
	10	Open  http://customizer.makerbot.com/image_surface in a web browser.
	11	Select the file you want to convert. White will make holes, so dont "Invert Colors" for this thing.
	12	Copy the array of numbers to a text file.
	13	File>Save As. In the drop-down menu "Save as type:" select "All files". This will allow you to actually set the extenstion to ".dat". Name the file <whatever>.dat.

Your image should now ceate a surface() as intended. */

// Load a 100x100 pixel image for the top. (images will be automatically stretched to fit) Simple, high contrast images like logos work best. White will become holes, black will remain structural, so DONT "Invert Colors" for this thing.
grill_img = "grill.dat"; // [image_surface:100x100]
//The largest width of your plate
x=40;
//The largest height of your plate
y=50;
//The depth of your plate
z=6;
//How far does the plate overhang the hole in the box?
lip=5;
//The thickness of the lip
thickness=2;
//What was the largest number of pixils in the image?
pixils=100;
image_size=min(x,y)-2*thickness;

grill_2();

module grill_1(){
	difference(){
		union(){
			cube([x,y,z],center=true);
			translate([0,0,(z-thickness)/2])
				cube([x+2*lip,y+2*lip,thickness],center=true);
			}
		scale([image_size/pixils,image_size/pixils,z])
			surface(file=grill_img, center=true, convexity=10);
		translate([0,0,-(z-thickness)/2])
			cube([x-2*thickness,y-2*thickness,z-thickness],center=true);
		}
	}

module grill_2(){
	difference(){
		cube([x,y,z],center=true);
		#cube([x-2*thickness,y-2*thickness,z],center=true);
		}

	difference(){
		translate([0,0,(z-thickness)/2])
			cube([x+2*lip,y+2*lip,thickness],center=true);
		scale([image_size/pixils,image_size/pixils,z])
			surface(file=grill_img, center=true, convexity=10);
		}
	}
```