From fefb6cfe87b2737b251f14fc78e3277fa10a99c1 Mon Sep 17 00:00:00 2001 From: Pierre Jacquier Date: Fri, 27 Jun 2025 10:21:30 -0400 Subject: [PATCH 01/19] Rerun sim tests after #7608 (#7624) --- .../screenshots/surgical-drill-guide.png | Bin 0 -> 35674 bytes public/kcl-samples/screenshots/teapot.png | Bin 0 -> 131032 bytes .../multi-axis-robot/artifact_commands.snap | 168 --- .../artifact_graph_flowchart.snap.md | 963 +++++++++--------- .../kcl_samples/multi-axis-robot/ops.snap | 31 +- .../subtract_regression12/rendered_model.png | Bin 61106 -> 61104 bytes 6 files changed, 484 insertions(+), 678 deletions(-) diff --git a/public/kcl-samples/screenshots/surgical-drill-guide.png b/public/kcl-samples/screenshots/surgical-drill-guide.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b75b445e29b405abcc357d03a6c6ab2bccf55c53 100644 GIT binary patch literal 35674 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

@ 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

>g&r*BTuZ}>AKv^WotA6IQ`mb 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 WK2Llh?vjLmul{<$oMWlkfA}vnWhqSn literal 0 HcmV?d00001 diff --git a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_commands.snap b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_commands.snap index 0406a627f..07c2c5abf 100644 --- a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_commands.snap +++ b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_commands.snap @@ -2546,174 +2546,6 @@ description: Artifact commands multi-axis-robot.kcl "planar_normal": null } }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "extrude", - "target": "[uuid]", - "distance": 3.8099999999999996, - "faces": null, - "opposite": "None" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "sketch_mode_disable" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "object_bring_to_front", - "object_id": "[uuid]" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "solid3d_get_extrusion_face_info", - "object_id": "[uuid]", - "edge_id": "[uuid]" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "solid3d_get_adjacency_info", - "object_id": "[uuid]", - "edge_id": "[uuid]" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "enable_sketch_mode", - "entity_id": "[uuid]", - "ortho": false, - "animated": false, - "adjust_camera": false, - "planar_normal": null - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "extrude", - "target": "[uuid]", - "distance": 3.8099999999999996, - "faces": null, - "opposite": "None" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "sketch_mode_disable" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "object_bring_to_front", - "object_id": "[uuid]" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "solid3d_get_extrusion_face_info", - "object_id": "[uuid]", - "edge_id": "[uuid]" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "solid3d_get_adjacency_info", - "object_id": "[uuid]", - "edge_id": "[uuid]" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "enable_sketch_mode", - "entity_id": "[uuid]", - "ortho": false, - "animated": false, - "adjust_camera": false, - "planar_normal": null - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "extrude", - "target": "[uuid]", - "distance": 3.8099999999999996, - "faces": null, - "opposite": "None" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "sketch_mode_disable" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "object_bring_to_front", - "object_id": "[uuid]" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "solid3d_get_extrusion_face_info", - "object_id": "[uuid]", - "edge_id": "[uuid]" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "solid3d_get_adjacency_info", - "object_id": "[uuid]", - "edge_id": "[uuid]" - } - }, - { - "cmdId": "[uuid]", - "range": [], - "command": { - "type": "enable_sketch_mode", - "entity_id": "[uuid]", - "ortho": false, - "animated": false, - "adjust_camera": false, - "planar_normal": null - } - }, { "cmdId": "[uuid]", "range": [], diff --git a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_graph_flowchart.snap.md b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_graph_flowchart.snap.md index 7d757975e..279c0f1b3 100644 --- a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_graph_flowchart.snap.md +++ b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_graph_flowchart.snap.md @@ -92,68 +92,68 @@ flowchart LR 195["Segment
[1741, 1911, 4]"] 196[Solid2d] end - subgraph path205 [Path] - 205["Path
[2247, 2400, 4]"] - 206["Segment
[2247, 2400, 4]"] - 207[Solid2d] + subgraph path202 [Path] + 202["Path
[2247, 2400, 4]"] + 203["Segment
[2247, 2400, 4]"] + 204[Solid2d] end - subgraph path214 [Path] - 214["Path
[289, 478, 5]"] - 215["Segment
[484, 570, 5]"] - 216["Segment
[576, 630, 5]"] - 217["Segment
[636, 722, 5]"] - 218["Segment
[728, 798, 5]"] - 219["Segment
[804, 811, 5]"] - 220[Solid2d] + subgraph path211 [Path] + 211["Path
[289, 478, 5]"] + 212["Segment
[484, 570, 5]"] + 213["Segment
[576, 630, 5]"] + 214["Segment
[636, 722, 5]"] + 215["Segment
[728, 798, 5]"] + 216["Segment
[804, 811, 5]"] + 217[Solid2d] end - subgraph path236 [Path] - 236["Path
[930, 1117, 5]"] - 237["Segment
[930, 1117, 5]"] - 238[Solid2d] + subgraph path233 [Path] + 233["Path
[930, 1117, 5]"] + 234["Segment
[930, 1117, 5]"] + 235[Solid2d] end - subgraph path245 [Path] - 245["Path
[1327, 1494, 5]"] - 246["Segment
[1327, 1494, 5]"] - 247[Solid2d] + subgraph path242 [Path] + 242["Path
[1327, 1494, 5]"] + 243["Segment
[1327, 1494, 5]"] + 244[Solid2d] end - subgraph path260 [Path] - 260["Path
[1898, 2140, 5]"] - 261["Segment
[1898, 2140, 5]"] - 262[Solid2d] + subgraph path257 [Path] + 257["Path
[1898, 2140, 5]"] + 258["Segment
[1898, 2140, 5]"] + 259[Solid2d] end - subgraph path269 [Path] - 269["Path
[2244, 2484, 5]"] - 270["Segment
[2244, 2484, 5]"] - 271[Solid2d] + subgraph path266 [Path] + 266["Path
[2244, 2484, 5]"] + 267["Segment
[2244, 2484, 5]"] + 268[Solid2d] end - subgraph path278 [Path] - 278["Path
[2643, 2681, 5]"] - 279["Segment
[2643, 2681, 5]"] - 280[Solid2d] + subgraph path275 [Path] + 275["Path
[2643, 2681, 5]"] + 276["Segment
[2643, 2681, 5]"] + 277[Solid2d] end - subgraph path287 [Path] - 287["Path
[2816, 2997, 5]"] - 288["Segment
[3003, 3071, 5]"] - 289["Segment
[3077, 3187, 5]"] - 290["Segment
[3193, 3261, 5]"] - 291["Segment
[3267, 3343, 5]"] - 292["Segment
[3349, 3425, 5]"] - 293["Segment
[3431, 3505, 5]"] - 294["Segment
[3511, 3567, 5]"] - 295["Segment
[3573, 3580, 5]"] - 296[Solid2d] + subgraph path284 [Path] + 284["Path
[2816, 2997, 5]"] + 285["Segment
[3003, 3071, 5]"] + 286["Segment
[3077, 3187, 5]"] + 287["Segment
[3193, 3261, 5]"] + 288["Segment
[3267, 3343, 5]"] + 289["Segment
[3349, 3425, 5]"] + 290["Segment
[3431, 3505, 5]"] + 291["Segment
[3511, 3567, 5]"] + 292["Segment
[3573, 3580, 5]"] + 293[Solid2d] end - subgraph path321 [Path] - 321["Path
[3714, 3895, 5]"] - 322["Segment
[3901, 3971, 5]"] - 323["Segment
[3977, 4092, 5]"] - 324["Segment
[4098, 4168, 5]"] - 325["Segment
[4174, 4252, 5]"] - 326["Segment
[4258, 4336, 5]"] - 327["Segment
[4342, 4418, 5]"] - 328["Segment
[4424, 4480, 5]"] - 329["Segment
[4486, 4493, 5]"] - 330[Solid2d] + subgraph path318 [Path] + 318["Path
[3714, 3895, 5]"] + 319["Segment
[3901, 3971, 5]"] + 320["Segment
[3977, 4092, 5]"] + 321["Segment
[4098, 4168, 5]"] + 322["Segment
[4174, 4252, 5]"] + 323["Segment
[4258, 4336, 5]"] + 324["Segment
[4342, 4418, 5]"] + 325["Segment
[4424, 4480, 5]"] + 326["Segment
[4486, 4493, 5]"] + 327[Solid2d] end 1["Plane
[219, 236, 1]"] 9["Sweep Extrusion
[742, 789, 1]"] @@ -332,83 +332,86 @@ flowchart LR %% face_code_ref=Missing NodePath 200["SweepEdge Opposite"] 201["SweepEdge Adjacent"] - 202["Sweep Extrusion
[2157, 2190, 4]"] - 203["Sweep Extrusion
[2157, 2190, 4]"] - 204["Sweep Extrusion
[2157, 2190, 4]"] - 208["Sweep Extrusion
[2402, 2432, 4]"] - 209[Wall] + 205["Sweep Extrusion
[2402, 2432, 4]"] + 206[Wall] %% face_code_ref=Missing NodePath - 210["Cap End"] + 207["Cap End"] + %% face_code_ref=Missing NodePath + 208["SweepEdge Opposite"] + 209["SweepEdge Adjacent"] + 210["Plane
[260, 283, 5]"] + 218["Sweep Extrusion
[825, 873, 5]"] + 219[Wall] + %% face_code_ref=Missing NodePath + 220[Wall] + %% face_code_ref=Missing NodePath + 221[Wall] %% face_code_ref=Missing NodePath - 211["SweepEdge Opposite"] - 212["SweepEdge Adjacent"] - 213["Plane
[260, 283, 5]"] - 221["Sweep Extrusion
[825, 873, 5]"] 222[Wall] %% face_code_ref=Missing NodePath - 223[Wall] + 223["Cap Start"] + 224["Cap End"] + 225["SweepEdge Opposite"] + 226["SweepEdge Adjacent"] + 227["SweepEdge Opposite"] + 228["SweepEdge Adjacent"] + 229["SweepEdge Opposite"] + 230["SweepEdge Adjacent"] + 231["SweepEdge Opposite"] + 232["SweepEdge Adjacent"] + 236["Sweep Extrusion
[1132, 1165, 5]"] + 237[Wall] %% face_code_ref=Missing NodePath - 224[Wall] + 238["Cap End"] + 239["SweepEdge Opposite"] + 240["SweepEdge Adjacent"] + 241["EdgeCut Fillet
[1171, 1233, 5]"] + 245["Sweep Extrusion
[1737, 1770, 5]"] + 246[Wall] %% face_code_ref=Missing NodePath - 225[Wall] + 247["Cap End"] %% face_code_ref=Missing NodePath - 226["Cap Start"] - 227["Cap End"] - 228["SweepEdge Opposite"] - 229["SweepEdge Adjacent"] - 230["SweepEdge Opposite"] - 231["SweepEdge Adjacent"] - 232["SweepEdge Opposite"] - 233["SweepEdge Adjacent"] - 234["SweepEdge Opposite"] - 235["SweepEdge Adjacent"] - 239["Sweep Extrusion
[1132, 1165, 5]"] - 240[Wall] - %% face_code_ref=Missing NodePath - 241["Cap End"] - 242["SweepEdge Opposite"] - 243["SweepEdge Adjacent"] - 244["EdgeCut Fillet
[1171, 1233, 5]"] - 248["Sweep Extrusion
[1737, 1770, 5]"] - 249[Wall] - %% face_code_ref=Missing NodePath - 250["Cap End"] - %% face_code_ref=Missing NodePath - 251["SweepEdge Opposite"] - 252["SweepEdge Adjacent"] + 248["SweepEdge Opposite"] + 249["SweepEdge Adjacent"] + 250["Sweep Extrusion
[1737, 1770, 5]"] + 251["Sweep Extrusion
[1737, 1770, 5]"] + 252["Sweep Extrusion
[1737, 1770, 5]"] 253["Sweep Extrusion
[1737, 1770, 5]"] 254["Sweep Extrusion
[1737, 1770, 5]"] 255["Sweep Extrusion
[1737, 1770, 5]"] 256["Sweep Extrusion
[1737, 1770, 5]"] - 257["Sweep Extrusion
[1737, 1770, 5]"] - 258["Sweep Extrusion
[1737, 1770, 5]"] - 259["Sweep Extrusion
[1737, 1770, 5]"] - 263["Sweep Extrusion
[2154, 2187, 5]"] - 264[Wall] + 260["Sweep Extrusion
[2154, 2187, 5]"] + 261[Wall] %% face_code_ref=Missing NodePath - 265["Cap Start"] + 262["Cap Start"] %% face_code_ref=Missing NodePath - 266["Cap End"] + 263["Cap End"] %% face_code_ref=Missing NodePath - 267["SweepEdge Opposite"] - 268["SweepEdge Adjacent"] - 272["Sweep Extrusion
[2499, 2532, 5]"] - 273[Wall] + 264["SweepEdge Opposite"] + 265["SweepEdge Adjacent"] + 269["Sweep Extrusion
[2499, 2532, 5]"] + 270[Wall] %% face_code_ref=Missing NodePath - 274["Cap Start"] - 275["Cap End"] + 271["Cap Start"] + 272["Cap End"] %% face_code_ref=Missing NodePath - 276["SweepEdge Opposite"] - 277["SweepEdge Adjacent"] - 281["Sweep Extrusion
[2696, 2730, 5]"] - 282[Wall] + 273["SweepEdge Opposite"] + 274["SweepEdge Adjacent"] + 278["Sweep Extrusion
[2696, 2730, 5]"] + 279[Wall] %% face_code_ref=Missing NodePath - 283["Cap Start"] - 284["Cap End"] + 280["Cap Start"] + 281["Cap End"] + %% face_code_ref=Missing NodePath + 282["SweepEdge Opposite"] + 283["SweepEdge Adjacent"] + 294["Sweep Extrusion
[3595, 3628, 5]"] + 295[Wall] + %% face_code_ref=Missing NodePath + 296[Wall] + %% face_code_ref=Missing NodePath + 297[Wall] %% face_code_ref=Missing NodePath - 285["SweepEdge Opposite"] - 286["SweepEdge Adjacent"] - 297["Sweep Extrusion
[3595, 3628, 5]"] 298[Wall] %% face_code_ref=Missing NodePath 299[Wall] @@ -417,31 +420,31 @@ flowchart LR %% face_code_ref=Missing NodePath 301[Wall] %% face_code_ref=Missing NodePath - 302[Wall] + 302["Cap Start"] %% face_code_ref=Missing NodePath - 303[Wall] + 303["Cap End"] %% face_code_ref=Missing NodePath - 304[Wall] + 304["SweepEdge Opposite"] + 305["SweepEdge Adjacent"] + 306["SweepEdge Opposite"] + 307["SweepEdge Adjacent"] + 308["SweepEdge Opposite"] + 309["SweepEdge Adjacent"] + 310["SweepEdge Opposite"] + 311["SweepEdge Adjacent"] + 312["SweepEdge Opposite"] + 313["SweepEdge Adjacent"] + 314["SweepEdge Opposite"] + 315["SweepEdge Adjacent"] + 316["SweepEdge Opposite"] + 317["SweepEdge Adjacent"] + 328["Sweep Extrusion
[4495, 4528, 5]"] + 329[Wall] %% face_code_ref=Missing NodePath - 305["Cap Start"] + 330[Wall] %% face_code_ref=Missing NodePath - 306["Cap End"] + 331[Wall] %% face_code_ref=Missing NodePath - 307["SweepEdge Opposite"] - 308["SweepEdge Adjacent"] - 309["SweepEdge Opposite"] - 310["SweepEdge Adjacent"] - 311["SweepEdge Opposite"] - 312["SweepEdge Adjacent"] - 313["SweepEdge Opposite"] - 314["SweepEdge Adjacent"] - 315["SweepEdge Opposite"] - 316["SweepEdge Adjacent"] - 317["SweepEdge Opposite"] - 318["SweepEdge Adjacent"] - 319["SweepEdge Opposite"] - 320["SweepEdge Adjacent"] - 331["Sweep Extrusion
[4495, 4528, 5]"] 332[Wall] %% face_code_ref=Missing NodePath 333[Wall] @@ -450,49 +453,43 @@ flowchart LR %% face_code_ref=Missing NodePath 335[Wall] %% face_code_ref=Missing NodePath - 336[Wall] + 336["Cap Start"] %% face_code_ref=Missing NodePath - 337[Wall] + 337["Cap End"] %% face_code_ref=Missing NodePath - 338[Wall] - %% face_code_ref=Missing NodePath - 339["Cap Start"] - %% face_code_ref=Missing NodePath - 340["Cap End"] - %% face_code_ref=Missing NodePath - 341["SweepEdge Opposite"] - 342["SweepEdge Adjacent"] - 343["SweepEdge Opposite"] - 344["SweepEdge Adjacent"] - 345["SweepEdge Opposite"] - 346["SweepEdge Adjacent"] - 347["SweepEdge Opposite"] - 348["SweepEdge Adjacent"] - 349["SweepEdge Opposite"] - 350["SweepEdge Adjacent"] - 351["SweepEdge Opposite"] - 352["SweepEdge Adjacent"] - 353["SweepEdge Opposite"] - 354["SweepEdge Adjacent"] - 355["StartSketchOnFace
[1126, 1163, 1]"] - 356["StartSketchOnFace
[1386, 1423, 1]"] - 357["StartSketchOnFace
[1560, 1597, 1]"] - 358["StartSketchOnFace
[1951, 1988, 1]"] - 359["StartSketchOnFace
[840, 877, 3]"] - 360["StartSketchOnFace
[1202, 1239, 3]"] - 361["StartSketchOnFace
[1627, 1664, 3]"] - 362["StartSketchOnFace
[777, 816, 4]"] - 363["StartSketchOnFace
[1015, 1054, 4]"] - 364["StartSketchOnFace
[1411, 1448, 4]"] - 365["StartSketchOnFace
[1698, 1735, 4]"] - 366["StartSketchOnFace
[2204, 2241, 4]"] - 367["StartSketchOnFace
[887, 924, 5]"] - 368["StartSketchOnFace
[1284, 1321, 5]"] - 369["StartSketchOnFace
[1853, 1892, 5]"] - 370["StartSketchOnFace
[2201, 2238, 5]"] - 371["StartSketchOnFace
[2598, 2637, 5]"] - 372["StartSketchOnFace
[2771, 2810, 5]"] - 373["StartSketchOnFace
[3669, 3708, 5]"] + 338["SweepEdge Opposite"] + 339["SweepEdge Adjacent"] + 340["SweepEdge Opposite"] + 341["SweepEdge Adjacent"] + 342["SweepEdge Opposite"] + 343["SweepEdge Adjacent"] + 344["SweepEdge Opposite"] + 345["SweepEdge Adjacent"] + 346["SweepEdge Opposite"] + 347["SweepEdge Adjacent"] + 348["SweepEdge Opposite"] + 349["SweepEdge Adjacent"] + 350["SweepEdge Opposite"] + 351["SweepEdge Adjacent"] + 352["StartSketchOnFace
[1126, 1163, 1]"] + 353["StartSketchOnFace
[1386, 1423, 1]"] + 354["StartSketchOnFace
[1560, 1597, 1]"] + 355["StartSketchOnFace
[1951, 1988, 1]"] + 356["StartSketchOnFace
[840, 877, 3]"] + 357["StartSketchOnFace
[1202, 1239, 3]"] + 358["StartSketchOnFace
[1627, 1664, 3]"] + 359["StartSketchOnFace
[777, 816, 4]"] + 360["StartSketchOnFace
[1015, 1054, 4]"] + 361["StartSketchOnFace
[1411, 1448, 4]"] + 362["StartSketchOnFace
[1698, 1735, 4]"] + 363["StartSketchOnFace
[2204, 2241, 4]"] + 364["StartSketchOnFace
[887, 924, 5]"] + 365["StartSketchOnFace
[1284, 1321, 5]"] + 366["StartSketchOnFace
[1853, 1892, 5]"] + 367["StartSketchOnFace
[2201, 2238, 5]"] + 368["StartSketchOnFace
[2598, 2637, 5]"] + 369["StartSketchOnFace
[2771, 2810, 5]"] + 370["StartSketchOnFace
[3669, 3708, 5]"] 1 --- 2 2 --- 3 2 --- 4 @@ -555,9 +552,9 @@ flowchart LR 46 <--x 15 15 --- 55 56 <--x 15 + 15 <--x 352 + 15 <--x 354 15 <--x 355 - 15 <--x 357 - 15 <--x 358 17 <--x 24 19 <--x 25 21 <--x 26 @@ -577,7 +574,7 @@ flowchart LR 34 <--x 33 33 --- 37 38 <--x 33 - 33 <--x 356 + 33 <--x 353 34 <--x 36 37 --- 38 37 --- 39 @@ -687,7 +684,7 @@ flowchart LR 97 <--x 90 90 --- 99 100 <--x 90 - 90 <--x 359 + 90 <--x 356 99 --- 100 99 --- 101 99 ---- 102 @@ -705,8 +702,8 @@ flowchart LR 109 <--x 104 104 --- 119 120 <--x 104 - 104 <--x 360 - 104 <--x 361 + 104 <--x 357 + 104 <--x 358 105 <--x 107 108 --- 109 108 --- 110 @@ -809,11 +806,11 @@ flowchart LR 162 <--x 151 151 --- 170 171 <--x 151 - 151 <--x 362 - 151 <--x 363 - 152 --- 205 - 206 <--x 152 - 152 <--x 366 + 151 <--x 359 + 151 <--x 360 + 152 --- 202 + 203 <--x 152 + 152 <--x 363 161 --- 162 161 --- 163 161 ---- 164 @@ -829,7 +826,7 @@ flowchart LR 167 <--x 166 166 --- 179 180 <--x 166 - 166 <--x 364 + 166 <--x 361 167 <--x 169 170 --- 171 170 --- 172 @@ -846,7 +843,7 @@ flowchart LR 176 <--x 175 175 --- 194 195 <--x 175 - 175 <--x 365 + 175 <--x 362 176 <--x 178 179 --- 180 179 --- 181 @@ -874,337 +871,337 @@ flowchart LR 198 --- 200 198 --- 201 200 <--x 199 + 202 --- 203 + 202 --- 204 + 202 ---- 205 + 203 --- 206 + 203 --- 208 + 203 --- 209 205 --- 206 205 --- 207 - 205 ---- 208 + 205 --- 208 + 205 --- 209 + 206 --- 208 206 --- 209 - 206 --- 211 - 206 --- 212 - 208 --- 209 - 208 --- 210 - 208 --- 211 - 208 --- 212 - 209 --- 211 - 209 --- 212 - 211 <--x 210 - 213 --- 214 - 214 --- 215 - 214 --- 216 - 214 --- 217 - 214 --- 218 - 214 --- 219 - 214 --- 220 - 214 ---- 221 + 208 <--x 207 + 210 --- 211 + 211 --- 212 + 211 --- 213 + 211 --- 214 + 211 --- 215 + 211 --- 216 + 211 --- 217 + 211 ---- 218 + 212 --- 219 + 212 x--> 223 + 212 --- 225 + 212 --- 226 + 213 --- 220 + 213 x--> 223 + 213 --- 227 + 213 --- 228 + 214 --- 221 + 214 x--> 223 + 214 --- 229 + 214 --- 230 215 --- 222 - 215 x--> 226 - 215 --- 228 - 215 --- 229 - 216 --- 223 - 216 x--> 226 - 216 --- 230 - 216 --- 231 - 217 --- 224 - 217 x--> 226 - 217 --- 232 - 217 --- 233 + 215 x--> 223 + 215 --- 231 + 215 --- 232 + 218 --- 219 + 218 --- 220 + 218 --- 221 + 218 --- 222 + 218 --- 223 + 218 --- 224 218 --- 225 - 218 x--> 226 - 218 --- 234 - 218 --- 235 - 221 --- 222 - 221 --- 223 - 221 --- 224 - 221 --- 225 - 221 --- 226 - 221 --- 227 - 221 --- 228 + 218 --- 226 + 218 --- 227 + 218 --- 228 + 218 --- 229 + 218 --- 230 + 218 --- 231 + 218 --- 232 + 219 --- 225 + 219 --- 226 + 232 <--x 219 + 226 <--x 220 + 220 --- 227 + 220 --- 228 + 228 <--x 221 221 --- 229 221 --- 230 - 221 --- 231 - 221 --- 232 - 221 --- 233 - 221 --- 234 - 221 --- 235 - 222 --- 228 - 222 --- 229 - 235 <--x 222 - 229 <--x 223 - 223 --- 230 - 223 --- 231 + 230 <--x 222 + 222 --- 231 + 222 --- 232 + 223 --- 257 + 223 <--x 366 + 225 <--x 224 + 227 <--x 224 + 229 <--x 224 231 <--x 224 - 224 --- 232 224 --- 233 - 233 <--x 225 - 225 --- 234 - 225 --- 235 - 226 --- 260 - 226 <--x 369 - 228 <--x 227 - 230 <--x 227 - 232 <--x 227 - 234 <--x 227 - 227 --- 236 - 237 <--x 227 - 227 --- 269 - 227 <--x 367 - 227 <--x 370 + 234 <--x 224 + 224 --- 266 + 224 <--x 364 + 224 <--x 367 + 233 --- 234 + 233 --- 235 + 233 ---- 236 + 234 --- 237 + 234 --- 239 + 234 --- 240 236 --- 237 236 --- 238 - 236 ---- 239 + 236 --- 239 + 236 --- 240 + 237 --- 239 237 --- 240 - 237 --- 242 - 237 --- 243 - 239 --- 240 - 239 --- 241 - 239 --- 242 - 239 --- 243 - 240 --- 242 - 240 --- 243 - 242 <--x 241 - 241 --- 245 - 246 <--x 241 - 241 <--x 368 - 242 <--x 244 + 239 <--x 238 + 238 --- 242 + 243 <--x 238 + 238 <--x 365 + 239 <--x 241 + 242 --- 243 + 242 --- 244 + 242 ---- 245 + 243 --- 246 + 243 --- 248 + 243 --- 249 245 --- 246 245 --- 247 - 245 ---- 248 + 245 --- 248 + 245 --- 249 + 246 --- 248 246 --- 249 - 246 --- 251 - 246 --- 252 - 248 --- 249 - 248 --- 250 - 248 --- 251 - 248 --- 252 - 249 --- 251 - 249 --- 252 - 251 <--x 250 + 248 <--x 247 + 257 --- 258 + 257 --- 259 + 257 ---- 260 + 258 --- 261 + 258 x--> 263 + 258 --- 264 + 258 --- 265 260 --- 261 260 --- 262 - 260 ---- 263 + 260 --- 263 + 260 --- 264 + 260 --- 265 261 --- 264 - 261 x--> 266 - 261 --- 267 - 261 --- 268 - 263 --- 264 - 263 --- 265 - 263 --- 266 - 263 --- 267 - 263 --- 268 - 264 --- 267 - 264 --- 268 - 267 <--x 265 + 261 --- 265 + 264 <--x 262 + 266 --- 267 + 266 --- 268 + 266 ---- 269 + 267 --- 270 + 267 x--> 272 + 267 --- 273 + 267 --- 274 269 --- 270 269 --- 271 - 269 ---- 272 + 269 --- 272 + 269 --- 273 + 269 --- 274 270 --- 273 - 270 x--> 275 - 270 --- 276 - 270 --- 277 - 272 --- 273 - 272 --- 274 - 272 --- 275 - 272 --- 276 - 272 --- 277 - 273 --- 276 - 273 --- 277 - 276 <--x 274 - 274 --- 278 - 274 <--x 371 + 270 --- 274 + 273 <--x 271 + 271 --- 275 + 271 <--x 368 + 275 --- 276 + 275 --- 277 + 275 ---- 278 + 276 --- 279 + 276 x--> 281 + 276 --- 282 + 276 --- 283 278 --- 279 278 --- 280 - 278 ---- 281 + 278 --- 281 + 278 --- 282 + 278 --- 283 279 --- 282 - 279 x--> 284 - 279 --- 285 - 279 --- 286 - 281 --- 282 - 281 --- 283 - 281 --- 284 - 281 --- 285 - 281 --- 286 - 282 --- 285 - 282 --- 286 - 285 <--x 283 - 283 --- 287 - 283 --- 321 - 283 <--x 372 - 283 <--x 373 - 287 --- 288 - 287 --- 289 - 287 --- 290 - 287 --- 291 - 287 --- 292 - 287 --- 293 - 287 --- 294 - 287 --- 295 - 287 --- 296 - 287 ---- 297 + 279 --- 283 + 282 <--x 280 + 280 --- 284 + 280 --- 318 + 280 <--x 369 + 280 <--x 370 + 284 --- 285 + 284 --- 286 + 284 --- 287 + 284 --- 288 + 284 --- 289 + 284 --- 290 + 284 --- 291 + 284 --- 292 + 284 --- 293 + 284 ---- 294 + 285 --- 295 + 285 x--> 303 + 285 --- 304 + 285 --- 305 + 286 --- 296 + 286 x--> 303 + 286 --- 306 + 286 --- 307 + 287 --- 297 + 287 x--> 303 + 287 --- 308 + 287 --- 309 288 --- 298 - 288 x--> 306 - 288 --- 307 - 288 --- 308 + 288 x--> 303 + 288 --- 310 + 288 --- 311 289 --- 299 - 289 x--> 306 - 289 --- 309 - 289 --- 310 + 289 x--> 303 + 289 --- 312 + 289 --- 313 290 --- 300 - 290 x--> 306 - 290 --- 311 - 290 --- 312 + 290 x--> 303 + 290 --- 314 + 290 --- 315 291 --- 301 - 291 x--> 306 - 291 --- 313 - 291 --- 314 - 292 --- 302 - 292 x--> 306 - 292 --- 315 - 292 --- 316 - 293 --- 303 - 293 x--> 306 - 293 --- 317 - 293 --- 318 + 291 x--> 303 + 291 --- 316 + 291 --- 317 + 294 --- 295 + 294 --- 296 + 294 --- 297 + 294 --- 298 + 294 --- 299 + 294 --- 300 + 294 --- 301 + 294 --- 302 + 294 --- 303 294 --- 304 - 294 x--> 306 - 294 --- 319 - 294 --- 320 - 297 --- 298 - 297 --- 299 - 297 --- 300 - 297 --- 301 - 297 --- 302 - 297 --- 303 - 297 --- 304 - 297 --- 305 - 297 --- 306 - 297 --- 307 + 294 --- 305 + 294 --- 306 + 294 --- 307 + 294 --- 308 + 294 --- 309 + 294 --- 310 + 294 --- 311 + 294 --- 312 + 294 --- 313 + 294 --- 314 + 294 --- 315 + 294 --- 316 + 294 --- 317 + 295 --- 304 + 295 --- 305 + 317 <--x 295 + 305 <--x 296 + 296 --- 306 + 296 --- 307 + 307 <--x 297 297 --- 308 297 --- 309 - 297 --- 310 - 297 --- 311 - 297 --- 312 - 297 --- 313 - 297 --- 314 - 297 --- 315 - 297 --- 316 - 297 --- 317 - 297 --- 318 - 297 --- 319 - 297 --- 320 - 298 --- 307 - 298 --- 308 - 320 <--x 298 - 308 <--x 299 - 299 --- 309 - 299 --- 310 - 310 <--x 300 - 300 --- 311 - 300 --- 312 - 312 <--x 301 - 301 --- 313 - 301 --- 314 + 309 <--x 298 + 298 --- 310 + 298 --- 311 + 311 <--x 299 + 299 --- 312 + 299 --- 313 + 313 <--x 300 + 300 --- 314 + 300 --- 315 + 315 <--x 301 + 301 --- 316 + 301 --- 317 + 304 <--x 302 + 306 <--x 302 + 308 <--x 302 + 310 <--x 302 + 312 <--x 302 314 <--x 302 - 302 --- 315 - 302 --- 316 - 316 <--x 303 - 303 --- 317 - 303 --- 318 - 318 <--x 304 - 304 --- 319 - 304 --- 320 - 307 <--x 305 - 309 <--x 305 - 311 <--x 305 - 313 <--x 305 - 315 <--x 305 - 317 <--x 305 - 319 <--x 305 - 321 --- 322 - 321 --- 323 - 321 --- 324 - 321 --- 325 - 321 --- 326 - 321 --- 327 - 321 --- 328 - 321 --- 329 - 321 --- 330 - 321 ---- 331 - 322 --- 338 - 322 x--> 340 - 322 --- 353 - 322 --- 354 - 323 --- 337 - 323 x--> 340 - 323 --- 351 - 323 --- 352 - 324 --- 336 - 324 x--> 340 - 324 --- 349 - 324 --- 350 - 325 --- 335 - 325 x--> 340 - 325 --- 347 - 325 --- 348 - 326 --- 334 - 326 x--> 340 - 326 --- 345 - 326 --- 346 - 327 --- 333 - 327 x--> 340 - 327 --- 343 - 327 --- 344 + 316 <--x 302 + 318 --- 319 + 318 --- 320 + 318 --- 321 + 318 --- 322 + 318 --- 323 + 318 --- 324 + 318 --- 325 + 318 --- 326 + 318 --- 327 + 318 ---- 328 + 319 --- 335 + 319 x--> 337 + 319 --- 350 + 319 --- 351 + 320 --- 334 + 320 x--> 337 + 320 --- 348 + 320 --- 349 + 321 --- 333 + 321 x--> 337 + 321 --- 346 + 321 --- 347 + 322 --- 332 + 322 x--> 337 + 322 --- 344 + 322 --- 345 + 323 --- 331 + 323 x--> 337 + 323 --- 342 + 323 --- 343 + 324 --- 330 + 324 x--> 337 + 324 --- 340 + 324 --- 341 + 325 --- 329 + 325 x--> 337 + 325 --- 338 + 325 --- 339 + 328 --- 329 + 328 --- 330 + 328 --- 331 328 --- 332 - 328 x--> 340 + 328 --- 333 + 328 --- 334 + 328 --- 335 + 328 --- 336 + 328 --- 337 + 328 --- 338 + 328 --- 339 + 328 --- 340 328 --- 341 328 --- 342 - 331 --- 332 - 331 --- 333 - 331 --- 334 - 331 --- 335 - 331 --- 336 - 331 --- 337 - 331 --- 338 - 331 --- 339 - 331 --- 340 - 331 --- 341 + 328 --- 343 + 328 --- 344 + 328 --- 345 + 328 --- 346 + 328 --- 347 + 328 --- 348 + 328 --- 349 + 328 --- 350 + 328 --- 351 + 329 --- 338 + 329 --- 339 + 341 <--x 329 + 330 --- 340 + 330 --- 341 + 343 <--x 330 331 --- 342 331 --- 343 - 331 --- 344 - 331 --- 345 - 331 --- 346 - 331 --- 347 - 331 --- 348 - 331 --- 349 - 331 --- 350 - 331 --- 351 - 331 --- 352 - 331 --- 353 - 331 --- 354 - 332 --- 341 - 332 --- 342 - 344 <--x 332 - 333 --- 343 - 333 --- 344 - 346 <--x 333 - 334 --- 345 - 334 --- 346 - 348 <--x 334 - 335 --- 347 - 335 --- 348 - 350 <--x 335 - 336 --- 349 - 336 --- 350 - 352 <--x 336 - 337 --- 351 - 337 --- 352 - 354 <--x 337 - 342 <--x 338 - 338 --- 353 - 338 --- 354 - 341 <--x 339 - 343 <--x 339 - 345 <--x 339 - 347 <--x 339 - 349 <--x 339 - 351 <--x 339 - 353 <--x 339 + 345 <--x 331 + 332 --- 344 + 332 --- 345 + 347 <--x 332 + 333 --- 346 + 333 --- 347 + 349 <--x 333 + 334 --- 348 + 334 --- 349 + 351 <--x 334 + 339 <--x 335 + 335 --- 350 + 335 --- 351 + 338 <--x 336 + 340 <--x 336 + 342 <--x 336 + 344 <--x 336 + 346 <--x 336 + 348 <--x 336 + 350 <--x 336 ``` diff --git a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/ops.snap b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/ops.snap index 986372dec..adec9fa53 100644 --- a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/ops.snap +++ b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/ops.snap @@ -1253,33 +1253,10 @@ description: Operations executed multi-axis-robot.kcl "name": "extrude", "unlabeledArg": { "value": { - "type": "Array", - "value": [ - { - "type": "Sketch", - "value": { - "artifactId": "[uuid]" - } - }, - { - "type": "Sketch", - "value": { - "artifactId": "[uuid]" - } - }, - { - "type": "Sketch", - "value": { - "artifactId": "[uuid]" - } - }, - { - "type": "Sketch", - "value": { - "artifactId": "[uuid]" - } - } - ] + "type": "Sketch", + "value": { + "artifactId": "[uuid]" + } }, "sourceRange": [] }, diff --git a/rust/kcl-lib/tests/subtract_regression12/rendered_model.png b/rust/kcl-lib/tests/subtract_regression12/rendered_model.png index 5aae217e389d3d0ffdf432404087fb0357d91ca7..c541dac7c7aa7f094e673795d0a99d9ce484697a 100644 GIT binary patch delta 14583 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 delta 14577 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 Date: Fri, 27 Jun 2025 13:29:27 -0400 Subject: [PATCH 02/19] Update output to match main (#7630) --- .../multi-axis-robot/artifact_commands.snap | 168 +++ .../artifact_graph_flowchart.snap.md | 963 +++++++++--------- .../kcl_samples/multi-axis-robot/ops.snap | 31 +- 3 files changed, 678 insertions(+), 484 deletions(-) diff --git a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_commands.snap b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_commands.snap index 07c2c5abf..0406a627f 100644 --- a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_commands.snap +++ b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_commands.snap @@ -2546,6 +2546,174 @@ description: Artifact commands multi-axis-robot.kcl "planar_normal": null } }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extrude", + "target": "[uuid]", + "distance": 3.8099999999999996, + "faces": null, + "opposite": "None" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_bring_to_front", + "object_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_extrusion_face_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_adjacency_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": null + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extrude", + "target": "[uuid]", + "distance": 3.8099999999999996, + "faces": null, + "opposite": "None" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_bring_to_front", + "object_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_extrusion_face_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_adjacency_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": null + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extrude", + "target": "[uuid]", + "distance": 3.8099999999999996, + "faces": null, + "opposite": "None" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_bring_to_front", + "object_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_extrusion_face_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_adjacency_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": null + } + }, { "cmdId": "[uuid]", "range": [], diff --git a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_graph_flowchart.snap.md b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_graph_flowchart.snap.md index 279c0f1b3..7d757975e 100644 --- a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_graph_flowchart.snap.md +++ b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/artifact_graph_flowchart.snap.md @@ -92,68 +92,68 @@ flowchart LR 195["Segment
[1741, 1911, 4]"] 196[Solid2d] end - subgraph path202 [Path] - 202["Path
[2247, 2400, 4]"] - 203["Segment
[2247, 2400, 4]"] - 204[Solid2d] + subgraph path205 [Path] + 205["Path
[2247, 2400, 4]"] + 206["Segment
[2247, 2400, 4]"] + 207[Solid2d] end - subgraph path211 [Path] - 211["Path
[289, 478, 5]"] - 212["Segment
[484, 570, 5]"] - 213["Segment
[576, 630, 5]"] - 214["Segment
[636, 722, 5]"] - 215["Segment
[728, 798, 5]"] - 216["Segment
[804, 811, 5]"] - 217[Solid2d] + subgraph path214 [Path] + 214["Path
[289, 478, 5]"] + 215["Segment
[484, 570, 5]"] + 216["Segment
[576, 630, 5]"] + 217["Segment
[636, 722, 5]"] + 218["Segment
[728, 798, 5]"] + 219["Segment
[804, 811, 5]"] + 220[Solid2d] end - subgraph path233 [Path] - 233["Path
[930, 1117, 5]"] - 234["Segment
[930, 1117, 5]"] - 235[Solid2d] + subgraph path236 [Path] + 236["Path
[930, 1117, 5]"] + 237["Segment
[930, 1117, 5]"] + 238[Solid2d] end - subgraph path242 [Path] - 242["Path
[1327, 1494, 5]"] - 243["Segment
[1327, 1494, 5]"] - 244[Solid2d] + subgraph path245 [Path] + 245["Path
[1327, 1494, 5]"] + 246["Segment
[1327, 1494, 5]"] + 247[Solid2d] end - subgraph path257 [Path] - 257["Path
[1898, 2140, 5]"] - 258["Segment
[1898, 2140, 5]"] - 259[Solid2d] + subgraph path260 [Path] + 260["Path
[1898, 2140, 5]"] + 261["Segment
[1898, 2140, 5]"] + 262[Solid2d] end - subgraph path266 [Path] - 266["Path
[2244, 2484, 5]"] - 267["Segment
[2244, 2484, 5]"] - 268[Solid2d] + subgraph path269 [Path] + 269["Path
[2244, 2484, 5]"] + 270["Segment
[2244, 2484, 5]"] + 271[Solid2d] end - subgraph path275 [Path] - 275["Path
[2643, 2681, 5]"] - 276["Segment
[2643, 2681, 5]"] - 277[Solid2d] + subgraph path278 [Path] + 278["Path
[2643, 2681, 5]"] + 279["Segment
[2643, 2681, 5]"] + 280[Solid2d] end - subgraph path284 [Path] - 284["Path
[2816, 2997, 5]"] - 285["Segment
[3003, 3071, 5]"] - 286["Segment
[3077, 3187, 5]"] - 287["Segment
[3193, 3261, 5]"] - 288["Segment
[3267, 3343, 5]"] - 289["Segment
[3349, 3425, 5]"] - 290["Segment
[3431, 3505, 5]"] - 291["Segment
[3511, 3567, 5]"] - 292["Segment
[3573, 3580, 5]"] - 293[Solid2d] + subgraph path287 [Path] + 287["Path
[2816, 2997, 5]"] + 288["Segment
[3003, 3071, 5]"] + 289["Segment
[3077, 3187, 5]"] + 290["Segment
[3193, 3261, 5]"] + 291["Segment
[3267, 3343, 5]"] + 292["Segment
[3349, 3425, 5]"] + 293["Segment
[3431, 3505, 5]"] + 294["Segment
[3511, 3567, 5]"] + 295["Segment
[3573, 3580, 5]"] + 296[Solid2d] end - subgraph path318 [Path] - 318["Path
[3714, 3895, 5]"] - 319["Segment
[3901, 3971, 5]"] - 320["Segment
[3977, 4092, 5]"] - 321["Segment
[4098, 4168, 5]"] - 322["Segment
[4174, 4252, 5]"] - 323["Segment
[4258, 4336, 5]"] - 324["Segment
[4342, 4418, 5]"] - 325["Segment
[4424, 4480, 5]"] - 326["Segment
[4486, 4493, 5]"] - 327[Solid2d] + subgraph path321 [Path] + 321["Path
[3714, 3895, 5]"] + 322["Segment
[3901, 3971, 5]"] + 323["Segment
[3977, 4092, 5]"] + 324["Segment
[4098, 4168, 5]"] + 325["Segment
[4174, 4252, 5]"] + 326["Segment
[4258, 4336, 5]"] + 327["Segment
[4342, 4418, 5]"] + 328["Segment
[4424, 4480, 5]"] + 329["Segment
[4486, 4493, 5]"] + 330[Solid2d] end 1["Plane
[219, 236, 1]"] 9["Sweep Extrusion
[742, 789, 1]"] @@ -332,86 +332,83 @@ flowchart LR %% face_code_ref=Missing NodePath 200["SweepEdge Opposite"] 201["SweepEdge Adjacent"] - 205["Sweep Extrusion
[2402, 2432, 4]"] - 206[Wall] + 202["Sweep Extrusion
[2157, 2190, 4]"] + 203["Sweep Extrusion
[2157, 2190, 4]"] + 204["Sweep Extrusion
[2157, 2190, 4]"] + 208["Sweep Extrusion
[2402, 2432, 4]"] + 209[Wall] %% face_code_ref=Missing NodePath - 207["Cap End"] - %% face_code_ref=Missing NodePath - 208["SweepEdge Opposite"] - 209["SweepEdge Adjacent"] - 210["Plane
[260, 283, 5]"] - 218["Sweep Extrusion
[825, 873, 5]"] - 219[Wall] - %% face_code_ref=Missing NodePath - 220[Wall] - %% face_code_ref=Missing NodePath - 221[Wall] + 210["Cap End"] %% face_code_ref=Missing NodePath + 211["SweepEdge Opposite"] + 212["SweepEdge Adjacent"] + 213["Plane
[260, 283, 5]"] + 221["Sweep Extrusion
[825, 873, 5]"] 222[Wall] %% face_code_ref=Missing NodePath - 223["Cap Start"] - 224["Cap End"] - 225["SweepEdge Opposite"] - 226["SweepEdge Adjacent"] - 227["SweepEdge Opposite"] - 228["SweepEdge Adjacent"] - 229["SweepEdge Opposite"] - 230["SweepEdge Adjacent"] - 231["SweepEdge Opposite"] - 232["SweepEdge Adjacent"] - 236["Sweep Extrusion
[1132, 1165, 5]"] - 237[Wall] + 223[Wall] %% face_code_ref=Missing NodePath - 238["Cap End"] - 239["SweepEdge Opposite"] - 240["SweepEdge Adjacent"] - 241["EdgeCut Fillet
[1171, 1233, 5]"] - 245["Sweep Extrusion
[1737, 1770, 5]"] - 246[Wall] + 224[Wall] %% face_code_ref=Missing NodePath - 247["Cap End"] + 225[Wall] %% face_code_ref=Missing NodePath - 248["SweepEdge Opposite"] - 249["SweepEdge Adjacent"] - 250["Sweep Extrusion
[1737, 1770, 5]"] - 251["Sweep Extrusion
[1737, 1770, 5]"] - 252["Sweep Extrusion
[1737, 1770, 5]"] + 226["Cap Start"] + 227["Cap End"] + 228["SweepEdge Opposite"] + 229["SweepEdge Adjacent"] + 230["SweepEdge Opposite"] + 231["SweepEdge Adjacent"] + 232["SweepEdge Opposite"] + 233["SweepEdge Adjacent"] + 234["SweepEdge Opposite"] + 235["SweepEdge Adjacent"] + 239["Sweep Extrusion
[1132, 1165, 5]"] + 240[Wall] + %% face_code_ref=Missing NodePath + 241["Cap End"] + 242["SweepEdge Opposite"] + 243["SweepEdge Adjacent"] + 244["EdgeCut Fillet
[1171, 1233, 5]"] + 248["Sweep Extrusion
[1737, 1770, 5]"] + 249[Wall] + %% face_code_ref=Missing NodePath + 250["Cap End"] + %% face_code_ref=Missing NodePath + 251["SweepEdge Opposite"] + 252["SweepEdge Adjacent"] 253["Sweep Extrusion
[1737, 1770, 5]"] 254["Sweep Extrusion
[1737, 1770, 5]"] 255["Sweep Extrusion
[1737, 1770, 5]"] 256["Sweep Extrusion
[1737, 1770, 5]"] - 260["Sweep Extrusion
[2154, 2187, 5]"] - 261[Wall] + 257["Sweep Extrusion
[1737, 1770, 5]"] + 258["Sweep Extrusion
[1737, 1770, 5]"] + 259["Sweep Extrusion
[1737, 1770, 5]"] + 263["Sweep Extrusion
[2154, 2187, 5]"] + 264[Wall] %% face_code_ref=Missing NodePath - 262["Cap Start"] + 265["Cap Start"] %% face_code_ref=Missing NodePath - 263["Cap End"] + 266["Cap End"] %% face_code_ref=Missing NodePath - 264["SweepEdge Opposite"] - 265["SweepEdge Adjacent"] - 269["Sweep Extrusion
[2499, 2532, 5]"] - 270[Wall] + 267["SweepEdge Opposite"] + 268["SweepEdge Adjacent"] + 272["Sweep Extrusion
[2499, 2532, 5]"] + 273[Wall] %% face_code_ref=Missing NodePath - 271["Cap Start"] - 272["Cap End"] + 274["Cap Start"] + 275["Cap End"] %% face_code_ref=Missing NodePath - 273["SweepEdge Opposite"] - 274["SweepEdge Adjacent"] - 278["Sweep Extrusion
[2696, 2730, 5]"] - 279[Wall] + 276["SweepEdge Opposite"] + 277["SweepEdge Adjacent"] + 281["Sweep Extrusion
[2696, 2730, 5]"] + 282[Wall] %% face_code_ref=Missing NodePath - 280["Cap Start"] - 281["Cap End"] - %% face_code_ref=Missing NodePath - 282["SweepEdge Opposite"] - 283["SweepEdge Adjacent"] - 294["Sweep Extrusion
[3595, 3628, 5]"] - 295[Wall] - %% face_code_ref=Missing NodePath - 296[Wall] - %% face_code_ref=Missing NodePath - 297[Wall] + 283["Cap Start"] + 284["Cap End"] %% face_code_ref=Missing NodePath + 285["SweepEdge Opposite"] + 286["SweepEdge Adjacent"] + 297["Sweep Extrusion
[3595, 3628, 5]"] 298[Wall] %% face_code_ref=Missing NodePath 299[Wall] @@ -420,31 +417,31 @@ flowchart LR %% face_code_ref=Missing NodePath 301[Wall] %% face_code_ref=Missing NodePath - 302["Cap Start"] + 302[Wall] %% face_code_ref=Missing NodePath - 303["Cap End"] + 303[Wall] %% face_code_ref=Missing NodePath - 304["SweepEdge Opposite"] - 305["SweepEdge Adjacent"] - 306["SweepEdge Opposite"] - 307["SweepEdge Adjacent"] - 308["SweepEdge Opposite"] - 309["SweepEdge Adjacent"] - 310["SweepEdge Opposite"] - 311["SweepEdge Adjacent"] - 312["SweepEdge Opposite"] - 313["SweepEdge Adjacent"] - 314["SweepEdge Opposite"] - 315["SweepEdge Adjacent"] - 316["SweepEdge Opposite"] - 317["SweepEdge Adjacent"] - 328["Sweep Extrusion
[4495, 4528, 5]"] - 329[Wall] + 304[Wall] %% face_code_ref=Missing NodePath - 330[Wall] + 305["Cap Start"] %% face_code_ref=Missing NodePath - 331[Wall] + 306["Cap End"] %% face_code_ref=Missing NodePath + 307["SweepEdge Opposite"] + 308["SweepEdge Adjacent"] + 309["SweepEdge Opposite"] + 310["SweepEdge Adjacent"] + 311["SweepEdge Opposite"] + 312["SweepEdge Adjacent"] + 313["SweepEdge Opposite"] + 314["SweepEdge Adjacent"] + 315["SweepEdge Opposite"] + 316["SweepEdge Adjacent"] + 317["SweepEdge Opposite"] + 318["SweepEdge Adjacent"] + 319["SweepEdge Opposite"] + 320["SweepEdge Adjacent"] + 331["Sweep Extrusion
[4495, 4528, 5]"] 332[Wall] %% face_code_ref=Missing NodePath 333[Wall] @@ -453,43 +450,49 @@ flowchart LR %% face_code_ref=Missing NodePath 335[Wall] %% face_code_ref=Missing NodePath - 336["Cap Start"] + 336[Wall] %% face_code_ref=Missing NodePath - 337["Cap End"] + 337[Wall] %% face_code_ref=Missing NodePath - 338["SweepEdge Opposite"] - 339["SweepEdge Adjacent"] - 340["SweepEdge Opposite"] - 341["SweepEdge Adjacent"] - 342["SweepEdge Opposite"] - 343["SweepEdge Adjacent"] - 344["SweepEdge Opposite"] - 345["SweepEdge Adjacent"] - 346["SweepEdge Opposite"] - 347["SweepEdge Adjacent"] - 348["SweepEdge Opposite"] - 349["SweepEdge Adjacent"] - 350["SweepEdge Opposite"] - 351["SweepEdge Adjacent"] - 352["StartSketchOnFace
[1126, 1163, 1]"] - 353["StartSketchOnFace
[1386, 1423, 1]"] - 354["StartSketchOnFace
[1560, 1597, 1]"] - 355["StartSketchOnFace
[1951, 1988, 1]"] - 356["StartSketchOnFace
[840, 877, 3]"] - 357["StartSketchOnFace
[1202, 1239, 3]"] - 358["StartSketchOnFace
[1627, 1664, 3]"] - 359["StartSketchOnFace
[777, 816, 4]"] - 360["StartSketchOnFace
[1015, 1054, 4]"] - 361["StartSketchOnFace
[1411, 1448, 4]"] - 362["StartSketchOnFace
[1698, 1735, 4]"] - 363["StartSketchOnFace
[2204, 2241, 4]"] - 364["StartSketchOnFace
[887, 924, 5]"] - 365["StartSketchOnFace
[1284, 1321, 5]"] - 366["StartSketchOnFace
[1853, 1892, 5]"] - 367["StartSketchOnFace
[2201, 2238, 5]"] - 368["StartSketchOnFace
[2598, 2637, 5]"] - 369["StartSketchOnFace
[2771, 2810, 5]"] - 370["StartSketchOnFace
[3669, 3708, 5]"] + 338[Wall] + %% face_code_ref=Missing NodePath + 339["Cap Start"] + %% face_code_ref=Missing NodePath + 340["Cap End"] + %% face_code_ref=Missing NodePath + 341["SweepEdge Opposite"] + 342["SweepEdge Adjacent"] + 343["SweepEdge Opposite"] + 344["SweepEdge Adjacent"] + 345["SweepEdge Opposite"] + 346["SweepEdge Adjacent"] + 347["SweepEdge Opposite"] + 348["SweepEdge Adjacent"] + 349["SweepEdge Opposite"] + 350["SweepEdge Adjacent"] + 351["SweepEdge Opposite"] + 352["SweepEdge Adjacent"] + 353["SweepEdge Opposite"] + 354["SweepEdge Adjacent"] + 355["StartSketchOnFace
[1126, 1163, 1]"] + 356["StartSketchOnFace
[1386, 1423, 1]"] + 357["StartSketchOnFace
[1560, 1597, 1]"] + 358["StartSketchOnFace
[1951, 1988, 1]"] + 359["StartSketchOnFace
[840, 877, 3]"] + 360["StartSketchOnFace
[1202, 1239, 3]"] + 361["StartSketchOnFace
[1627, 1664, 3]"] + 362["StartSketchOnFace
[777, 816, 4]"] + 363["StartSketchOnFace
[1015, 1054, 4]"] + 364["StartSketchOnFace
[1411, 1448, 4]"] + 365["StartSketchOnFace
[1698, 1735, 4]"] + 366["StartSketchOnFace
[2204, 2241, 4]"] + 367["StartSketchOnFace
[887, 924, 5]"] + 368["StartSketchOnFace
[1284, 1321, 5]"] + 369["StartSketchOnFace
[1853, 1892, 5]"] + 370["StartSketchOnFace
[2201, 2238, 5]"] + 371["StartSketchOnFace
[2598, 2637, 5]"] + 372["StartSketchOnFace
[2771, 2810, 5]"] + 373["StartSketchOnFace
[3669, 3708, 5]"] 1 --- 2 2 --- 3 2 --- 4 @@ -552,9 +555,9 @@ flowchart LR 46 <--x 15 15 --- 55 56 <--x 15 - 15 <--x 352 - 15 <--x 354 15 <--x 355 + 15 <--x 357 + 15 <--x 358 17 <--x 24 19 <--x 25 21 <--x 26 @@ -574,7 +577,7 @@ flowchart LR 34 <--x 33 33 --- 37 38 <--x 33 - 33 <--x 353 + 33 <--x 356 34 <--x 36 37 --- 38 37 --- 39 @@ -684,7 +687,7 @@ flowchart LR 97 <--x 90 90 --- 99 100 <--x 90 - 90 <--x 356 + 90 <--x 359 99 --- 100 99 --- 101 99 ---- 102 @@ -702,8 +705,8 @@ flowchart LR 109 <--x 104 104 --- 119 120 <--x 104 - 104 <--x 357 - 104 <--x 358 + 104 <--x 360 + 104 <--x 361 105 <--x 107 108 --- 109 108 --- 110 @@ -806,11 +809,11 @@ flowchart LR 162 <--x 151 151 --- 170 171 <--x 151 - 151 <--x 359 - 151 <--x 360 - 152 --- 202 - 203 <--x 152 - 152 <--x 363 + 151 <--x 362 + 151 <--x 363 + 152 --- 205 + 206 <--x 152 + 152 <--x 366 161 --- 162 161 --- 163 161 ---- 164 @@ -826,7 +829,7 @@ flowchart LR 167 <--x 166 166 --- 179 180 <--x 166 - 166 <--x 361 + 166 <--x 364 167 <--x 169 170 --- 171 170 --- 172 @@ -843,7 +846,7 @@ flowchart LR 176 <--x 175 175 --- 194 195 <--x 175 - 175 <--x 362 + 175 <--x 365 176 <--x 178 179 --- 180 179 --- 181 @@ -871,337 +874,337 @@ flowchart LR 198 --- 200 198 --- 201 200 <--x 199 - 202 --- 203 - 202 --- 204 - 202 ---- 205 - 203 --- 206 - 203 --- 208 - 203 --- 209 205 --- 206 205 --- 207 - 205 --- 208 - 205 --- 209 - 206 --- 208 + 205 ---- 208 206 --- 209 - 208 <--x 207 - 210 --- 211 - 211 --- 212 - 211 --- 213 - 211 --- 214 - 211 --- 215 - 211 --- 216 - 211 --- 217 - 211 ---- 218 - 212 --- 219 - 212 x--> 223 - 212 --- 225 - 212 --- 226 - 213 --- 220 - 213 x--> 223 - 213 --- 227 - 213 --- 228 - 214 --- 221 - 214 x--> 223 - 214 --- 229 - 214 --- 230 + 206 --- 211 + 206 --- 212 + 208 --- 209 + 208 --- 210 + 208 --- 211 + 208 --- 212 + 209 --- 211 + 209 --- 212 + 211 <--x 210 + 213 --- 214 + 214 --- 215 + 214 --- 216 + 214 --- 217 + 214 --- 218 + 214 --- 219 + 214 --- 220 + 214 ---- 221 215 --- 222 - 215 x--> 223 - 215 --- 231 - 215 --- 232 - 218 --- 219 - 218 --- 220 - 218 --- 221 - 218 --- 222 - 218 --- 223 - 218 --- 224 + 215 x--> 226 + 215 --- 228 + 215 --- 229 + 216 --- 223 + 216 x--> 226 + 216 --- 230 + 216 --- 231 + 217 --- 224 + 217 x--> 226 + 217 --- 232 + 217 --- 233 218 --- 225 - 218 --- 226 - 218 --- 227 - 218 --- 228 - 218 --- 229 - 218 --- 230 - 218 --- 231 - 218 --- 232 - 219 --- 225 - 219 --- 226 - 232 <--x 219 - 226 <--x 220 - 220 --- 227 - 220 --- 228 - 228 <--x 221 + 218 x--> 226 + 218 --- 234 + 218 --- 235 + 221 --- 222 + 221 --- 223 + 221 --- 224 + 221 --- 225 + 221 --- 226 + 221 --- 227 + 221 --- 228 221 --- 229 221 --- 230 - 230 <--x 222 - 222 --- 231 - 222 --- 232 - 223 --- 257 - 223 <--x 366 - 225 <--x 224 - 227 <--x 224 - 229 <--x 224 + 221 --- 231 + 221 --- 232 + 221 --- 233 + 221 --- 234 + 221 --- 235 + 222 --- 228 + 222 --- 229 + 235 <--x 222 + 229 <--x 223 + 223 --- 230 + 223 --- 231 231 <--x 224 + 224 --- 232 224 --- 233 - 234 <--x 224 - 224 --- 266 - 224 <--x 364 - 224 <--x 367 - 233 --- 234 - 233 --- 235 - 233 ---- 236 - 234 --- 237 - 234 --- 239 - 234 --- 240 + 233 <--x 225 + 225 --- 234 + 225 --- 235 + 226 --- 260 + 226 <--x 369 + 228 <--x 227 + 230 <--x 227 + 232 <--x 227 + 234 <--x 227 + 227 --- 236 + 237 <--x 227 + 227 --- 269 + 227 <--x 367 + 227 <--x 370 236 --- 237 236 --- 238 - 236 --- 239 - 236 --- 240 - 237 --- 239 + 236 ---- 239 237 --- 240 - 239 <--x 238 - 238 --- 242 - 243 <--x 238 - 238 <--x 365 - 239 <--x 241 - 242 --- 243 - 242 --- 244 - 242 ---- 245 - 243 --- 246 - 243 --- 248 - 243 --- 249 + 237 --- 242 + 237 --- 243 + 239 --- 240 + 239 --- 241 + 239 --- 242 + 239 --- 243 + 240 --- 242 + 240 --- 243 + 242 <--x 241 + 241 --- 245 + 246 <--x 241 + 241 <--x 368 + 242 <--x 244 245 --- 246 245 --- 247 - 245 --- 248 - 245 --- 249 - 246 --- 248 + 245 ---- 248 246 --- 249 - 248 <--x 247 - 257 --- 258 - 257 --- 259 - 257 ---- 260 - 258 --- 261 - 258 x--> 263 - 258 --- 264 - 258 --- 265 + 246 --- 251 + 246 --- 252 + 248 --- 249 + 248 --- 250 + 248 --- 251 + 248 --- 252 + 249 --- 251 + 249 --- 252 + 251 <--x 250 260 --- 261 260 --- 262 - 260 --- 263 - 260 --- 264 - 260 --- 265 + 260 ---- 263 261 --- 264 - 261 --- 265 - 264 <--x 262 - 266 --- 267 - 266 --- 268 - 266 ---- 269 - 267 --- 270 - 267 x--> 272 - 267 --- 273 - 267 --- 274 + 261 x--> 266 + 261 --- 267 + 261 --- 268 + 263 --- 264 + 263 --- 265 + 263 --- 266 + 263 --- 267 + 263 --- 268 + 264 --- 267 + 264 --- 268 + 267 <--x 265 269 --- 270 269 --- 271 - 269 --- 272 - 269 --- 273 - 269 --- 274 + 269 ---- 272 270 --- 273 - 270 --- 274 - 273 <--x 271 - 271 --- 275 - 271 <--x 368 - 275 --- 276 - 275 --- 277 - 275 ---- 278 - 276 --- 279 - 276 x--> 281 - 276 --- 282 - 276 --- 283 + 270 x--> 275 + 270 --- 276 + 270 --- 277 + 272 --- 273 + 272 --- 274 + 272 --- 275 + 272 --- 276 + 272 --- 277 + 273 --- 276 + 273 --- 277 + 276 <--x 274 + 274 --- 278 + 274 <--x 371 278 --- 279 278 --- 280 - 278 --- 281 - 278 --- 282 - 278 --- 283 + 278 ---- 281 279 --- 282 - 279 --- 283 - 282 <--x 280 - 280 --- 284 - 280 --- 318 - 280 <--x 369 - 280 <--x 370 - 284 --- 285 - 284 --- 286 - 284 --- 287 - 284 --- 288 - 284 --- 289 - 284 --- 290 - 284 --- 291 - 284 --- 292 - 284 --- 293 - 284 ---- 294 - 285 --- 295 - 285 x--> 303 - 285 --- 304 - 285 --- 305 - 286 --- 296 - 286 x--> 303 - 286 --- 306 - 286 --- 307 - 287 --- 297 - 287 x--> 303 - 287 --- 308 - 287 --- 309 + 279 x--> 284 + 279 --- 285 + 279 --- 286 + 281 --- 282 + 281 --- 283 + 281 --- 284 + 281 --- 285 + 281 --- 286 + 282 --- 285 + 282 --- 286 + 285 <--x 283 + 283 --- 287 + 283 --- 321 + 283 <--x 372 + 283 <--x 373 + 287 --- 288 + 287 --- 289 + 287 --- 290 + 287 --- 291 + 287 --- 292 + 287 --- 293 + 287 --- 294 + 287 --- 295 + 287 --- 296 + 287 ---- 297 288 --- 298 - 288 x--> 303 - 288 --- 310 - 288 --- 311 + 288 x--> 306 + 288 --- 307 + 288 --- 308 289 --- 299 - 289 x--> 303 - 289 --- 312 - 289 --- 313 + 289 x--> 306 + 289 --- 309 + 289 --- 310 290 --- 300 - 290 x--> 303 - 290 --- 314 - 290 --- 315 + 290 x--> 306 + 290 --- 311 + 290 --- 312 291 --- 301 - 291 x--> 303 - 291 --- 316 - 291 --- 317 - 294 --- 295 - 294 --- 296 - 294 --- 297 - 294 --- 298 - 294 --- 299 - 294 --- 300 - 294 --- 301 - 294 --- 302 - 294 --- 303 + 291 x--> 306 + 291 --- 313 + 291 --- 314 + 292 --- 302 + 292 x--> 306 + 292 --- 315 + 292 --- 316 + 293 --- 303 + 293 x--> 306 + 293 --- 317 + 293 --- 318 294 --- 304 - 294 --- 305 - 294 --- 306 - 294 --- 307 - 294 --- 308 - 294 --- 309 - 294 --- 310 - 294 --- 311 - 294 --- 312 - 294 --- 313 - 294 --- 314 - 294 --- 315 - 294 --- 316 - 294 --- 317 - 295 --- 304 - 295 --- 305 - 317 <--x 295 - 305 <--x 296 - 296 --- 306 - 296 --- 307 - 307 <--x 297 + 294 x--> 306 + 294 --- 319 + 294 --- 320 + 297 --- 298 + 297 --- 299 + 297 --- 300 + 297 --- 301 + 297 --- 302 + 297 --- 303 + 297 --- 304 + 297 --- 305 + 297 --- 306 + 297 --- 307 297 --- 308 297 --- 309 - 309 <--x 298 - 298 --- 310 - 298 --- 311 - 311 <--x 299 - 299 --- 312 - 299 --- 313 - 313 <--x 300 - 300 --- 314 - 300 --- 315 - 315 <--x 301 - 301 --- 316 - 301 --- 317 - 304 <--x 302 - 306 <--x 302 - 308 <--x 302 - 310 <--x 302 - 312 <--x 302 + 297 --- 310 + 297 --- 311 + 297 --- 312 + 297 --- 313 + 297 --- 314 + 297 --- 315 + 297 --- 316 + 297 --- 317 + 297 --- 318 + 297 --- 319 + 297 --- 320 + 298 --- 307 + 298 --- 308 + 320 <--x 298 + 308 <--x 299 + 299 --- 309 + 299 --- 310 + 310 <--x 300 + 300 --- 311 + 300 --- 312 + 312 <--x 301 + 301 --- 313 + 301 --- 314 314 <--x 302 - 316 <--x 302 - 318 --- 319 - 318 --- 320 - 318 --- 321 - 318 --- 322 - 318 --- 323 - 318 --- 324 - 318 --- 325 - 318 --- 326 - 318 --- 327 - 318 ---- 328 - 319 --- 335 - 319 x--> 337 - 319 --- 350 - 319 --- 351 - 320 --- 334 - 320 x--> 337 - 320 --- 348 - 320 --- 349 - 321 --- 333 - 321 x--> 337 - 321 --- 346 - 321 --- 347 - 322 --- 332 - 322 x--> 337 - 322 --- 344 - 322 --- 345 - 323 --- 331 - 323 x--> 337 - 323 --- 342 - 323 --- 343 - 324 --- 330 - 324 x--> 337 - 324 --- 340 - 324 --- 341 - 325 --- 329 - 325 x--> 337 - 325 --- 338 - 325 --- 339 - 328 --- 329 - 328 --- 330 - 328 --- 331 + 302 --- 315 + 302 --- 316 + 316 <--x 303 + 303 --- 317 + 303 --- 318 + 318 <--x 304 + 304 --- 319 + 304 --- 320 + 307 <--x 305 + 309 <--x 305 + 311 <--x 305 + 313 <--x 305 + 315 <--x 305 + 317 <--x 305 + 319 <--x 305 + 321 --- 322 + 321 --- 323 + 321 --- 324 + 321 --- 325 + 321 --- 326 + 321 --- 327 + 321 --- 328 + 321 --- 329 + 321 --- 330 + 321 ---- 331 + 322 --- 338 + 322 x--> 340 + 322 --- 353 + 322 --- 354 + 323 --- 337 + 323 x--> 340 + 323 --- 351 + 323 --- 352 + 324 --- 336 + 324 x--> 340 + 324 --- 349 + 324 --- 350 + 325 --- 335 + 325 x--> 340 + 325 --- 347 + 325 --- 348 + 326 --- 334 + 326 x--> 340 + 326 --- 345 + 326 --- 346 + 327 --- 333 + 327 x--> 340 + 327 --- 343 + 327 --- 344 328 --- 332 - 328 --- 333 - 328 --- 334 - 328 --- 335 - 328 --- 336 - 328 --- 337 - 328 --- 338 - 328 --- 339 - 328 --- 340 + 328 x--> 340 328 --- 341 328 --- 342 - 328 --- 343 - 328 --- 344 - 328 --- 345 - 328 --- 346 - 328 --- 347 - 328 --- 348 - 328 --- 349 - 328 --- 350 - 328 --- 351 - 329 --- 338 - 329 --- 339 - 341 <--x 329 - 330 --- 340 - 330 --- 341 - 343 <--x 330 + 331 --- 332 + 331 --- 333 + 331 --- 334 + 331 --- 335 + 331 --- 336 + 331 --- 337 + 331 --- 338 + 331 --- 339 + 331 --- 340 + 331 --- 341 331 --- 342 331 --- 343 - 345 <--x 331 - 332 --- 344 - 332 --- 345 - 347 <--x 332 - 333 --- 346 - 333 --- 347 - 349 <--x 333 - 334 --- 348 - 334 --- 349 - 351 <--x 334 - 339 <--x 335 - 335 --- 350 - 335 --- 351 - 338 <--x 336 - 340 <--x 336 - 342 <--x 336 - 344 <--x 336 - 346 <--x 336 - 348 <--x 336 - 350 <--x 336 + 331 --- 344 + 331 --- 345 + 331 --- 346 + 331 --- 347 + 331 --- 348 + 331 --- 349 + 331 --- 350 + 331 --- 351 + 331 --- 352 + 331 --- 353 + 331 --- 354 + 332 --- 341 + 332 --- 342 + 344 <--x 332 + 333 --- 343 + 333 --- 344 + 346 <--x 333 + 334 --- 345 + 334 --- 346 + 348 <--x 334 + 335 --- 347 + 335 --- 348 + 350 <--x 335 + 336 --- 349 + 336 --- 350 + 352 <--x 336 + 337 --- 351 + 337 --- 352 + 354 <--x 337 + 342 <--x 338 + 338 --- 353 + 338 --- 354 + 341 <--x 339 + 343 <--x 339 + 345 <--x 339 + 347 <--x 339 + 349 <--x 339 + 351 <--x 339 + 353 <--x 339 ``` diff --git a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/ops.snap b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/ops.snap index adec9fa53..986372dec 100644 --- a/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/ops.snap +++ b/rust/kcl-lib/tests/kcl_samples/multi-axis-robot/ops.snap @@ -1253,10 +1253,33 @@ description: Operations executed multi-axis-robot.kcl "name": "extrude", "unlabeledArg": { "value": { - "type": "Sketch", - "value": { - "artifactId": "[uuid]" - } + "type": "Array", + "value": [ + { + "type": "Sketch", + "value": { + "artifactId": "[uuid]" + } + }, + { + "type": "Sketch", + "value": { + "artifactId": "[uuid]" + } + }, + { + "type": "Sketch", + "value": { + "artifactId": "[uuid]" + } + }, + { + "type": "Sketch", + "value": { + "artifactId": "[uuid]" + } + } + ] }, "sourceRange": [] }, From cb3b45747c7e4c47e393e09a4d00a3ba0ed2a6ae Mon Sep 17 00:00:00 2001 From: Jess Frazelle Date: Fri, 27 Jun 2025 12:44:05 -0700 Subject: [PATCH 03/19] Change AI to ML because cringe (#7636) Change AI to ML --- src/routes/SignIn.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/SignIn.tsx b/src/routes/SignIn.tsx index 590382d51..595c16609 100644 --- a/src/routes/SignIn.tsx +++ b/src/routes/SignIn.tsx @@ -280,7 +280,7 @@ const SignIn = () => { }} className="!bg-primary !text-chalkboard-10 !border-transarent" > - AI-unlocked CAD + ML-unlocked CAD From 30000a1eac99c0ccf08f7929d3894c1b68dac402 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Sat, 28 Jun 2025 09:23:47 -0400 Subject: [PATCH 04/19] Fix the vertical alignment on the temporary workspace label (#7638) --- src/Toolbar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Toolbar.tsx b/src/Toolbar.tsx index 6be7284a9..657081eb7 100644 --- a/src/Toolbar.tsx +++ b/src/Toolbar.tsx @@ -394,7 +394,7 @@ export function Toolbar({

{isInTemporaryWorkspace && (
-
+
Temporary workspace
) diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx index 234540de6..de9555ae5 100644 --- a/src/routes/Home.tsx +++ b/src/routes/Home.tsx @@ -66,6 +66,7 @@ import { defaultLocalStatusBarItems, defaultGlobalStatusBarItems, } from '@src/components/StatusBar/defaultStatusBarItems' +import { useSelector } from '@xstate/react' type ReadWriteProjectState = { value: boolean @@ -81,6 +82,8 @@ const Home = () => { const [nativeFileMenuCreated, setNativeFileMenuCreated] = useState(false) const apiToken = useToken() const networkMachineStatus = useNetworkMachineStatus() + const billingContext = useSelector(billingActor, ({ context }) => context) + const hasUnlimitedCredits = billingContext.credits === Infinity // Only create the native file menus on desktop useEffect(() => { @@ -354,11 +357,13 @@ const Home = () => {
    -
  • -
    - -
    -
  • + {!hasUnlimitedCredits && ( +
  • +
    + +
    +
  • + )}
  • Date: Mon, 30 Jun 2025 00:03:36 +1200 Subject: [PATCH 07/19] Use proper envs for Rust functions (#7623) --- rust/kcl-lib/src/execution/fn_call.rs | 2 +- rust/kcl-lib/src/execution/memory.rs | 38 ++------------------------- rust/kcl-lib/src/execution/mod.rs | 16 +++++++++++ 3 files changed, 19 insertions(+), 37 deletions(-) diff --git a/rust/kcl-lib/src/execution/fn_call.rs b/rust/kcl-lib/src/execution/fn_call.rs index 778140385..581873646 100644 --- a/rust/kcl-lib/src/execution/fn_call.rs +++ b/rust/kcl-lib/src/execution/fn_call.rs @@ -401,7 +401,7 @@ impl FunctionDefinition<'_> { impl FunctionBody<'_> { fn prep_mem(&self, exec_state: &mut ExecState) { match self { - FunctionBody::Rust(_) => exec_state.mut_stack().push_new_env_for_rust_call(), + FunctionBody::Rust(_) => exec_state.mut_stack().push_new_root_env(true), FunctionBody::Kcl(_, memory) => exec_state.mut_stack().push_new_env_for_call(*memory), } } diff --git a/rust/kcl-lib/src/execution/memory.rs b/rust/kcl-lib/src/execution/memory.rs index a420a6922..85ecb1c51 100644 --- a/rust/kcl-lib/src/execution/memory.rs +++ b/rust/kcl-lib/src/execution/memory.rs @@ -541,22 +541,6 @@ impl Stack { self.push_new_env_for_call(snapshot); } - /// Push a new stack frame on to the call stack for callees which should not read or write - /// from memory. - /// - /// This is suitable for calling standard library functions or other functions written in Rust - /// which will use 'Rust memory' rather than KCL's memory and cannot reach into the wider - /// environment. - /// - /// Trying to read or write from this environment will panic with an index out of bounds. - pub fn push_new_env_for_rust_call(&mut self) { - self.call_stack.push(self.current_env); - // Rust functions shouldn't try to set or access anything in their environment, so don't - // waste time and space on a new env. Using usize::MAX means we'll get an overflow if we - // try to access anything rather than a silent error. - self.current_env = EnvironmentRef(usize::MAX, 0); - } - /// Push a new stack frame on to the call stack with no connection to a parent environment. /// /// Suitable for executing a separate module. @@ -683,7 +667,7 @@ impl Stack { env.contains_key(var) } - /// Get a key from the first KCL (i.e., non-Rust) stack frame on the call stack. + /// Get a key from the first stack frame on the call stack. pub fn get_from_call_stack(&self, key: &str, source_range: SourceRange) -> Result<(usize, &KclValue), KclError> { if !self.current_env.skip_env() { return Ok((self.current_env.1, self.get(key, source_range)?)); @@ -695,7 +679,7 @@ impl Stack { } } - unreachable!("It can't be Rust frames all the way down"); + unreachable!("No frames on the stack?"); } /// Iterate over all keys in the current environment which satisfy the provided predicate. @@ -1217,24 +1201,6 @@ mod test { assert_get_from(mem, "c", 5, callee); } - #[test] - fn rust_env() { - let mem = &mut Stack::new_for_tests(); - mem.add("a".to_owned(), val(1), sr()).unwrap(); - mem.add("b".to_owned(), val(3), sr()).unwrap(); - let sn = mem.snapshot(); - - mem.push_new_env_for_rust_call(); - mem.push_new_env_for_call(sn); - assert_get(mem, "b", 3); - mem.add("b".to_owned(), val(4), sr()).unwrap(); - assert_get(mem, "b", 4); - - mem.pop_env(); - mem.pop_env(); - assert_get(mem, "b", 3); - } - #[test] fn deep_call_env() { let mem = &mut Stack::new_for_tests(); diff --git a/rust/kcl-lib/src/execution/mod.rs b/rust/kcl-lib/src/execution/mod.rs index 5c6f4c209..8f3647716 100644 --- a/rust/kcl-lib/src/execution/mod.rs +++ b/rust/kcl-lib/src/execution/mod.rs @@ -1920,6 +1920,22 @@ shape = layer() |> patternTransform(instances = 10, transform = transform) ); } + #[tokio::test(flavor = "multi_thread")] + async fn pass_std_to_std() { + let ast = r#"sketch001 = startSketchOn(XY) +profile001 = circle(sketch001, center = [0, 0], radius = 2) +extrude001 = extrude(profile001, length = 5) +extrudes = patternLinear3d( + extrude001, + instances = 3, + distance = 5, + axis = [1, 1, 0], +) +clone001 = map(extrudes, f = clone) +"#; + parse_execute(ast).await.unwrap(); + } + #[tokio::test(flavor = "multi_thread")] async fn test_zero_param_fn() { let ast = r#"sigmaAllow = 35000 // psi From 62d8d45a58ee9993dfe5e53aa4c9d47860eb97b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 10:07:54 -0400 Subject: [PATCH 08/19] Bump the major group across 1 directory with 4 updates (#7572) * Bump the major group across 1 directory with 4 updates Bumps the major group with 4 updates in the / directory: [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact), [runs-on/action](https://github.com/runs-on/action), [actions/create-github-app-token](https://github.com/actions/create-github-app-token) and [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv). Updates `dawidd6/action-download-artifact` from 7 to 11 - [Release notes](https://github.com/dawidd6/action-download-artifact/releases) - [Commits](https://github.com/dawidd6/action-download-artifact/compare/v7...v11) Updates `runs-on/action` from 1 to 2 - [Release notes](https://github.com/runs-on/action/releases) - [Commits](https://github.com/runs-on/action/compare/v1...v2) Updates `actions/create-github-app-token` from 1 to 2 - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/v1...v2) Updates `astral-sh/setup-uv` from 5 to 6 - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/v5...v6) --- updated-dependencies: - dependency-name: dawidd6/action-download-artifact dependency-version: '11' dependency-type: direct:production update-type: version-update:semver-major dependency-group: major - dependency-name: runs-on/action dependency-version: '2' dependency-type: direct:production update-type: version-update:semver-major dependency-group: major - dependency-name: actions/create-github-app-token dependency-version: '2' dependency-type: direct:production update-type: version-update:semver-major dependency-group: major - dependency-name: astral-sh/setup-uv dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: major ... Signed-off-by: dependabot[bot] * bump --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Ammann --- .github/workflows/build-apps.yml | 2 +- .github/workflows/cargo-test.yml | 12 ++++++------ .github/workflows/e2e-tests.yml | 6 +++--- .github/workflows/generate-website-docs.yml | 2 +- .github/workflows/kcl-python-bindings.yml | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-apps.yml b/.github/workflows/build-apps.yml index 839ec313f..fc0aace03 100644 --- a/.github/workflows/build-apps.yml +++ b/.github/workflows/build-apps.yml @@ -43,7 +43,7 @@ jobs: - name: Download Wasm Cache id: download-wasm if: ${{ github.event_name == 'pull_request' && steps.filter.outputs.rust == 'false' }} - uses: dawidd6/action-download-artifact@v7 + uses: dawidd6/action-download-artifact@v11 continue-on-error: true with: github_token: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/cargo-test.yml b/.github/workflows/cargo-test.yml index 8eb8fb446..d38867655 100644 --- a/.github/workflows/cargo-test.yml +++ b/.github/workflows/cargo-test.yml @@ -25,8 +25,8 @@ jobs: - runner=8cpu-linux-x64 - extras=s3-cache steps: - - uses: runs-on/action@v1 - - uses: actions/create-github-app-token@v1 + - uses: runs-on/action@v2 + - uses: actions/create-github-app-token@v2 id: app-token with: app-id: ${{ secrets.MODELING_APP_GH_APP_ID }} @@ -149,8 +149,8 @@ jobs: partitionIndex: [1, 2, 3, 4, 5, 6] partitionTotal: [6] steps: - - uses: runs-on/action@v1 - - uses: actions/create-github-app-token@v1 + - uses: runs-on/action@v2 + - uses: actions/create-github-app-token@v2 id: app-token with: app-id: ${{ secrets.MODELING_APP_GH_APP_ID }} @@ -207,8 +207,8 @@ jobs: - runner=32cpu-linux-x64 - extras=s3-cache steps: - - uses: runs-on/action@v1 - - uses: actions/create-github-app-token@v1 + - uses: runs-on/action@v2 + - uses: actions/create-github-app-token@v2 id: app-token with: app-id: ${{ secrets.MODELING_APP_GH_APP_ID }} diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 32cee74b9..b173db5db 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -46,7 +46,7 @@ jobs: - name: Download Wasm cache id: download-wasm if: ${{ github.event_name != 'schedule' && steps.filter.outputs.rust == 'false' }} - uses: dawidd6/action-download-artifact@v7 + uses: dawidd6/action-download-artifact@v11 continue-on-error: true with: github_token: ${{secrets.GITHUB_TOKEN}} @@ -110,7 +110,7 @@ jobs: steps: - - uses: actions/create-github-app-token@v1 + - uses: actions/create-github-app-token@v2 id: app-token with: app-id: ${{ secrets.MODELING_APP_GH_APP_ID }} @@ -230,7 +230,7 @@ jobs: steps: - - uses: actions/create-github-app-token@v1 + - uses: actions/create-github-app-token@v2 id: app-token with: app-id: ${{ secrets.MODELING_APP_GH_APP_ID }} diff --git a/.github/workflows/generate-website-docs.yml b/.github/workflows/generate-website-docs.yml index d5cd67609..c3f209101 100644 --- a/.github/workflows/generate-website-docs.yml +++ b/.github/workflows/generate-website-docs.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/create-github-app-token@v1 + - uses: actions/create-github-app-token@v2 id: app-token with: # required diff --git a/.github/workflows/kcl-python-bindings.yml b/.github/workflows/kcl-python-bindings.yml index 2a31bb257..2cd0e9011 100644 --- a/.github/workflows/kcl-python-bindings.yml +++ b/.github/workflows/kcl-python-bindings.yml @@ -113,7 +113,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v6 - uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: taiki-e/install-action@just - name: Run tests @@ -130,7 +130,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install the latest version of uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v6 - name: Install codespell run: | uv venv .venv @@ -161,7 +161,7 @@ jobs: with: path: rust/kcl-python-bindings - name: Install the latest version of uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v6 - name: do uv things run: | cd rust/kcl-python-bindings From fb8b975b5eaa2650b55da149e66a12c80252b327 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:40:33 +0000 Subject: [PATCH 09/19] Bump esbuild from 0.25.2 to 0.25.3 in the security group across 1 directory (#6681) Bump esbuild in the security group across 1 directory Bumps the security group with 1 update in the / directory: [esbuild](https://github.com/evanw/esbuild). Updates `esbuild` from 0.25.2 to 0.25.3 - [Release notes](https://github.com/evanw/esbuild/releases) - [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md) - [Commits](https://github.com/evanw/esbuild/compare/v0.25.2...v0.25.3) --- updated-dependencies: - dependency-name: esbuild dependency-version: 0.25.3 dependency-type: direct:development dependency-group: security ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 1118 ++++++++++++------------- rust/kcl-language-server/package.json | 2 +- 2 files changed, 535 insertions(+), 585 deletions(-) diff --git a/package-lock.json b/package-lock.json index f6d219b48..798907d5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3652,303 +3652,285 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", + "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz", + "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz", + "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz", + "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz", + "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz", + "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz", + "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz", + "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz", + "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz", + "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz", + "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz", + "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz", + "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", "cpu": [ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz", + "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz", + "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz", + "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz", + "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz", + "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -3958,31 +3940,29 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz", + "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz", + "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -3992,88 +3972,83 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz", + "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz", + "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz", + "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz", + "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz", + "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -13244,42 +13219,43 @@ "optional": true }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz", + "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.25.3", + "@esbuild/android-arm": "0.25.3", + "@esbuild/android-arm64": "0.25.3", + "@esbuild/android-x64": "0.25.3", + "@esbuild/darwin-arm64": "0.25.3", + "@esbuild/darwin-x64": "0.25.3", + "@esbuild/freebsd-arm64": "0.25.3", + "@esbuild/freebsd-x64": "0.25.3", + "@esbuild/linux-arm": "0.25.3", + "@esbuild/linux-arm64": "0.25.3", + "@esbuild/linux-ia32": "0.25.3", + "@esbuild/linux-loong64": "0.25.3", + "@esbuild/linux-mips64el": "0.25.3", + "@esbuild/linux-ppc64": "0.25.3", + "@esbuild/linux-riscv64": "0.25.3", + "@esbuild/linux-s390x": "0.25.3", + "@esbuild/linux-x64": "0.25.3", + "@esbuild/netbsd-arm64": "0.25.3", + "@esbuild/netbsd-x64": "0.25.3", + "@esbuild/openbsd-arm64": "0.25.3", + "@esbuild/openbsd-x64": "0.25.3", + "@esbuild/sunos-x64": "0.25.3", + "@esbuild/win32-arm64": "0.25.3", + "@esbuild/win32-ia32": "0.25.3", + "@esbuild/win32-x64": "0.25.3" } }, "node_modules/escalade": { @@ -25297,6 +25273,412 @@ } } }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, "node_modules/vite/node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -26279,7 +26661,7 @@ "@vscode/test-electron": "^2.4.1", "@vscode/vsce": "^3.3.2", "cross-env": "^7.0.3", - "esbuild": "^0.25.2", + "esbuild": "^0.25.3", "glob": "^11.0.1", "mocha": "^11.1.0", "typescript": "^5.8.3" @@ -26288,397 +26670,6 @@ "vscode": "^1.97.0" } }, - "rust/kcl-language-server/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/android-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/android-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/android-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/darwin-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/linux-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/linux-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/linux-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/linux-loong64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/linux-s390x": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/linux-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/sunos-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/win32-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/win32-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "rust/kcl-language-server/node_modules/@esbuild/win32-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, "rust/kcl-language-server/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -26689,47 +26680,6 @@ "balanced-match": "^1.0.0" } }, - "rust/kcl-language-server/node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" - } - }, "rust/kcl-language-server/node_modules/glob": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", diff --git a/rust/kcl-language-server/package.json b/rust/kcl-language-server/package.json index 9bd17fa6f..a67c5769e 100644 --- a/rust/kcl-language-server/package.json +++ b/rust/kcl-language-server/package.json @@ -123,7 +123,7 @@ "@vscode/test-electron": "^2.4.1", "@vscode/vsce": "^3.3.2", "cross-env": "^7.0.3", - "esbuild": "^0.25.2", + "esbuild": "^0.25.3", "glob": "^11.0.1", "mocha": "^11.1.0", "typescript": "^5.8.3" From 27af2d08a3708b000d8d30ae0054d67995702232 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 12:09:43 -0400 Subject: [PATCH 10/19] Bump the patch group in /rust with 3 updates (#7575) * Bump the patch group in /rust with 3 updates Bumps the patch group in /rust with 3 updates: [toml_edit](https://github.com/toml-rs/toml), [syn](https://github.com/dtolnay/syn) and [toml](https://github.com/toml-rs/toml). Updates `toml_edit` from 0.22.26 to 0.22.27 - [Commits](https://github.com/toml-rs/toml/compare/v0.22.26...v0.22.27) Updates `syn` from 2.0.103 to 2.0.104 - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.103...2.0.104) Updates `toml` from 0.8.22 to 0.8.23 - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.22...toml-v0.8.23) --- updated-dependencies: - dependency-name: toml_edit dependency-version: 0.22.27 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch - dependency-name: syn dependency-version: 2.0.104 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch - dependency-name: toml dependency-version: 0.8.23 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch ... Signed-off-by: dependabot[bot] * Trigger CI --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jonathan Tran --- rust/Cargo.lock | 120 +++++++++++------------ rust/kcl-bumper/Cargo.toml | 2 +- rust/kcl-derive-docs/Cargo.toml | 2 +- rust/kcl-directory-test-macro/Cargo.toml | 2 +- rust/kcl-lib/Cargo.toml | 2 +- rust/kcl-wasm-lib/Cargo.toml | 2 +- 6 files changed, 65 insertions(+), 65 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 918f321c0..57dd1c8c9 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -178,7 +178,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -189,7 +189,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -211,7 +211,7 @@ checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -514,7 +514,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -740,7 +740,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -751,7 +751,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -810,7 +810,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -831,7 +831,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -841,7 +841,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -906,7 +906,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -944,7 +944,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1119,7 +1119,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1223,7 +1223,7 @@ dependencies = [ "inflections", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1599,7 +1599,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1829,7 +1829,7 @@ version = "0.1.83" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -1839,7 +1839,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2104,7 +2104,7 @@ dependencies = [ "kittycad-modeling-cmds-macros-impl", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2115,7 +2115,7 @@ checksum = "fdb4ee23cc996aa2dca7584d410e8826e08161e1ac4335bb646d5ede33f37cb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2311,7 +2311,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2640,7 +2640,7 @@ dependencies = [ "regex", "regex-syntax 0.8.5", "structmeta", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2654,7 +2654,7 @@ dependencies = [ "regex", "regex-syntax 0.8.5", "structmeta", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2710,7 +2710,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2754,7 +2754,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2809,7 +2809,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2921,7 +2921,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2981,7 +2981,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -2994,7 +2994,7 @@ dependencies = [ "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3492,7 +3492,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3556,7 +3556,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3567,7 +3567,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3591,14 +3591,14 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -3815,7 +3815,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3826,7 +3826,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3848,7 +3848,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3891,9 +3891,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.103" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -3917,7 +3917,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -3941,7 +3941,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -4050,7 +4050,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -4061,7 +4061,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -4173,7 +4173,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -4217,9 +4217,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -4238,9 +4238,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.9.0", "serde", @@ -4341,7 +4341,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -4369,7 +4369,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -4449,7 +4449,7 @@ checksum = "e9d4ed7b4c18cc150a6a0a1e9ea1ecfa688791220781af6e119f9599a8502a0a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "termcolor", ] @@ -4635,7 +4635,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -4706,7 +4706,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -4742,7 +4742,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4777,7 +4777,7 @@ checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -5067,7 +5067,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "synstructure", ] @@ -5112,7 +5112,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -5123,7 +5123,7 @@ checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -5143,7 +5143,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", "synstructure", ] @@ -5164,7 +5164,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] @@ -5186,7 +5186,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.104", ] [[package]] diff --git a/rust/kcl-bumper/Cargo.toml b/rust/kcl-bumper/Cargo.toml index 16dee4e08..397c74faa 100644 --- a/rust/kcl-bumper/Cargo.toml +++ b/rust/kcl-bumper/Cargo.toml @@ -19,7 +19,7 @@ anyhow = { workspace = true } clap = { workspace = true, features = ["derive"] } semver = "1.0.25" serde = { workspace = true } -toml_edit = "0.22.26" +toml_edit = "0.22.27" [lints] workspace = true diff --git a/rust/kcl-derive-docs/Cargo.toml b/rust/kcl-derive-docs/Cargo.toml index 9040377df..239862f2a 100644 --- a/rust/kcl-derive-docs/Cargo.toml +++ b/rust/kcl-derive-docs/Cargo.toml @@ -14,7 +14,7 @@ bench = false [dependencies] proc-macro2 = "1" quote = "1" -syn = { version = "2.0.103", features = ["full"] } +syn = { version = "2.0.104", features = ["full"] } [lints] workspace = true diff --git a/rust/kcl-directory-test-macro/Cargo.toml b/rust/kcl-directory-test-macro/Cargo.toml index 113de027a..a3216c8ca 100644 --- a/rust/kcl-directory-test-macro/Cargo.toml +++ b/rust/kcl-directory-test-macro/Cargo.toml @@ -14,7 +14,7 @@ bench = false convert_case = "0.8.0" proc-macro2 = "1" quote = "1" -syn = { version = "2.0.103", features = ["full"] } +syn = { version = "2.0.104", features = ["full"] } [lints] workspace = true diff --git a/rust/kcl-lib/Cargo.toml b/rust/kcl-lib/Cargo.toml index 4f5d24874..501afae99 100644 --- a/rust/kcl-lib/Cargo.toml +++ b/rust/kcl-lib/Cargo.toml @@ -74,7 +74,7 @@ sha2 = "0.10.9" tabled = { version = "0.20.0", optional = true } tempfile = "3.20" thiserror = "2.0.0" -toml = "0.8.22" +toml = "0.8.23" ts-rs = { version = "11.0.1", features = [ "uuid-impl", "url-impl", diff --git a/rust/kcl-wasm-lib/Cargo.toml b/rust/kcl-wasm-lib/Cargo.toml index 5db47e99a..209abefd3 100644 --- a/rust/kcl-wasm-lib/Cargo.toml +++ b/rust/kcl-wasm-lib/Cargo.toml @@ -25,7 +25,7 @@ kittycad = { workspace = true } kittycad-modeling-cmds = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true, features = ["sync", "rt"] } -toml = "0.8.22" +toml = "0.8.23" tower-lsp = { workspace = true, features = ["runtime-agnostic"] } uuid = { workspace = true, features = ["v4", "js", "serde"] } wasm-bindgen = "0.2.99" From 85c721fb49ef5a18fb9e5693ce5f54362eef46c2 Mon Sep 17 00:00:00 2001 From: Jonathan Tran Date: Mon, 30 Jun 2025 15:26:45 -0400 Subject: [PATCH 11/19] Add display of units for calculated KCL values (#7619) * Add display of units in UI modals with calculated KCL values * Fix command bar display to handle units * Add display of units in the command bar * Fix more cases of NaN from units * Fix to support explicit plus for exponent in scientific notation * Fix display in autocomplete * Change to parseFloat to be more resilient * Add e2e test for command bar * Change an existing test to use explicit inline units * Fix case when input string can't be parsed --- e2e/playwright/command-bar-tests.spec.ts | 42 +++++++- e2e/playwright/point-click.spec.ts | 6 +- rust/kcl-lib/src/execution/types.rs | 12 +++ rust/kcl-lib/src/fmt.rs | 95 +++++++++++++++++++ rust/kcl-lib/src/lib.rs | 2 +- rust/kcl-wasm-lib/src/wasm.rs | 31 ++++++ .../CommandBar/CommandBarHeaderFooter.tsx | 8 +- .../CommandBar/CommandBarKclInput.tsx | 26 +++-- src/lang/queryAst.test.ts | 33 ++++++- src/lang/queryAst.ts | 3 + src/lang/wasm.ts | 18 ++++ src/lib/kclHelpers.test.ts | 9 +- src/lib/kclHelpers.ts | 28 +++++- src/lib/useCalculateKclExpression.ts | 2 +- src/lib/utils.test.ts | 43 +++++++++ src/lib/utils.ts | 26 +++++ src/lib/wasm_lib_wrapper.ts | 4 + 17 files changed, 360 insertions(+), 28 deletions(-) diff --git a/e2e/playwright/command-bar-tests.spec.ts b/e2e/playwright/command-bar-tests.spec.ts index 3e4d28391..4cea2adc4 100644 --- a/e2e/playwright/command-bar-tests.spec.ts +++ b/e2e/playwright/command-bar-tests.spec.ts @@ -525,7 +525,9 @@ test.describe('Command bar tests', () => { const projectName = 'test' const beforeKclCode = `a = 5 b = a * a -c = 3 + a` +c = 3 + a +theta = 45deg +` await context.folderSetupFn(async (dir) => { const testProject = join(dir, projectName) await fsp.mkdir(testProject, { recursive: true }) @@ -615,9 +617,45 @@ c = 3 + a` stage: 'commandBarClosed', }) }) + await test.step(`Edit a parameter with explicit units via command bar`, async () => { + await cmdBar.cmdBarOpenBtn.click() + await cmdBar.chooseCommand('edit parameter') + await cmdBar + .selectOption({ + name: 'theta', + }) + .click() + await cmdBar.expectState({ + stage: 'arguments', + commandName: 'Edit parameter', + currentArgKey: 'value', + currentArgValue: '45deg', + headerArguments: { + Name: 'theta', + Value: '', + }, + highlightedHeaderArg: 'value', + }) + await cmdBar.argumentInput + .locator('[contenteditable]') + .fill('45deg + 1deg') + await cmdBar.progressCmdBar() + await cmdBar.expectState({ + stage: 'review', + commandName: 'Edit parameter', + headerArguments: { + Name: 'theta', + Value: '46deg', + }, + }) + await cmdBar.progressCmdBar() + await cmdBar.expectState({ + stage: 'commandBarClosed', + }) + }) await editor.expectEditor.toContain( - `a = 5b = a * amyParameter001 = ${newValue}c = 3 + a` + `a = 5b = a * amyParameter001 = ${newValue}c = 3 + atheta = 45deg + 1deg` ) }) diff --git a/e2e/playwright/point-click.spec.ts b/e2e/playwright/point-click.spec.ts index 780269cd6..31e4ffc0b 100644 --- a/e2e/playwright/point-click.spec.ts +++ b/e2e/playwright/point-click.spec.ts @@ -136,17 +136,17 @@ test.describe('Point-and-click tests', () => { highlightedHeaderArg: 'length', commandName: 'Extrude', }) - await page.keyboard.insertText('width - 0.001') + await page.keyboard.insertText('width - 0.001in') await cmdBar.progressCmdBar() await cmdBar.expectState({ stage: 'review', headerArguments: { - Length: '4.999', + Length: '4.999in', }, commandName: 'Extrude', }) await cmdBar.progressCmdBar() - await editor.expectEditor.toContain('extrude(length = width - 0.001)') + await editor.expectEditor.toContain('extrude(length = width - 0.001in)') }) await test.step(`Edit second extrude via feature tree`, async () => { diff --git a/rust/kcl-lib/src/execution/types.rs b/rust/kcl-lib/src/execution/types.rs index 6de88d39b..5546a6f88 100644 --- a/rust/kcl-lib/src/execution/types.rs +++ b/rust/kcl-lib/src/execution/types.rs @@ -840,6 +840,18 @@ pub enum UnitType { Angle(UnitAngle), } +impl UnitType { + pub(crate) fn to_suffix(self) -> Option { + match self { + UnitType::Count => Some("_".to_owned()), + UnitType::Length(UnitLen::Unknown) => None, + UnitType::Angle(UnitAngle::Unknown) => None, + UnitType::Length(l) => Some(l.to_string()), + UnitType::Angle(a) => Some(a.to_string()), + } + } +} + impl std::fmt::Display for UnitType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/rust/kcl-lib/src/fmt.rs b/rust/kcl-lib/src/fmt.rs index a7a20fa20..2caa721f9 100644 --- a/rust/kcl-lib/src/fmt.rs +++ b/rust/kcl-lib/src/fmt.rs @@ -45,6 +45,31 @@ pub fn format_number_literal(value: f64, suffix: NumericSuffix) -> Result Result { + match ty { + NumericType::Default { .. } => Ok(value.to_string()), + // There isn't a syntactic suffix for these. For unknown, we don't want + // to ever generate the unknown suffix. We currently warn on it, and we + // may remove it in the future. + NumericType::Unknown | NumericType::Any => Err(FormatNumericTypeError::Invalid(ty)), + NumericType::Known(unit_type) => unit_type + .to_suffix() + .map(|suffix| format!("{value}{suffix}")) + .ok_or(FormatNumericTypeError::Invalid(ty)), + } +} + #[cfg(test)] mod tests { use pretty_assertions::assert_eq; @@ -134,4 +159,74 @@ mod tests { Err(FormatNumericSuffixError::Invalid(NumericSuffix::Unknown)) ); } + + #[test] + fn test_format_number_value() { + assert_eq!( + format_number_value( + 1.0, + NumericType::Default { + len: Default::default(), + angle: Default::default() + } + ), + Ok("1".to_owned()) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Unknown))), + Err(FormatNumericTypeError::Invalid(NumericType::Known(UnitType::Length( + UnitLen::Unknown + )))) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Angle(UnitAngle::Unknown))), + Err(FormatNumericTypeError::Invalid(NumericType::Known(UnitType::Angle( + UnitAngle::Unknown + )))) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Count)), + Ok("1_".to_owned()) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Mm))), + Ok("1mm".to_owned()) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Cm))), + Ok("1cm".to_owned()) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::M))), + Ok("1m".to_owned()) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Inches))), + Ok("1in".to_owned()) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Feet))), + Ok("1ft".to_owned()) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Yards))), + Ok("1yd".to_owned()) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Angle(UnitAngle::Degrees))), + Ok("1deg".to_owned()) + ); + assert_eq!( + format_number_value(1.0, NumericType::Known(UnitType::Angle(UnitAngle::Radians))), + Ok("1rad".to_owned()) + ); + assert_eq!( + format_number_value(1.0, NumericType::Unknown), + Err(FormatNumericTypeError::Invalid(NumericType::Unknown)) + ); + assert_eq!( + format_number_value(1.0, NumericType::Any), + Err(FormatNumericTypeError::Invalid(NumericType::Any)) + ); + } } diff --git a/rust/kcl-lib/src/lib.rs b/rust/kcl-lib/src/lib.rs index 7aebd7d20..4b11113b5 100644 --- a/rust/kcl-lib/src/lib.rs +++ b/rust/kcl-lib/src/lib.rs @@ -140,7 +140,7 @@ pub mod std_utils { pub mod pretty { pub use crate::{ - fmt::{format_number_literal, human_display_number}, + fmt::{format_number_literal, format_number_value, human_display_number}, parsing::token::NumericSuffix, }; } diff --git a/rust/kcl-wasm-lib/src/wasm.rs b/rust/kcl-wasm-lib/src/wasm.rs index c44f8c634..ae9095d05 100644 --- a/rust/kcl-wasm-lib/src/wasm.rs +++ b/rust/kcl-wasm-lib/src/wasm.rs @@ -61,6 +61,37 @@ pub fn format_number_literal(value: f64, suffix_json: &str) -> Result Result { + console_error_panic_hook::set_once(); + + // ts-rs can't handle tuple types, so it mashes all of these types together. + if let Ok(ty) = serde_json::from_str::(numeric_type_json) { + if let Ok(formatted) = kcl_lib::pretty::format_number_value(value, ty) { + return Ok(formatted); + } + } + if let Ok(unit_type) = serde_json::from_str::(numeric_type_json) { + let ty = NumericType::Known(unit_type); + if let Ok(formatted) = kcl_lib::pretty::format_number_value(value, ty) { + return Ok(formatted); + } + } + if let Ok(unit_len) = serde_json::from_str::(numeric_type_json) { + let ty = NumericType::Known(UnitType::Length(unit_len)); + if let Ok(formatted) = kcl_lib::pretty::format_number_value(value, ty) { + return Ok(formatted); + } + } + if let Ok(unit_angle) = serde_json::from_str::(numeric_type_json) { + let ty = NumericType::Known(UnitType::Angle(unit_angle)); + if let Ok(formatted) = kcl_lib::pretty::format_number_value(value, ty) { + return Ok(formatted); + } + } + Err(format!("Invalid type: {numeric_type_json}")) +} + #[wasm_bindgen] pub fn human_display_number(value: f64, ty_json: &str) -> Result { console_error_panic_hook::set_once(); diff --git a/src/components/CommandBar/CommandBarHeaderFooter.tsx b/src/components/CommandBar/CommandBarHeaderFooter.tsx index 8934aeaaa..19731edd9 100644 --- a/src/components/CommandBar/CommandBarHeaderFooter.tsx +++ b/src/components/CommandBar/CommandBarHeaderFooter.tsx @@ -12,7 +12,7 @@ import type { } from '@src/lib/commandTypes' import type { Selections } from '@src/lib/selections' import { getSelectionTypeDisplayText } from '@src/lib/selections' -import { roundOff } from '@src/lib/utils' +import { roundOffWithUnits } from '@src/lib/utils' import { commandBarActor, useCommandBarState } from '@src/lib/singletons' function CommandBarHeaderFooter({ @@ -163,10 +163,8 @@ function CommandBarHeaderFooter({ arg.inputType === 'selectionMixed' ? ( getSelectionTypeDisplayText(argValue as Selections) ) : arg.inputType === 'kcl' ? ( - roundOff( - Number( - (argValue as KclCommandValue).valueCalculated - ), + roundOffWithUnits( + (argValue as KclCommandValue).valueCalculated, 4 ) ) : arg.inputType === 'text' && diff --git a/src/components/CommandBar/CommandBarKclInput.tsx b/src/components/CommandBar/CommandBarKclInput.tsx index 257206681..113d4c814 100644 --- a/src/components/CommandBar/CommandBarKclInput.tsx +++ b/src/components/CommandBar/CommandBarKclInput.tsx @@ -21,13 +21,13 @@ import { Spinner } from '@src/components/Spinner' import { createLocalName, createVariableDeclaration } from '@src/lang/create' import { getNodeFromPath } from '@src/lang/queryAst' import type { SourceRange, VariableDeclarator } from '@src/lang/wasm' -import { isPathToNode } from '@src/lang/wasm' +import { formatNumberValue, isPathToNode } from '@src/lang/wasm' import type { CommandArgument, KclCommandValue } from '@src/lib/commandTypes' import { kclManager } from '@src/lib/singletons' import { getSystemTheme } from '@src/lib/theme' import { err } from '@src/lib/trap' import { useCalculateKclExpression } from '@src/lib/useCalculateKclExpression' -import { roundOff } from '@src/lib/utils' +import { roundOff, roundOffWithUnits } from '@src/lib/utils' import { varMentions } from '@src/lib/varCompletionExtension' import { useSettings } from '@src/lib/singletons' import { commandBarActor, useCommandBarState } from '@src/lib/singletons' @@ -128,10 +128,22 @@ function CommandBarKclInput({ sourceRange: sourceRangeForPrevVariables, }) - const varMentionData: Completion[] = prevVariables.map((v) => ({ - label: v.key, - detail: String(roundOff(Number(v.value))), - })) + const varMentionData: Completion[] = prevVariables.map((v) => { + const roundedWithUnits = (() => { + if (typeof v.value !== 'number' || !v.ty) { + return undefined + } + const numWithUnits = formatNumberValue(v.value, v.ty) + if (err(numWithUnits)) { + return undefined + } + return roundOffWithUnits(numWithUnits) + })() + return { + label: v.key, + detail: roundedWithUnits ?? String(roundOff(Number(v.value))), + } + }) const varMentionsExtension = varMentions(varMentionData) const { setContainer, view } = useCodeMirror({ @@ -282,7 +294,7 @@ function CommandBarKclInput({ ) : calcResult === 'NAN' ? ( "Can't calculate" ) : ( - roundOff(Number(calcResult), 4) + roundOffWithUnits(calcResult, 4) )} diff --git a/src/lang/queryAst.test.ts b/src/lang/queryAst.test.ts index e71d39ddc..94d570af7 100644 --- a/src/lang/queryAst.test.ts +++ b/src/lang/queryAst.test.ts @@ -63,11 +63,36 @@ variableBelowShouldNotBeIncluded = 3 execState.variables, topLevelRange(rangeStart, rangeStart) ) + const defaultTy = { + type: 'Default', + angle: { + type: 'Degrees', + }, + len: { + type: 'Mm', + }, + } expect(variables).toEqual([ - { key: 'baseThick', value: 1 }, - { key: 'armAngle', value: 60 }, - { key: 'baseThickHalf', value: 0.5 }, - { key: 'halfArmAngle', value: 30 }, + { + key: 'baseThick', + value: 1, + ty: defaultTy, + }, + { + key: 'armAngle', + value: 60, + ty: defaultTy, + }, + { + key: 'baseThickHalf', + value: 0.5, + ty: defaultTy, + }, + { + key: 'halfArmAngle', + value: 30, + ty: defaultTy, + }, // no arrExpShouldNotBeIncluded, variableBelowShouldNotBeIncluded etc ]) // there are 4 number variables and 2 non-number variables before the sketch var diff --git a/src/lang/queryAst.ts b/src/lang/queryAst.ts index d89d7b1c8..1ea158cec 100644 --- a/src/lang/queryAst.ts +++ b/src/lang/queryAst.ts @@ -55,6 +55,7 @@ import type { OpKclValue, Operation } from '@rust/kcl-lib/bindings/Operation' import { ARG_INDEX_FIELD, LABELED_ARG_FIELD } from '@src/lang/queryAstConstants' import type { KclCommandValue } from '@src/lib/commandTypes' import type { UnaryExpression } from 'typescript' +import type { NumericType } from '@rust/kcl-lib/bindings/NumericType' /** * Retrieves a node from a given path within a Program node structure, optionally stopping at a specified node type. @@ -306,6 +307,7 @@ export function traverse( export interface PrevVariable { key: string value: T + ty: NumericType | undefined } export function findAllPreviousVariablesPath( @@ -353,6 +355,7 @@ export function findAllPreviousVariablesPath( variables.push({ key: varName, value: varValue.value, + ty: varValue.type === 'Number' ? varValue.ty : undefined, }) }) diff --git a/src/lang/wasm.ts b/src/lang/wasm.ts index ebdb544b5..ee2d05f9a 100644 --- a/src/lang/wasm.ts +++ b/src/lang/wasm.ts @@ -45,6 +45,7 @@ import { default_app_settings, default_project_settings, format_number_literal, + format_number_value, get_kcl_version, get_tangential_arc_to_info, human_display_number, @@ -448,6 +449,23 @@ export function formatNumberLiteral( } } +/** + * Format a number from a KclValue such that it could be parsed as KCL. + */ +export function formatNumberValue( + value: number, + numericType: NumericType +): string | Error { + try { + return format_number_value(value, JSON.stringify(numericType)) + } catch (e) { + return new Error( + `Error formatting number value: value=${value}, numericType=${numericType}`, + { cause: e } + ) + } +} + /** * Debug display a number with suffix, for human consumption only. */ diff --git a/src/lib/kclHelpers.test.ts b/src/lib/kclHelpers.test.ts index c3b79a50e..3bcfc58eb 100644 --- a/src/lib/kclHelpers.test.ts +++ b/src/lib/kclHelpers.test.ts @@ -2,13 +2,20 @@ import type { ParseResult } from '@src/lang/wasm' import { getCalculatedKclExpressionValue } from '@src/lib/kclHelpers' describe('KCL expression calculations', () => { - it('calculates a simple expression', async () => { + it('calculates a simple expression without units', async () => { const actual = await getCalculatedKclExpressionValue('1 + 2') const coercedActual = actual as Exclude expect(coercedActual).not.toHaveProperty('errors') expect(coercedActual.valueAsString).toEqual('3') expect(coercedActual?.astNode).toBeDefined() }) + it('calculates a simple expression with units', async () => { + const actual = await getCalculatedKclExpressionValue('1deg + 30deg') + const coercedActual = actual as Exclude + expect(coercedActual).not.toHaveProperty('errors') + expect(coercedActual.valueAsString).toEqual('31deg') + expect(coercedActual?.astNode).toBeDefined() + }) it('returns NAN for an invalid expression', async () => { const actual = await getCalculatedKclExpressionValue('1 + x') const coercedActual = actual as Exclude diff --git a/src/lib/kclHelpers.ts b/src/lib/kclHelpers.ts index 284ce10d0..3244fa16a 100644 --- a/src/lib/kclHelpers.ts +++ b/src/lib/kclHelpers.ts @@ -1,5 +1,10 @@ import { executeAstMock } from '@src/lang/langHelpers' -import { type CallExpressionKw, parse, resultIsOk } from '@src/lang/wasm' +import { + type CallExpressionKw, + formatNumberValue, + parse, + resultIsOk, +} from '@src/lang/wasm' import type { KclCommandValue, KclExpression } from '@src/lib/commandTypes' import { rustContext } from '@src/lib/singletons' import { err } from '@src/lib/trap' @@ -32,12 +37,27 @@ export async function getCalculatedKclExpressionValue(value: string) { const variableDeclaratorAstNode = resultDeclaration?.type === 'VariableDeclaration' && resultDeclaration?.declaration.init - const resultRawValue = execState.variables[DUMMY_VARIABLE_NAME]?.value + const varValue = execState.variables[DUMMY_VARIABLE_NAME] + // If the value is a number, attempt to format it with units. + const resultValueWithUnits = (() => { + if (!varValue || varValue.type !== 'Number') { + return undefined + } + const formatted = formatNumberValue(varValue.value, varValue.ty) + if (err(formatted)) return undefined + return formatted + })() + // Prefer the formatted value with units. Fallback to the raw value. + const resultRawValue = varValue?.value + const valueAsString = resultValueWithUnits + ? resultValueWithUnits + : typeof resultRawValue === 'number' + ? String(resultRawValue) + : 'NAN' return { astNode: variableDeclaratorAstNode, - valueAsString: - typeof resultRawValue === 'number' ? String(resultRawValue) : 'NAN', + valueAsString, } } diff --git a/src/lib/useCalculateKclExpression.ts b/src/lib/useCalculateKclExpression.ts index 5bcbf5cf9..15184ab89 100644 --- a/src/lib/useCalculateKclExpression.ts +++ b/src/lib/useCalculateKclExpression.ts @@ -79,7 +79,7 @@ export function useCalculateKclExpression({ isValueParsable = false } const initialCalcResult: number | string = - Number.isNaN(Number(value)) || !isValueParsable ? 'NAN' : value + Number.isNaN(parseFloat(value)) || !isValueParsable ? 'NAN' : value const [calcResult, setCalcResult] = useState(initialCalcResult) const [newVariableName, _setNewVariableName] = useState('') const [isNewVariableNameUnique, setIsNewVariableNameUnique] = useState(true) diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts index cf96a8423..a5b850f44 100644 --- a/src/lib/utils.test.ts +++ b/src/lib/utils.test.ts @@ -8,6 +8,7 @@ import { isOverlap, onDragNumberCalculation, roundOff, + roundOffWithUnits, simulateOnMouseDragMatch, } from '@src/lib/utils' @@ -43,6 +44,48 @@ describe('testing roundOff', () => { }) }) +describe('roundOffWithUnits', () => { + it('works with no units', () => { + expect(roundOffWithUnits('1.23456789')).toBe('1.23') + expect(roundOffWithUnits('1.23456789', 3)).toBe('1.235') + expect(roundOffWithUnits('1.', 3)).toBe('1') + expect(roundOffWithUnits('-1.23456789')).toBe('-1.23') + expect(roundOffWithUnits('-1.23456789', 3)).toBe('-1.235') + expect(roundOffWithUnits('-1.', 3)).toBe('-1') + }) + it('works with standard units', () => { + expect(roundOffWithUnits('1.23456789mm', 3)).toBe('1.235mm') + expect(roundOffWithUnits('1.23456789m', 3)).toBe('1.235m') + expect(roundOffWithUnits('1.23456789in', 3)).toBe('1.235in') + expect(roundOffWithUnits('1.23456789_', 3)).toBe('1.235_') + expect(roundOffWithUnits('1._', 3)).toBe('1_') + expect(roundOffWithUnits('-1.23456789mm', 3)).toBe('-1.235mm') + expect(roundOffWithUnits('-1.23456789m', 3)).toBe('-1.235m') + expect(roundOffWithUnits('-1.23456789in', 3)).toBe('-1.235in') + expect(roundOffWithUnits('-1.23456789_', 3)).toBe('-1.235_') + expect(roundOffWithUnits('-1._', 3)).toBe('-1_') + expect(roundOffWithUnits('1.23456789e3mm', 3)).toBe('1234.568mm') + expect(roundOffWithUnits('1.23456789e3m', 3)).toBe('1234.568m') + expect(roundOffWithUnits('1.23456789e3in', 3)).toBe('1234.568in') + expect(roundOffWithUnits('1.23456789e3_', 3)).toBe('1234.568_') + expect(roundOffWithUnits('1.e3_', 3)).toBe('1000_') + expect(roundOffWithUnits('1e3_', 3)).toBe('1000_') + expect(roundOffWithUnits('1.23456789e-3mm', 3)).toBe('0.001mm') + expect(roundOffWithUnits('1.23456789e-3m', 3)).toBe('0.001m') + expect(roundOffWithUnits('1.23456789e-3in', 3)).toBe('0.001in') + expect(roundOffWithUnits('1.23456789e-3_', 3)).toBe('0.001_') + expect(roundOffWithUnits('1.e-3_', 3)).toBe('0.001_') + expect(roundOffWithUnits('1e-3_', 3)).toBe('0.001_') + }) + it('works with weird units', () => { + expect(roundOffWithUnits('1.23456789_?', 3)).toBe('1.235_?') + expect(roundOffWithUnits('-1.23456789_?', 3)).toBe('-1.235_?') + }) + it('returns the original string when used with something not parsable as a number', () => { + expect(roundOffWithUnits('foo', 3)).toBe('foo') + }) +}) + describe('testing hasLeadingZero', () => { it('.1 should have no leading zero', () => { const actual = hasLeadingZero('.1') diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 49b4e59c2..2b0e1a06f 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -328,6 +328,32 @@ export function roundOff(num: number, precision: number = 2): number { return Math.round(num * x) / x } +export function roundOffWithUnits( + numWithUnits: string, + precision: number = 2 +): string { + const match = numWithUnits.match( + /^([+-]?[\d.]+(?:[eE][+-]?\d+)?)([a-zA-Z_?]+)$/ + ) + let num: string + let suffix: string + if (match) { + num = match[1] + suffix = match[2] ?? '' + } else { + // If no match, assume it's just a number with no units. + num = numWithUnits + suffix = '' + } + const parsedNum = parseFloat(num) + if (Number.isNaN(parsedNum)) { + // If parsing fails, return the original string. + return numWithUnits + } + const roundedNum = roundOff(parsedNum, precision) + return `${roundedNum}${suffix}` +} + /** * Determine if the number as a string has any precision in the decimal places * '1' -> 0 diff --git a/src/lib/wasm_lib_wrapper.ts b/src/lib/wasm_lib_wrapper.ts index 1af4c9d97..8fee6b6c9 100644 --- a/src/lib/wasm_lib_wrapper.ts +++ b/src/lib/wasm_lib_wrapper.ts @@ -13,6 +13,7 @@ import type { default_app_settings as DefaultAppSettings, default_project_settings as DefaultProjectSettings, format_number_literal as FormatNumberLiteral, + format_number_value as FormatNumberValue, human_display_number as HumanDisplayNumber, get_kcl_version as GetKclVersion, get_tangential_arc_to_info as GetTangentialArcToInfo, @@ -59,6 +60,9 @@ export const recast_wasm: typeof RecastWasm = (...args) => { export const format_number_literal: typeof FormatNumberLiteral = (...args) => { return getModule().format_number_literal(...args) } +export const format_number_value: typeof FormatNumberValue = (...args) => { + return getModule().format_number_value(...args) +} export const human_display_number: typeof HumanDisplayNumber = (...args) => { return getModule().human_display_number(...args) } From 4a080d1583fd3f920b2d4e56aa7bad241c89ec46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 12:01:45 -0400 Subject: [PATCH 12/19] Bump @types/node from 22.15.32 to 24.0.3 in /packages/codemirror-lsp-client in the major group (#7490) Bump @types/node in /packages/codemirror-lsp-client in the major group Bumps the major group in /packages/codemirror-lsp-client with 1 update: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node). Updates `@types/node` from 22.15.32 to 24.0.3 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 24.0.3 dependency-type: direct:development update-type: version-update:semver-major dependency-group: major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Pierre Jacquier --- packages/codemirror-lsp-client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/codemirror-lsp-client/package.json b/packages/codemirror-lsp-client/package.json index 3462e18cf..7c937934e 100644 --- a/packages/codemirror-lsp-client/package.json +++ b/packages/codemirror-lsp-client/package.json @@ -29,7 +29,7 @@ "vscode-uri": "^3.1.0" }, "devDependencies": { - "@types/node": "^22.14.1", + "@types/node": "^24.0.7", "ts-node": "^10.9.2" } } From fbcbb341e24cfc779e5148466cdaf54865f0926a Mon Sep 17 00:00:00 2001 From: Adam Chalmers Date: Tue, 1 Jul 2025 12:42:12 -0500 Subject: [PATCH 13/19] KCL: Add planeOf function to stdlib (#7643) Gets the plane a face lies on, if any. Closes #7642 --- docs/kcl-std/functions/std-sketch-planeOf.md | 48 ++ docs/kcl-std/index.md | 1 + docs/kcl-std/modules/std-sketch.md | 1 + rust/justfile | 3 + rust/kcl-derive-docs/src/example_tests.rs | 1 + rust/kcl-lib/src/execution/cad_op.rs | 5 +- rust/kcl-lib/src/execution/exec_ast.rs | 8 +- rust/kcl-lib/src/execution/geometry.rs | 9 +- rust/kcl-lib/src/execution/kcl_value.rs | 36 +- rust/kcl-lib/src/execution/types.rs | 14 +- rust/kcl-lib/src/simulation_tests.rs | 21 + rust/kcl-lib/src/std/args.rs | 6 +- rust/kcl-lib/src/std/mod.rs | 4 + rust/kcl-lib/src/std/patterns.rs | 2 +- rust/kcl-lib/src/std/planes.rs | 116 ++- rust/kcl-lib/src/std/segment.rs | 8 +- rust/kcl-lib/src/std/shapes.rs | 9 +- rust/kcl-lib/src/std/sketch.rs | 4 +- rust/kcl-lib/std/sketch.kcl | 21 + ...al_test_example_fn_std-sketch-planeOf0.png | Bin 0 -> 19940 bytes .../tests/plane_of/artifact_commands.snap | 381 ++++++++++ .../plane_of/artifact_graph_flowchart.snap | 6 + .../plane_of/artifact_graph_flowchart.snap.md | 105 +++ rust/kcl-lib/tests/plane_of/ast.snap | 705 ++++++++++++++++++ rust/kcl-lib/tests/plane_of/input.kcl | 13 + rust/kcl-lib/tests/plane_of/ops.snap | 254 +++++++ .../tests/plane_of/program_memory.snap | 192 +++++ .../kcl-lib/tests/plane_of/rendered_model.png | Bin 0 -> 54480 bytes rust/kcl-lib/tests/plane_of/unparsed.snap | 16 + 29 files changed, 1945 insertions(+), 44 deletions(-) create mode 100644 docs/kcl-std/functions/std-sketch-planeOf.md create mode 100644 rust/kcl-lib/tests/outputs/serial_test_example_fn_std-sketch-planeOf0.png create mode 100644 rust/kcl-lib/tests/plane_of/artifact_commands.snap create mode 100644 rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap create mode 100644 rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap.md create mode 100644 rust/kcl-lib/tests/plane_of/ast.snap create mode 100644 rust/kcl-lib/tests/plane_of/input.kcl create mode 100644 rust/kcl-lib/tests/plane_of/ops.snap create mode 100644 rust/kcl-lib/tests/plane_of/program_memory.snap create mode 100644 rust/kcl-lib/tests/plane_of/rendered_model.png create mode 100644 rust/kcl-lib/tests/plane_of/unparsed.snap diff --git a/docs/kcl-std/functions/std-sketch-planeOf.md b/docs/kcl-std/functions/std-sketch-planeOf.md new file mode 100644 index 000000000..111a03db3 --- /dev/null +++ b/docs/kcl-std/functions/std-sketch-planeOf.md @@ -0,0 +1,48 @@ +--- +title: "planeOf" +subtitle: "Function in std::sketch" +excerpt: "Find the plane a face lies on. Returns an error if the face doesn't lie on any plane (for example, the curved face of a cylinder)" +layout: manual +--- + +Find the plane a face lies on. Returns an error if the face doesn't lie on any plane (for example, the curved face of a cylinder) + +```kcl +planeOf( + @solid: Solid, + face: TaggedFace, +): Plane +``` + + + +### Arguments + +| Name | Type | Description | Required | +|----------|------|-------------|----------| +| `solid` | [`Solid`](/docs/kcl-std/types/std-types-Solid) | The solid whose face is being queried. | Yes | +| `face` | [`TaggedFace`](/docs/kcl-std/types/std-types-TaggedFace) | Find the plane which this face lies on. | Yes | + +### Returns + +[`Plane`](/docs/kcl-std/types/std-types-Plane) - An abstract plane. + + +### Examples + +```kcl +triangle = startSketchOn(XY) + |> polygon(radius = 3, numSides = 3, center = [0, 0]) + |> extrude(length = 2) + +// Find the plane of the triangle's top face. +topPlane = planeOf(triangle, face = END) + +// Create a new plane, 10 units above the triangle's top face. +startSketchOn(offsetPlane(topPlane, offset = 10)) + +``` + +![Rendered example of planeOf 0](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAAAALQCAYAAADPfd1WAABNq0lEQVR4Ae3AA6AkWZbG8f937o3IzKdyS2Oubdu2bdu2bdu2bWmMnpZKr54yMyLu+Xa3anqmhztr1a8+6EEP4qqrrrrqqquuuuqqq6666qqrrrrqqquu+j+JylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuur/vBd7sRd7bZ6Pf/iHf/htrrrqqquuuuqqq676v4zKVVddddVVV1111VX/p73O67zOe3/4h3/4d128ePF2HuDEiRM3f/3Xf/37/NZv/dZ3c9VVV1111VVXXXXV/1XoQQ96EFddddVVV1111VVX/d90zTXXPPibvumbnv60pz3tD7/lW77lbXmAD/qgD/rJhz70oa/6IR/yIQ+57777buWqq6666qqrrrrqqv+LqFx11VVXXXXVVVdd9X/eiRMnbn7Hd3zHr+EBHvrQh74qV1111VVXXXXVVVf9X0flqquuuuqqq6666qr/077+67/+fT78wz/8u17u5V7unXguP/IjP/LZ9913361cddVVV1111VVXXfV/FXrQgx7EVVddddVVV1111VX/d11zzTUPfrEXe7HX5vn4rd/6re/mqquuuuqqq6666qr/y9CDHvQgrrrqqquuuuqqq6666qqrrrrqqquuuuqq/5Mox48f56qrrrrqqquuuuqq/x8+/MM//Lse/OAHvzSgs2fP3spVV1111VVXXXXVVf/XUbnqqquuuuqqq6666v+Fb/qmb3r6Nddc82Ce6UM+5EMect99993KVVddddVVV1111VX/lxFcddVVV1111VVXXfX/wjXXXPNgHuBzP/dzf5urrrrqqquuuuqqq/6vI7jqqquuuuqqq6666v+Ff/iHf/htnum+++679YM/+IMfzFVXXXXVVVddddVV/9ehBz3oQVx11VVXXXXVVVdd9f/D67zO67z3mTNnHvSjP/qjn8NVV1111VVXXXXVVf8foAc96EFcddVVV1111VVXXXXVVVddddVVV1111VX/J1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/Kv4R/WxcCe3yxu8AAAAASUVORK5CYII=) + + diff --git a/docs/kcl-std/index.md b/docs/kcl-std/index.md index 9b7cb37c8..4a31d1d64 100644 --- a/docs/kcl-std/index.md +++ b/docs/kcl-std/index.md @@ -67,6 +67,7 @@ layout: manual * [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d) * [`patternLinear2d`](/docs/kcl-std/functions/std-sketch-patternLinear2d) * [`patternTransform2d`](/docs/kcl-std/functions/std-sketch-patternTransform2d) + * [`planeOf`](/docs/kcl-std/functions/std-sketch-planeOf) * [`polygon`](/docs/kcl-std/functions/std-sketch-polygon) * [`profileStart`](/docs/kcl-std/functions/std-sketch-profileStart) * [`profileStartX`](/docs/kcl-std/functions/std-sketch-profileStartX) diff --git a/docs/kcl-std/modules/std-sketch.md b/docs/kcl-std/modules/std-sketch.md index b64f54467..a96536547 100644 --- a/docs/kcl-std/modules/std-sketch.md +++ b/docs/kcl-std/modules/std-sketch.md @@ -32,6 +32,7 @@ This module contains functions for creating and manipulating sketches, and makin * [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d) * [`patternLinear2d`](/docs/kcl-std/functions/std-sketch-patternLinear2d) * [`patternTransform2d`](/docs/kcl-std/functions/std-sketch-patternTransform2d) +* [`planeOf`](/docs/kcl-std/functions/std-sketch-planeOf) * [`polygon`](/docs/kcl-std/functions/std-sketch-polygon) * [`profileStart`](/docs/kcl-std/functions/std-sketch-profileStart) * [`profileStartX`](/docs/kcl-std/functions/std-sketch-profileStartX) diff --git a/rust/justfile b/rust/justfile index f098f05de..b85c94480 100644 --- a/rust/justfile +++ b/rust/justfile @@ -8,6 +8,9 @@ lint: # Ensure we can build without extra feature flags. cargo clippy -p kcl-lib --all-targets -- -D warnings +lint-fix: + cargo clippy --workspace --all-targets --all-features --fix + # Run the stdlib docs generation redo-kcl-stdlib-docs-no-imgs: EXPECTORATE=overwrite {{cnr}} {{kcl_lib_flags}} docs::gen_std_tests::test_generate_stdlib diff --git a/rust/kcl-derive-docs/src/example_tests.rs b/rust/kcl-derive-docs/src/example_tests.rs index 392fc3b91..27ba9fcf9 100644 --- a/rust/kcl-derive-docs/src/example_tests.rs +++ b/rust/kcl-derive-docs/src/example_tests.rs @@ -97,6 +97,7 @@ pub const TEST_NAMES: &[&str] = &[ "std-offsetPlane-2", "std-offsetPlane-3", "std-offsetPlane-4", + "std-sketch-planeOf-0", "std-sketch-circle-0", "std-sketch-circle-1", "std-sketch-patternTransform2d-0", diff --git a/rust/kcl-lib/src/execution/cad_op.rs b/rust/kcl-lib/src/execution/cad_op.rs index 6c277258b..585a50d04 100644 --- a/rust/kcl-lib/src/execution/cad_op.rs +++ b/rust/kcl-lib/src/execution/cad_op.rs @@ -226,10 +226,7 @@ impl From<&KclValue> for OpKclValue { match value { KclValue::Uuid { value, .. } => Self::Uuid { value: *value }, KclValue::Bool { value, .. } => Self::Bool { value: *value }, - KclValue::Number { value, ty, .. } => Self::Number { - value: *value, - ty: ty.clone(), - }, + KclValue::Number { value, ty, .. } => Self::Number { value: *value, ty: *ty }, KclValue::String { value, .. } => Self::String { value: value.clone() }, KclValue::Tuple { value, .. } | KclValue::HomArray { value, .. } => { let value = value.iter().map(Self::from).collect(); diff --git a/rust/kcl-lib/src/execution/exec_ast.rs b/rust/kcl-lib/src/execution/exec_ast.rs index 34639033d..9d2240e30 100644 --- a/rust/kcl-lib/src/execution/exec_ast.rs +++ b/rust/kcl-lib/src/execution/exec_ast.rs @@ -1297,7 +1297,7 @@ impl Node { Ok(KclValue::Number { value: -value, meta, - ty: ty.clone(), + ty: *ty, }) } KclValue::Plane { value } => { @@ -1329,7 +1329,7 @@ impl Node { .map(|v| match v { KclValue::Number { value, ty, meta } => Ok(KclValue::Number { value: *value * -1.0, - ty: ty.clone(), + ty: *ty, meta: meta.clone(), }), _ => Err(err()), @@ -1350,7 +1350,7 @@ impl Node { .map(|v| match v { KclValue::Number { value, ty, meta } => Ok(KclValue::Number { value: *value * -1.0, - ty: ty.clone(), + ty: *ty, meta: meta.clone(), }), _ => Err(err()), @@ -1544,7 +1544,7 @@ impl Node { .into_iter() .map(|num| KclValue::Number { value: num as f64, - ty: start_ty.clone(), + ty: start_ty, meta: meta.clone(), }) .collect(), diff --git a/rust/kcl-lib/src/execution/geometry.rs b/rust/kcl-lib/src/execution/geometry.rs index 2a091be4a..4745c6e94 100644 --- a/rust/kcl-lib/src/execution/geometry.rs +++ b/rust/kcl-lib/src/execution/geometry.rs @@ -939,6 +939,7 @@ impl From for Point3D { Self { x: p.x, y: p.y, z: p.z } } } + impl From for kittycad_modeling_cmds::shared::Point3d { fn from(p: Point3d) -> Self { Self { @@ -1004,12 +1005,12 @@ pub struct BasePath { impl BasePath { pub fn get_to(&self) -> [TyF64; 2] { let ty: NumericType = self.units.into(); - [TyF64::new(self.to[0], ty.clone()), TyF64::new(self.to[1], ty)] + [TyF64::new(self.to[0], ty), TyF64::new(self.to[1], ty)] } pub fn get_from(&self) -> [TyF64; 2] { let ty: NumericType = self.units.into(); - [TyF64::new(self.from[0], ty.clone()), TyF64::new(self.from[1], ty)] + [TyF64::new(self.from[0], ty), TyF64::new(self.from[1], ty)] } } @@ -1225,14 +1226,14 @@ impl Path { pub fn get_from(&self) -> [TyF64; 2] { let p = &self.get_base().from; let ty: NumericType = self.get_base().units.into(); - [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)] + [TyF64::new(p[0], ty), TyF64::new(p[1], ty)] } /// Where does this path segment end? pub fn get_to(&self) -> [TyF64; 2] { let p = &self.get_base().to; let ty: NumericType = self.get_base().units.into(); - [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)] + [TyF64::new(p[0], ty), TyF64::new(p[1], ty)] } /// The path segment start point and its type. diff --git a/rust/kcl-lib/src/execution/kcl_value.rs b/rust/kcl-lib/src/execution/kcl_value.rs index 71c2dba66..9f9a07451 100644 --- a/rust/kcl-lib/src/execution/kcl_value.rs +++ b/rust/kcl-lib/src/execution/kcl_value.rs @@ -415,15 +415,41 @@ impl KclValue { /// Put the point into a KCL value. pub fn from_point2d(p: [f64; 2], ty: NumericType, meta: Vec) -> Self { + let [x, y] = p; Self::Tuple { value: vec![ Self::Number { - value: p[0], + value: x, meta: meta.clone(), - ty: ty.clone(), + ty, }, Self::Number { - value: p[1], + value: y, + meta: meta.clone(), + ty, + }, + ], + meta, + } + } + + /// Put the point into a KCL value. + pub fn from_point3d(p: [f64; 3], ty: NumericType, meta: Vec) -> Self { + let [x, y, z] = p; + Self::Tuple { + value: vec![ + Self::Number { + value: x, + meta: meta.clone(), + ty, + }, + Self::Number { + value: y, + meta: meta.clone(), + ty, + }, + Self::Number { + value: z, meta: meta.clone(), ty, }, @@ -448,7 +474,7 @@ impl KclValue { pub fn as_int_with_ty(&self) -> Option<(i64, NumericType)> { match self { - KclValue::Number { value, ty, .. } => crate::try_f64_to_i64(*value).map(|i| (i, ty.clone())), + KclValue::Number { value, ty, .. } => crate::try_f64_to_i64(*value).map(|i| (i, *ty)), _ => None, } } @@ -562,7 +588,7 @@ impl KclValue { pub fn as_ty_f64(&self) -> Option { match self { - KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, ty.clone())), + KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, *ty)), _ => None, } } diff --git a/rust/kcl-lib/src/execution/types.rs b/rust/kcl-lib/src/execution/types.rs index 5546a6f88..6ea937ab5 100644 --- a/rust/kcl-lib/src/execution/types.rs +++ b/rust/kcl-lib/src/execution/types.rs @@ -460,7 +460,7 @@ impl fmt::Display for PrimitiveType { } } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ts_rs::TS, JsonSchema)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, ts_rs::TS, JsonSchema)] #[ts(export)] #[serde(tag = "type")] pub enum NumericType { @@ -575,7 +575,7 @@ impl NumericType { match (&ty, &i.ty) { (Any, Default { .. }) if i.n == 0.0 => {} (Any, t) => { - ty = t.clone(); + ty = *t; } (_, Unknown) | (Default { .. }, Default { .. }) => return (result, Unknown), @@ -598,7 +598,7 @@ impl NumericType { } if ty == Any && !input.is_empty() { - ty = input[0].ty.clone(); + ty = input[0].ty; } (result, ty) @@ -722,7 +722,7 @@ impl NumericType { if ty.subtype(self) { return Ok(KclValue::Number { value: *value, - ty: ty.clone(), + ty: *ty, meta: meta.clone(), }); } @@ -736,7 +736,7 @@ impl NumericType { (Any, _) => Ok(KclValue::Number { value: *value, - ty: self.clone(), + ty: *self, meta: meta.clone(), }), @@ -744,7 +744,7 @@ impl NumericType { // means accept any number rather than force the current default. (_, Default { .. }) => Ok(KclValue::Number { value: *value, - ty: ty.clone(), + ty: *ty, meta: meta.clone(), }), @@ -1491,7 +1491,7 @@ impl KclValue { pub fn principal_type(&self) -> Option { match self { KclValue::Bool { .. } => Some(RuntimeType::Primitive(PrimitiveType::Boolean)), - KclValue::Number { ty, .. } => Some(RuntimeType::Primitive(PrimitiveType::Number(ty.clone()))), + KclValue::Number { ty, .. } => Some(RuntimeType::Primitive(PrimitiveType::Number(*ty))), KclValue::String { .. } => Some(RuntimeType::Primitive(PrimitiveType::String)), KclValue::Object { value, .. } => { let properties = value diff --git a/rust/kcl-lib/src/simulation_tests.rs b/rust/kcl-lib/src/simulation_tests.rs index 776e364ae..40a507ba0 100644 --- a/rust/kcl-lib/src/simulation_tests.rs +++ b/rust/kcl-lib/src/simulation_tests.rs @@ -3632,3 +3632,24 @@ mod non_english_identifiers { super::execute(TEST_NAME, true).await } } +mod plane_of { + const TEST_NAME: &str = "plane_of"; + + /// Test parsing KCL. + #[test] + fn parse() { + super::parse(TEST_NAME) + } + + /// Test that parsing and unparsing KCL produces the original KCL input. + #[tokio::test(flavor = "multi_thread")] + async fn unparse() { + super::unparse(TEST_NAME).await + } + + /// Test that KCL is executed correctly. + #[tokio::test(flavor = "multi_thread")] + async fn kcl_test_execute() { + super::execute(TEST_NAME, true).await + } +} diff --git a/rust/kcl-lib/src/std/args.rs b/rust/kcl-lib/src/std/args.rs index 4aaecbee3..087a6220c 100644 --- a/rust/kcl-lib/src/std/args.rs +++ b/rust/kcl-lib/src/std/args.rs @@ -340,12 +340,12 @@ impl Args { let x = KclValue::Number { value: p[0], meta: vec![meta], - ty: ty.clone(), + ty, }; let y = KclValue::Number { value: p[1], meta: vec![meta], - ty: ty.clone(), + ty, }; let ty = RuntimeType::Primitive(PrimitiveType::Number(ty)); @@ -1038,7 +1038,7 @@ impl<'a> FromKclValue<'a> for u64 { impl<'a> FromKclValue<'a> for TyF64 { fn from_kcl_val(arg: &'a KclValue) -> Option { match arg { - KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, ty.clone())), + KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, *ty)), _ => None, } } diff --git a/rust/kcl-lib/src/std/mod.rs b/rust/kcl-lib/src/std/mod.rs index 4c124fcbf..152cd4be1 100644 --- a/rust/kcl-lib/src/std/mod.rs +++ b/rust/kcl-lib/src/std/mod.rs @@ -256,6 +256,10 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp |e, a| Box::pin(crate::std::shapes::circle(e, a)), StdFnProps::default("std::sketch::circle"), ), + ("sketch", "planeOf") => ( + |e, a| Box::pin(crate::std::planes::plane_of(e, a)), + StdFnProps::default("std::sketch::planeOf"), + ), ("sketch", "extrude") => ( |e, a| Box::pin(crate::std::extrude::extrude(e, a)), StdFnProps::default("std::sketch::extrude").include_in_feature_tree(), diff --git a/rust/kcl-lib/src/std/patterns.rs b/rust/kcl-lib/src/std/patterns.rs index 454385f83..b1807553b 100644 --- a/rust/kcl-lib/src/std/patterns.rs +++ b/rust/kcl-lib/src/std/patterns.rs @@ -408,7 +408,7 @@ impl GeometryTrait for Sketch { exec_state: &mut ExecState, ) -> Result<[TyF64; 3], KclError> { let [x, y] = array_to_point2d(val, source_ranges, exec_state)?; - let ty = x.ty.clone(); + let ty = x.ty; Ok([x, y, TyF64::new(0.0, ty)]) } diff --git a/rust/kcl-lib/src/std/planes.rs b/rust/kcl-lib/src/std/planes.rs index 59389196e..25fe4cce3 100644 --- a/rust/kcl-lib/src/std/planes.rs +++ b/rust/kcl-lib/src/std/planes.rs @@ -1,15 +1,123 @@ //! Standard library plane helpers. use kcmc::{ModelingCmd, each_cmd as mcmd, length_unit::LengthUnit, shared::Color}; -use kittycad_modeling_cmds as kcmc; +use kittycad_modeling_cmds::{self as kcmc, ok_response::OkModelingCmdResponse, websocket::OkWebSocketResponseData}; -use super::{args::TyF64, sketch::PlaneData}; +use super::{ + args::TyF64, + sketch::{FaceTag, PlaneData}, +}; use crate::{ - errors::KclError, - execution::{ExecState, KclValue, ModelingCmdMeta, Plane, PlaneType, types::RuntimeType}, + UnitLen, + errors::{KclError, KclErrorDetails}, + execution::{ExecState, KclValue, Metadata, ModelingCmdMeta, Plane, PlaneType, types::RuntimeType}, std::Args, }; +/// Find the plane of a given face. +pub async fn plane_of(exec_state: &mut ExecState, args: Args) -> Result { + let solid = args.get_unlabeled_kw_arg("solid", &RuntimeType::solid(), exec_state)?; + let face = args.get_kw_arg("face", &RuntimeType::tagged_face(), exec_state)?; + + inner_plane_of(solid, face, exec_state, &args) + .await + .map(Box::new) + .map(|value| KclValue::Plane { value }) +} + +async fn inner_plane_of( + solid: crate::execution::Solid, + face: FaceTag, + exec_state: &mut ExecState, + args: &Args, +) -> Result { + // Support mock execution + // Return an arbitrary (incorrect) plane and a non-fatal error. + if args.ctx.no_engine_commands().await { + let plane_id = exec_state.id_generator().next_uuid(); + exec_state.err(crate::CompilationError { + source_range: args.source_range, + message: "The engine isn't available, so returning an arbitrary incorrect plane".to_owned(), + suggestion: None, + severity: crate::errors::Severity::Error, + tag: crate::errors::Tag::None, + }); + return Ok(Plane { + artifact_id: plane_id.into(), + id: plane_id, + // Engine doesn't know about the ID we created, so set this to Uninit. + value: PlaneType::Uninit, + info: crate::execution::PlaneInfo { + origin: Default::default(), + x_axis: Default::default(), + y_axis: Default::default(), + }, + meta: vec![Metadata { + source_range: args.source_range, + }], + }); + } + + // Query the engine to learn what plane, if any, this face is on. + let face_id = face.get_face_id(&solid, exec_state, args, true).await?; + let meta = args.into(); + let cmd = ModelingCmd::FaceIsPlanar(mcmd::FaceIsPlanar { object_id: face_id }); + let plane_resp = exec_state.send_modeling_cmd(meta, cmd).await?; + let OkWebSocketResponseData::Modeling { + modeling_response: OkModelingCmdResponse::FaceIsPlanar(planar), + } = plane_resp + else { + return Err(KclError::new_semantic(KclErrorDetails::new( + format!( + "Engine returned invalid response, it should have returned FaceIsPlanar but it returned {plane_resp:#?}" + ), + vec![args.source_range], + ))); + }; + // Destructure engine's response to check if the face was on a plane. + let not_planar: Result<_, KclError> = Err(KclError::new_semantic(KclErrorDetails::new( + "The face you provided doesn't lie on any plane. It might be curved.".to_owned(), + vec![args.source_range], + ))); + let Some(x_axis) = planar.x_axis else { return not_planar }; + let Some(y_axis) = planar.y_axis else { return not_planar }; + let Some(origin) = planar.origin else { return not_planar }; + + // Engine always returns measurements in mm. + let engine_units = UnitLen::Mm; + let x_axis = crate::execution::Point3d { + x: x_axis.x, + y: x_axis.y, + z: x_axis.z, + units: engine_units, + }; + let y_axis = crate::execution::Point3d { + x: y_axis.x, + y: y_axis.y, + z: y_axis.z, + units: engine_units, + }; + let origin = crate::execution::Point3d { + x: origin.x.0, + y: origin.y.0, + z: origin.z.0, + units: engine_units, + }; + + // Engine doesn't send back an ID, so let's just make a new plane ID. + let plane_id = exec_state.id_generator().next_uuid(); + Ok(Plane { + artifact_id: plane_id.into(), + id: plane_id, + // Engine doesn't know about the ID we created, so set this to Uninit. + value: PlaneType::Uninit, + info: crate::execution::PlaneInfo { origin, x_axis, y_axis }, + meta: vec![Metadata { + source_range: args.source_range, + }], + }) +} + /// Offset a plane by a distance along its normal. pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result { let std_plane = args.get_unlabeled_kw_arg("plane", &RuntimeType::plane(), exec_state)?; diff --git a/rust/kcl-lib/src/std/segment.rs b/rust/kcl-lib/src/std/segment.rs index 42d40bf42..02b873c79 100644 --- a/rust/kcl-lib/src/std/segment.rs +++ b/rust/kcl-lib/src/std/segment.rs @@ -18,7 +18,7 @@ pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result Result<[TyF64; 2], KclError> { @@ -31,7 +31,7 @@ fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args })?; let (p, ty) = path.end_point_components(); // Docs generation isn't smart enough to handle ([f64; 2], NumericType). - let point = [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)]; + let point = [TyF64::new(p[0], ty), TyF64::new(p[1], ty)]; Ok(point) } @@ -81,7 +81,7 @@ pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result Result<[TyF64; 2], KclError> { @@ -94,7 +94,7 @@ fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar })?; let (p, ty) = path.start_point_components(); // Docs generation isn't smart enough to handle ([f64; 2], NumericType). - let point = [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)]; + let point = [TyF64::new(p[0], ty), TyF64::new(p[1], ty)]; Ok(point) } diff --git a/rust/kcl-lib/src/std/shapes.rs b/rust/kcl-lib/src/std/shapes.rs index 74685e392..5518f228b 100644 --- a/rust/kcl-lib/src/std/shapes.rs +++ b/rust/kcl-lib/src/std/shapes.rs @@ -71,7 +71,7 @@ async fn inner_circle( let radius = get_radius(radius, diameter, args.source_range)?; let from = [center_u[0] + radius.to_length_units(units), center_u[1]]; - let from_t = [TyF64::new(from[0], ty.clone()), TyF64::new(from[1], ty)]; + let from_t = [TyF64::new(from[0], ty), TyF64::new(from[1], ty)]; let sketch = crate::std::sketch::inner_start_profile(sketch_surface, from_t, None, exec_state, args.clone()).await?; @@ -156,7 +156,7 @@ async fn inner_circle_three_point( exec_state: &mut ExecState, args: Args, ) -> Result { - let ty = p1[0].ty.clone(); + let ty = p1[0].ty; let units = ty.expect_length(); let p1 = point_to_len_unit(p1, units); @@ -172,10 +172,7 @@ async fn inner_circle_three_point( SketchOrSurface::Sketch(group) => group.on, }; - let from = [ - TyF64::new(center[0] + radius, ty.clone()), - TyF64::new(center[1], ty.clone()), - ]; + let from = [TyF64::new(center[0] + radius, ty), TyF64::new(center[1], ty)]; let sketch = crate::std::sketch::inner_start_profile(sketch_surface, from.clone(), None, exec_state, args.clone()).await?; diff --git a/rust/kcl-lib/src/std/sketch.rs b/rust/kcl-lib/src/std/sketch.rs index cd09df518..8b67c7096 100644 --- a/rust/kcl-lib/src/std/sketch.rs +++ b/rust/kcl-lib/src/std/sketch.rs @@ -599,7 +599,7 @@ async fn inner_angled_line_of_x_length( } let to = get_y_component(Angle::from_degrees(angle_degrees), length.n); - let to = [TyF64::new(to[0], length.ty.clone()), TyF64::new(to[1], length.ty)]; + let to = [TyF64::new(to[0], length.ty), TyF64::new(to[1], length.ty)]; let new_sketch = straight_line(StraightLineParams::relative(to, sketch, tag), exec_state, args).await?; @@ -666,7 +666,7 @@ async fn inner_angled_line_of_y_length( } let to = get_x_component(Angle::from_degrees(angle_degrees), length.n); - let to = [TyF64::new(to[0], length.ty.clone()), TyF64::new(to[1], length.ty)]; + let to = [TyF64::new(to[0], length.ty), TyF64::new(to[1], length.ty)]; let new_sketch = straight_line(StraightLineParams::relative(to, sketch, tag), exec_state, args).await?; diff --git a/rust/kcl-lib/std/sketch.kcl b/rust/kcl-lib/std/sketch.kcl index 9c1e59b67..864b0246e 100644 --- a/rust/kcl-lib/std/sketch.kcl +++ b/rust/kcl-lib/std/sketch.kcl @@ -1941,3 +1941,24 @@ export fn subtract2d( /// The shape(s) which should be cut out of the sketch. tool: [Sketch; 1+], ): Sketch {} + +/// Find the plane a face lies on. +/// Returns an error if the face doesn't lie on any plane (for example, the curved face of a cylinder) +///```kcl +/// triangle = startSketchOn(XY) +/// |> polygon(radius = 3, numSides = 3, center = [0, 0]) +/// |> extrude(length = 2) +/// +/// // Find the plane of the triangle's top face. +/// topPlane = planeOf(triangle, face = END) +/// +/// // Create a new plane, 10 units above the triangle's top face. +/// startSketchOn(offsetPlane(topPlane, offset = 10)) +/// ``` +@(impl = std_rust) +export fn planeOf( + /// The solid whose face is being queried. + @solid: Solid, + /// Find the plane which this face lies on. + face: TaggedFace, +): Plane {} diff --git a/rust/kcl-lib/tests/outputs/serial_test_example_fn_std-sketch-planeOf0.png b/rust/kcl-lib/tests/outputs/serial_test_example_fn_std-sketch-planeOf0.png new file mode 100644 index 0000000000000000000000000000000000000000..df07af62749bad3358ed88ae23f17f80daead70a GIT binary patch literal 19940 zcmeHP+e?#S9G*p4f-I2`y4W%U!;3C5>7v{)6|+bxG>JSx7t%omO=p@e5*aJQi^vFR z%><2x8&Xsr+9E|ec!JOop|fb_0VkT`{B-;J)GmI%+#e9~z}UvvyYG8{`@PTiJkR@V z`ZGxhfdP90WHMP`;)%F(GTAoi>6U>V+ogy8vf=YG*=bW^TugGY-}Jk!#{Cy+x@JX< z>)wZ+#{5&4%sJm){k>hTGSr;37!F15b1fCUzEaYlJ9>4{q8g8p|9EaPw@z-n6V&=o zDXHm&gB$M_w7Vbp9@IK1Mnw1?R5&Q6B>Oy)bac`5EX~)Eq}RmMvn@VOZ}pVDmZ$kX zPH**tJel#%jdNO?r(nB-iIIxp8)NN{RwTWFHO6|wWCnO};0JiH1_5{gJit6C0R&g1 z)c^_R)d0Kast2-#sZD?fUoKG4Y`MT1VD1ON1Ko?yFsZK!31~!JT_M{M{Ex%Z4N2TF;r{aI;}g0gqQ?d z70nWfjc@y=+WSh^-ls`#FP<$@jCSgSk7zx1t!H^rCnF(z07pr&5<}FjLbf{O_GF;9K*W==Y>bWrW+}Fin zjiZSqv?RV%GEkxDBr9Lkq!;u?$;+imHQUFQ+)WOlX=aRMu*A>Oi21#wdfckHf1tZs z`HK!vuAhoxWz^qx*!Uv5e}om=&VpfLWuDNGS0Y5&(|%_eCSp}TV-@+1vc+LG=3x+> zh4_B$-HOoy^vgFM&Lc23WA%}D>=CQFP@iZdV2y8Q<}d&Nlr literal 0 HcmV?d00001 diff --git a/rust/kcl-lib/tests/plane_of/artifact_commands.snap b/rust/kcl-lib/tests/plane_of/artifact_commands.snap new file mode 100644 index 000000000..8a38a1a13 --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/artifact_commands.snap @@ -0,0 +1,381 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact commands plane_of.kcl +--- +{ + "rust/kcl-lib/tests/plane_of/input.kcl": [ + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "make_plane", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "x_axis": { + "x": 1.0, + "y": 0.0, + "z": 0.0 + }, + "y_axis": { + "x": 0.0, + "y": 1.0, + "z": 0.0 + }, + "size": 60.0, + "clobber": false, + "hide": true + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "start_path" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "move_path_pen", + "path": "[uuid]", + "to": { + "x": 2743.2, + "y": 0.0, + "z": 0.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": -1371.5999999999995, + "y": 2375.680887661472, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": -1371.6000000000013, + "y": -2375.680887661472, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 2743.2, + "y": 0.0, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "close_path", + "path_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extrude", + "target": "[uuid]", + "distance": 1828.8, + "faces": null, + "opposite": "None" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_bring_to_front", + "object_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_extrusion_face_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_adjacency_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "face_is_planar", + "object_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "make_plane", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 3657.6 + }, + "x_axis": { + "x": 1.0, + "y": 0.0, + "z": 0.0 + }, + "y_axis": { + "x": 0.0, + "y": 1.0, + "z": 0.0 + }, + "size": 100.0, + "clobber": false, + "hide": false + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "plane_set_color", + "plane_id": "[uuid]", + "color": { + "r": 0.6, + "g": 0.6, + "b": 0.6, + "a": 0.3 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_visible", + "object_id": "[uuid]", + "hidden": true + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "start_path" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "move_path_pen", + "path": "[uuid]", + "to": { + "x": 1828.8, + "y": 0.0, + "z": 0.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 0.00000000000011198170331403397, + "y": 1828.8, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": -1828.8, + "y": 0.00000000000022396340662806795, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": -0.0000000000003359451099421019, + "y": -1828.8, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 1828.8, + "y": 0.0, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "close_path", + "path_id": "[uuid]" + } + } + ], + "std::appearance": [], + "std::array": [], + "std::math": [], + "std::prelude": [], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap b/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap new file mode 100644 index 000000000..4d1e0089e --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap @@ -0,0 +1,6 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact graph flowchart plane_of.kcl +extension: md +snapshot_kind: binary +--- diff --git a/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap.md b/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap.md new file mode 100644 index 000000000..17cc9b7e7 --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap.md @@ -0,0 +1,105 @@ +```mermaid +flowchart LR + subgraph path2 [Path] + 2["Path
    [64, 114, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 3["Segment
    [64, 114, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 4["Segment
    [64, 114, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 5["Segment
    [64, 114, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 6["Segment
    [64, 114, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 7[Solid2d] + end + subgraph path21 [Path] + 21["Path
    [311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 22["Segment
    [311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 23["Segment
    [311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 24["Segment
    [311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 25["Segment
    [311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 26["Segment
    [311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 27[Solid2d] + end + 1["Plane
    [41, 58, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 0 }] + 8["Sweep Extrusion
    [120, 139, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 2 }] + 9[Wall] + %% face_code_ref=Missing NodePath + 10[Wall] + %% face_code_ref=Missing NodePath + 11[Wall] + %% face_code_ref=Missing NodePath + 12["Cap Start"] + %% face_code_ref=Missing NodePath + 13["Cap End"] + %% face_code_ref=Missing NodePath + 14["SweepEdge Opposite"] + 15["SweepEdge Adjacent"] + 16["SweepEdge Opposite"] + 17["SweepEdge Adjacent"] + 18["SweepEdge Opposite"] + 19["SweepEdge Adjacent"] + 20["Plane
    [277, 304, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 0 }, CallKwUnlabeledArg] + 28["StartSketchOnPlane
    [263, 305, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 0 }] + 1 --- 2 + 2 --- 3 + 2 --- 4 + 2 --- 5 + 2 --- 6 + 2 --- 7 + 2 ---- 8 + 3 --- 9 + 3 x--> 12 + 3 --- 14 + 3 --- 15 + 4 --- 10 + 4 x--> 12 + 4 --- 16 + 4 --- 17 + 5 --- 11 + 5 x--> 12 + 5 --- 18 + 5 --- 19 + 8 --- 9 + 8 --- 10 + 8 --- 11 + 8 --- 12 + 8 --- 13 + 8 --- 14 + 8 --- 15 + 8 --- 16 + 8 --- 17 + 8 --- 18 + 8 --- 19 + 9 --- 14 + 9 --- 15 + 19 <--x 9 + 15 <--x 10 + 10 --- 16 + 10 --- 17 + 17 <--x 11 + 11 --- 18 + 11 --- 19 + 14 <--x 13 + 16 <--x 13 + 18 <--x 13 + 20 --- 21 + 20 <--x 28 + 21 --- 22 + 21 --- 23 + 21 --- 24 + 21 --- 25 + 21 --- 26 + 21 --- 27 +``` diff --git a/rust/kcl-lib/tests/plane_of/ast.snap b/rust/kcl-lib/tests/plane_of/ast.snap new file mode 100644 index 000000000..7db45f037 --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/ast.snap @@ -0,0 +1,705 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of parsing plane_of.kcl +--- +{ + "Ok": { + "body": [ + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "tri", + "start": 0, + "type": "Identifier" + }, + "init": { + "body": [ + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "startSketchOn", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "XY", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "radius", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "3", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 3.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "numSides", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "3", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 3.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "center", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + }, + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "polygon", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "length", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "extrude", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "nonCodeMeta": { + "nonCodeNodes": { + "2": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "NonCodeNode", + "value": { + "type": "newLineBlockComment", + "value": "Get the plane which `tri` ends on.", + "style": "line" + } + } + ] + }, + "startNodes": [] + }, + "start": 0, + "type": "PipeExpression", + "type": "PipeExpression" + }, + "moduleId": 0, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "const", + "moduleId": 0, + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + }, + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "p0", + "start": 0, + "type": "Identifier" + }, + "init": { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "face", + "start": 0, + "type": "Identifier" + }, + "arg": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "END", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "planeOf", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "tri", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + "moduleId": 0, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "const", + "moduleId": 0, + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + }, + { + "commentStart": 0, + "end": 0, + "expression": { + "body": [ + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "startSketchOn", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "offset", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "offsetPlane", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "p0", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + } + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "radius", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "numSides", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "4", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 4.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "center", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + }, + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "polygon", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "PipeExpression", + "type": "PipeExpression" + }, + "moduleId": 0, + "preComments": [ + "", + "", + "// Offset that plane by 2, then draw a square on it." + ], + "start": 0, + "type": "ExpressionStatement", + "type": "ExpressionStatement" + } + ], + "commentStart": 0, + "end": 0, + "innerAttrs": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "settings", + "start": 0, + "type": "Identifier" + }, + "properties": [ + { + "commentStart": 0, + "end": 0, + "key": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "defaultLengthUnit", + "start": 0, + "type": "Identifier" + }, + "moduleId": 0, + "start": 0, + "type": "ObjectProperty", + "value": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "yd", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + } + ], + "start": 0, + "type": "Annotation" + } + ], + "moduleId": 0, + "nonCodeMeta": { + "nonCodeNodes": { + "2": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "NonCodeNode", + "value": { + "type": "newLine" + } + } + ] + }, + "startNodes": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "NonCodeNode", + "value": { + "type": "newLine" + } + } + ] + }, + "start": 0 + } +} diff --git a/rust/kcl-lib/tests/plane_of/input.kcl b/rust/kcl-lib/tests/plane_of/input.kcl new file mode 100644 index 000000000..bca0bfa3a --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/input.kcl @@ -0,0 +1,13 @@ +@settings(defaultLengthUnit = yd) + +tri = startSketchOn(XY) + |> polygon(radius = 3, numSides = 3, center = [0, 0]) + |> extrude(length = 2) + +// Get the plane which `tri` ends on. +p0 = planeOf(tri, face = END) + +// Offset that plane by 2, then draw a square on it. +startSketchOn(offsetPlane(p0, offset = 2)) + |> polygon(radius = 2, numSides = 4, center = [0, 0]) + diff --git a/rust/kcl-lib/tests/plane_of/ops.snap b/rust/kcl-lib/tests/plane_of/ops.snap new file mode 100644 index 000000000..adfad681b --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/ops.snap @@ -0,0 +1,254 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Operations executed plane_of.kcl +--- +{ + "rust/kcl-lib/tests/plane_of/input.kcl": [ + { + "type": "StdLibCall", + "name": "startSketchOn", + "unlabeledArg": { + "value": { + "type": "Plane", + "artifact_id": "[uuid]" + }, + "sourceRange": [] + }, + "labeledArgs": {}, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 0 + }, + { + "type": "VariableDeclarationDeclaration" + }, + { + "type": "VariableDeclarationInit" + }, + { + "type": "PipeBodyItem", + "index": 0 + } + ] + }, + "sourceRange": [] + }, + { + "type": "StdLibCall", + "name": "extrude", + "unlabeledArg": { + "value": { + "type": "Sketch", + "value": { + "artifactId": "[uuid]" + } + }, + "sourceRange": [] + }, + "labeledArgs": { + "length": { + "value": { + "type": "Number", + "value": 2.0, + "ty": { + "type": "Default", + "len": { + "type": "Yards" + }, + "angle": { + "type": "Degrees" + } + } + }, + "sourceRange": [] + } + }, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 0 + }, + { + "type": "VariableDeclarationDeclaration" + }, + { + "type": "VariableDeclarationInit" + }, + { + "type": "PipeBodyItem", + "index": 2 + } + ] + }, + "sourceRange": [] + }, + { + "type": "StdLibCall", + "name": "offsetPlane", + "unlabeledArg": { + "value": { + "type": "Plane", + "artifact_id": "[uuid]" + }, + "sourceRange": [] + }, + "labeledArgs": { + "offset": { + "value": { + "type": "Number", + "value": 2.0, + "ty": { + "type": "Default", + "len": { + "type": "Yards" + }, + "angle": { + "type": "Degrees" + } + } + }, + "sourceRange": [] + } + }, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 2 + }, + { + "type": "ExpressionStatementExpr" + }, + { + "type": "PipeBodyItem", + "index": 0 + }, + { + "type": "CallKwUnlabeledArg" + } + ] + }, + "sourceRange": [] + }, + { + "type": "StdLibCall", + "name": "startSketchOn", + "unlabeledArg": { + "value": { + "type": "Plane", + "artifact_id": "[uuid]" + }, + "sourceRange": [] + }, + "labeledArgs": {}, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 2 + }, + { + "type": "ExpressionStatementExpr" + }, + { + "type": "PipeBodyItem", + "index": 0 + } + ] + }, + "sourceRange": [] + } + ], + "std::appearance": [], + "std::array": [], + "std::math": [ + { + "type": "VariableDeclaration", + "name": "PI", + "value": { + "type": "Number", + "value": 3.141592653589793, + "ty": { + "type": "Unknown" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "E", + "value": { + "type": "Number", + "value": 2.718281828459045, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "TAU", + "value": { + "type": "Number", + "value": 6.283185307179586, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::prelude": [ + { + "type": "VariableDeclaration", + "name": "START", + "value": { + "type": "String", + "value": "start" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "END", + "value": { + "type": "String", + "value": "end" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/plane_of/program_memory.snap b/rust/kcl-lib/tests/plane_of/program_memory.snap new file mode 100644 index 000000000..ddd84bc7c --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/program_memory.snap @@ -0,0 +1,192 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Variables in memory after executing plane_of.kcl +--- +{ + "p0": { + "type": "Plane", + "value": { + "artifactId": "[uuid]", + "id": "[uuid]", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 1828.8, + "units": { + "type": "Mm" + } + }, + "value": "Uninit", + "xAxis": { + "x": 1.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Mm" + } + }, + "yAxis": { + "x": 0.0, + "y": 1.0, + "z": 0.0, + "units": { + "type": "Mm" + } + } + } + }, + "tri": { + "type": "Solid", + "value": { + "type": "Solid", + "id": "[uuid]", + "artifactId": "[uuid]", + "value": [ + { + "faceId": "[uuid]", + "id": "[uuid]", + "sourceRange": [], + "tag": null, + "type": "extrudePlane" + }, + { + "faceId": "[uuid]", + "id": "[uuid]", + "sourceRange": [], + "tag": null, + "type": "extrudePlane" + }, + { + "faceId": "[uuid]", + "id": "[uuid]", + "sourceRange": [], + "tag": null, + "type": "extrudePlane" + } + ], + "sketch": { + "type": "Sketch", + "id": "[uuid]", + "paths": [ + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + 3.0, + 0.0 + ], + "tag": null, + "to": [ + -1.4999999999999993, + 2.598076211353316 + ], + "type": "ToPoint", + "units": { + "type": "Yards" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + -1.4999999999999993, + 2.598076211353316 + ], + "tag": null, + "to": [ + -1.5000000000000013, + -2.5980762113533156 + ], + "type": "ToPoint", + "units": { + "type": "Yards" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + -1.5000000000000013, + -2.5980762113533156 + ], + "tag": null, + "to": [ + 3.0, + 0.0 + ], + "type": "ToPoint", + "units": { + "type": "Yards" + } + } + ], + "on": { + "artifactId": "[uuid]", + "id": "[uuid]", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Mm" + } + }, + "type": "plane", + "value": "XY", + "xAxis": { + "x": 1.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Unknown" + } + }, + "yAxis": { + "x": 0.0, + "y": 1.0, + "z": 0.0, + "units": { + "type": "Unknown" + } + } + }, + "start": { + "from": [ + 3.0, + 0.0 + ], + "to": [ + 3.0, + 0.0 + ], + "units": { + "type": "Yards" + }, + "tag": null, + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + } + }, + "artifactId": "[uuid]", + "originalId": "[uuid]", + "units": { + "type": "Yards" + } + }, + "height": 2.0, + "startCapId": "[uuid]", + "endCapId": "[uuid]", + "units": { + "type": "Yards" + }, + "sectional": false + } + } +} diff --git a/rust/kcl-lib/tests/plane_of/rendered_model.png b/rust/kcl-lib/tests/plane_of/rendered_model.png new file mode 100644 index 0000000000000000000000000000000000000000..441e64b83669814edc99a141d17eacbf07a2c549 GIT binary patch literal 54480 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 polygon(radius = 3, numSides = 3, center = [0, 0]) + |> extrude(length = 2) + +// Get the plane which `tri` ends on. +p0 = planeOf(tri, face = END) + +// Offset that plane by 2, then draw a square on it. +startSketchOn(offsetPlane(p0, offset = 2)) + |> polygon(radius = 2, numSides = 4, center = [0, 0]) From 7f9851ae288cc33ae47d481bc09822946daa9c8f Mon Sep 17 00:00:00 2001 From: Kevin Nadro Date: Tue, 1 Jul 2025 13:01:42 -0500 Subject: [PATCH 14/19] [Chore]: Added url-checker, updated circular-deps, documented new static analysis .txt pattern (#7442) * fix: ignoring url checker files * fix: url checker * fix: auto fmt and cleanup * fix: moving the bash scripts and known files into the scripts repo * fix: removed all url_results and made it be all in memory * fix: fixed the newline issue * fix: url checking as a step to the static analysis * fix: removed old code * chore: writing documentation on our static checker pattern * fix: updating the docs more to be clearer * fix: copy and paste without understanding requirements of ci cd dependencies? do i need all of these? * fix: updating * fix: I thought this got in? * Update CONTRIBUTING.md Co-authored-by: Jace Browning --------- Co-authored-by: Jace Browning --- .github/workflows/static-analysis.yml | 30 ++++++++++ .gitignore | 2 +- CONTRIBUTING.md | 41 ++++++++++++++ package.json | 5 +- scripts/diff-circular-deps.sh | 2 +- scripts/diff-url-checker.sh | 5 ++ .../known/circular.txt | 0 scripts/known/urls.txt | 21 +++++++ scripts/url-checker.sh | 56 +++++++++++++++++++ 9 files changed, 159 insertions(+), 3 deletions(-) create mode 100755 scripts/diff-url-checker.sh rename known-circular.txt => scripts/known/circular.txt (100%) create mode 100644 scripts/known/urls.txt create mode 100755 scripts/url-checker.sh diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 12805fd5d..bc07de134 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -120,6 +120,36 @@ jobs: - run: npm run circular-deps:diff + npm-url-checker: + runs-on: ubuntu-latest + needs: npm-build-wasm + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'npm' + - run: npm install + + - name: Download all artifacts + uses: actions/download-artifact@v4 + + - name: Copy prepared wasm + run: | + ls -R prepared-wasm + cp prepared-wasm/kcl_wasm_lib_bg.wasm public + mkdir rust/kcl-wasm-lib/pkg + cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg + + - name: Copy prepared ts-rs bindings + run: | + ls -R prepared-ts-rs-bindings + mkdir rust/kcl-lib/bindings + cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/ + + - run: npm run url-checker:diff + python-codespell: runs-on: ubuntu-22.04 steps: diff --git a/.gitignore b/.gitignore index 25e5edc45..562e471c2 100644 --- a/.gitignore +++ b/.gitignore @@ -87,4 +87,4 @@ venv .vscode-test .biome/ -.million +.million \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6427419d3..d124a1bf1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -235,6 +235,47 @@ To display logging (to the terminal or console) set `ZOO_LOG=1`. This will log s To enable memory metrics, build with `--features dhat-heap`. +## Running scripts + +There are multiple scripts under the folder path `./scripts` which can be used in various settings. + +### Pattern for a static file, npm run commands, and CI-CD checks + +If you want to implement a static checker follow this pattern. Two static checkers we have are circular dependency checks in our typescript code and url checker to see if any hard coded URL is the typescript application 404s. We have a set of known files in `./scripts/known/*.txt` which is the baseline. + +If you improve the baseline, run the overwrite command and commit the new smaller baseline. Try not to make the baseline bigger, the CI CD will complain. +These baselines are to hold us to higher standards and help implement automated testing against the repository + +#### Output result to stdout +- `npm run circular-deps` +- `npm run url-checker` + +- create a `.sh` file that will run the static checker then output the result to `stdout` + +#### Overwrite result to known .txt file on disk + +If the application needs to overwrite the known file on disk use this pattern. This known .txt file will be source controlled as the baseline + +- `npm run circular-deps:overwrite` +- `npm run url-checker:overwrite` + +#### Diff baseline and current + +These commands will write a /tmp/ file on disk and compare it to the known file in the repository. This command will also be used in the CI CD pipeline for automated checks + +- create a `diff-.sh` file that is the script to diff your tmp file to the baseline +e.g. `diff-url-checker.sh` +```bash +#!/bin/bash +set -euo pipefail + +npm run url-checker > /tmp/urls.txt +diff --ignore-blank-lines -w /tmp/urls.txt ./scripts/known/urls.txt +``` + +- `npm run circular-deps:diff` +- `npm run url-checker:diff` + ## Proposing changes Before you submit a contribution PR to this repo, please ensure that: diff --git a/package.json b/package.json index 5d56502a2..07ebc3da8 100644 --- a/package.json +++ b/package.json @@ -110,8 +110,11 @@ "remove-importmeta": "sed -i 's/import.meta.url/window.location.origin/g' \"./rust/kcl-wasm-lib/pkg/kcl_wasm_lib.js\"; sed -i '' 's/import.meta.url/window.location.origin/g' \"./rust/kcl-wasm-lib/pkg/kcl_wasm_lib.js\" || echo \"sed for both mac and linux\"", "lint-fix": "eslint --fix --ext .ts --ext .tsx src e2e packages/codemirror-lsp-client/src rust/kcl-language-server/client/src", "lint": "eslint --max-warnings 0 --ext .ts --ext .tsx src e2e packages/codemirror-lsp-client/src rust/kcl-language-server/client/src", + "url-checker":"./scripts/url-checker.sh", + "url-checker:overwrite":"npm run url-checker > scripts/known/urls.txt", + "url-checker:diff":"./scripts/diff-url-checker.sh", "circular-deps": "dpdm --no-warning --no-tree -T --skip-dynamic-imports=circular src/index.tsx", - "circular-deps:overwrite": "npm run circular-deps | sed '$d' | grep -v '^npm run' > known-circular.txt", + "circular-deps:overwrite": "npm run circular-deps | sed '$d' | grep -v '^npm run' > scripts/known/circular.txt", "circular-deps:diff": "./scripts/diff-circular-deps.sh", "circular-deps:diff:nodejs": "npm run circular-deps:diff || node ./scripts/diff.js", "files:set-version": "echo \"$(jq --arg v \"$VERSION\" '.version=$v' package.json --indent 2)\" > package.json", diff --git a/scripts/diff-circular-deps.sh b/scripts/diff-circular-deps.sh index 425b363b2..9d95765e6 100755 --- a/scripts/diff-circular-deps.sh +++ b/scripts/diff-circular-deps.sh @@ -2,4 +2,4 @@ set -euo pipefail npm run circular-deps | sed '$d' > /tmp/circular-deps.txt -diff --ignore-blank-lines -w /tmp/circular-deps.txt ./known-circular.txt +diff --ignore-blank-lines -w /tmp/circular-deps.txt ./scripts/known/circular.txt diff --git a/scripts/diff-url-checker.sh b/scripts/diff-url-checker.sh new file mode 100755 index 000000000..21b4e4fa2 --- /dev/null +++ b/scripts/diff-url-checker.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -euo pipefail + +npm run url-checker > /tmp/urls.txt +diff --ignore-blank-lines -w /tmp/urls.txt ./scripts/known/urls.txt diff --git a/known-circular.txt b/scripts/known/circular.txt similarity index 100% rename from known-circular.txt rename to scripts/known/circular.txt diff --git a/scripts/known/urls.txt b/scripts/known/urls.txt new file mode 100644 index 000000000..2b08be00e --- /dev/null +++ b/scripts/known/urls.txt @@ -0,0 +1,21 @@ + +> zoo-modeling-app@0.0.0 url-checker +> ./scripts/url-checker.sh + +URL STATUS +000 https://${BASE_URL} +301 https://discord.gg/JQEpHR7Nt2 +404 https://github.com/KittyCAD/engine/issues/3528 +404 https://github.com/KittyCAD/modeling-app/commit/${ref} +302 https://github.com/KittyCAD/modeling-app/issues/new/choose +302 https://github.com/KittyCAD/modeling-app/issues/new?template=bug_report.yml +302 https://github.com/KittyCAD/modeling-app/issues/new?title=${title}&body=${body} +404 https://github.com/KittyCAD/modeling-app/releases/tag/v${version} +521 https://placekitten.com/200/200 +302 https://reactrouter.com/en/6.16.0/routers/picking-a-router#using-v64-data-apis +302 https://stackoverflow.com/a/57390160/22753272 +302 https://stackoverflow.com/a/58436959/22753272 +303 https://text-to-cad.zoo.dev/dashboard +307 https://zoo.dev/ +308 https://zoo.dev/docs/api/ml/generate-a-cad-model-from-text +308 https://zoo.dev/docs/kcl diff --git a/scripts/url-checker.sh b/scripts/url-checker.sh new file mode 100755 index 000000000..450e86214 --- /dev/null +++ b/scripts/url-checker.sh @@ -0,0 +1,56 @@ +#!/bin/bash +set -euo pipefail +trap 'echo "$BASH_COMMAND"' ERR + +remove_after_space () { + sed 's/ .*//' +} + +remove_after_backtick () { + sed 's/`.*//' +} + +remove_after_end_paren () { + sed 's/).*//' +} + +remove_after_double_quote () { + sed 's/".*//' +} + +remove_after_gt () { + sed 's/>.*//' +} + +remove_after_comma () { + sed 's/,.*//' +} + +# Search all src/**/*.ts files +val1=$(grep -Eoh "(https)://[^']+" src/**/*.ts | remove_after_space | remove_after_backtick | remove_after_end_paren | remove_after_double_quote | remove_after_gt | remove_after_comma) + +# Search all src/**/*.tsx files +val2=$(grep -Eoh "(https)://[^']+" src/**/*.tsx | remove_after_space | remove_after_backtick | remove_after_end_paren | remove_after_double_quote | remove_after_gt | remove_after_comma) + +# Required a newline between them when combining since there is not one at the end of val1 +combined="$val1"$'\n'"$val2" + +# Merge both ts and tsx results and unique them +uniqued=$(echo "$combined" | sort | uniq) + +# All urls and status codes +all="URL\tSTATUS\n" + +# All non 200 urls and status codes +problematic="URL\tSTATUS\n" +while read line; do + # || true this curl request to bypass any failures and not have the scrip panic. + # the set -euo pipefail will cause a panic if a curl fails + status=$(curl -o /dev/null -s -w "%{http_code}\n" $line || true) + all+="$status\t$line\n" + if [[ "$status" -ne 200 ]]; then + # list status first over line because of white space formatting, less annoying for diffing + problematic+="$status\t$line\n" + fi +done < <(echo "$uniqued") +echo -e $problematic | column -t From 051bb0589e324db2403d1e96d275c08764b9582c Mon Sep 17 00:00:00 2001 From: Adam Chalmers Date: Tue, 1 Jul 2025 13:26:04 -0500 Subject: [PATCH 15/19] KCL: rectangle function (#7616) * KCL test for rectangle * Rectangle function * Rectangle helper tests * Rectangle helper * Fix clippy lints * Update docs * fmt * Fix bug * fmt * Fix doc comments * Update generated docs --------- Co-authored-by: Jonathan Tran --- .../kcl-std/functions/std-sketch-rectangle.md | 55 ++ docs/kcl-std/index.md | 1 + docs/kcl-std/modules/std-sketch.md | 1 + rust/kcl-derive-docs/src/example_tests.rs | 2 + rust/kcl-lib/src/execution/geometry.rs | 2 +- rust/kcl-lib/src/simulation_tests.rs | 42 ++ rust/kcl-lib/src/std/mod.rs | 4 + rust/kcl-lib/src/std/shapes.rs | 113 +++ rust/kcl-lib/std/sketch.kcl | 33 + ..._test_example_fn_std-sketch-rectangle0.png | Bin 0 -> 24230 bytes ..._test_example_fn_std-sketch-rectangle1.png | Bin 0 -> 24230 bytes .../kcl-lib/tests/rect/artifact_commands.snap | 163 ++++ .../tests/rect/artifact_graph_flowchart.snap | 6 + .../rect/artifact_graph_flowchart.snap.md | 27 + rust/kcl-lib/tests/rect/ast.snap | 701 ++++++++++++++++++ rust/kcl-lib/tests/rect/input.kcl | 7 + rust/kcl-lib/tests/rect/ops.snap | 128 ++++ rust/kcl-lib/tests/rect/program_memory.snap | 181 +++++ rust/kcl-lib/tests/rect/rendered_model.png | Bin 0 -> 26188 bytes rust/kcl-lib/tests/rect/unparsed.snap | 11 + .../tests/rect_helper/artifact_commands.snap | 163 ++++ .../rect_helper/artifact_graph_flowchart.snap | 6 + .../artifact_graph_flowchart.snap.md | 24 + rust/kcl-lib/tests/rect_helper/ast.snap | 233 ++++++ rust/kcl-lib/tests/rect_helper/input.kcl | 2 + rust/kcl-lib/tests/rect_helper/ops.snap | 128 ++++ .../tests/rect_helper/program_memory.snap | 144 ++++ .../tests/rect_helper/rendered_model.png | Bin 0 -> 26188 bytes rust/kcl-lib/tests/rect_helper/unparsed.snap | 6 + 29 files changed, 2182 insertions(+), 1 deletion(-) create mode 100644 docs/kcl-std/functions/std-sketch-rectangle.md create mode 100644 rust/kcl-lib/tests/outputs/serial_test_example_fn_std-sketch-rectangle0.png create mode 100644 rust/kcl-lib/tests/outputs/serial_test_example_fn_std-sketch-rectangle1.png create mode 100644 rust/kcl-lib/tests/rect/artifact_commands.snap create mode 100644 rust/kcl-lib/tests/rect/artifact_graph_flowchart.snap create mode 100644 rust/kcl-lib/tests/rect/artifact_graph_flowchart.snap.md create mode 100644 rust/kcl-lib/tests/rect/ast.snap create mode 100644 rust/kcl-lib/tests/rect/input.kcl create mode 100644 rust/kcl-lib/tests/rect/ops.snap create mode 100644 rust/kcl-lib/tests/rect/program_memory.snap create mode 100644 rust/kcl-lib/tests/rect/rendered_model.png create mode 100644 rust/kcl-lib/tests/rect/unparsed.snap create mode 100644 rust/kcl-lib/tests/rect_helper/artifact_commands.snap create mode 100644 rust/kcl-lib/tests/rect_helper/artifact_graph_flowchart.snap create mode 100644 rust/kcl-lib/tests/rect_helper/artifact_graph_flowchart.snap.md create mode 100644 rust/kcl-lib/tests/rect_helper/ast.snap create mode 100644 rust/kcl-lib/tests/rect_helper/input.kcl create mode 100644 rust/kcl-lib/tests/rect_helper/ops.snap create mode 100644 rust/kcl-lib/tests/rect_helper/program_memory.snap create mode 100644 rust/kcl-lib/tests/rect_helper/rendered_model.png create mode 100644 rust/kcl-lib/tests/rect_helper/unparsed.snap diff --git a/docs/kcl-std/functions/std-sketch-rectangle.md b/docs/kcl-std/functions/std-sketch-rectangle.md new file mode 100644 index 000000000..5654a837b --- /dev/null +++ b/docs/kcl-std/functions/std-sketch-rectangle.md @@ -0,0 +1,55 @@ +--- +title: "rectangle" +subtitle: "Function in std::sketch" +excerpt: "Sketch a rectangle." +layout: manual +--- + +Sketch a rectangle. + +```kcl +rectangle( + @sketchOrSurface: Sketch | Plane | Face, + width: number(Length), + height: number(Length), + center?: Point2d, + corner?: Point2d, +): Sketch +``` + + + +### Arguments + +| Name | Type | Description | Required | +|----------|------|-------------|----------| +| `sketchOrSurface` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) or [`Plane`](/docs/kcl-std/types/std-types-Plane) or [`Face`](/docs/kcl-std/types/std-types-Face) | Sketch to extend, or plane or surface to sketch on. | Yes | +| `width` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | Rectangle's width along X axis. | Yes | +| `height` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | Rectangle's height along Y axis. | Yes | +| `center` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | The center of the rectangle. Incompatible with `corner`. | No | +| `corner` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | The corner of the rectangle. Incompatible with `center`. This will be the corner which is most negative on both X and Y axes. | No | + +### Returns + +[`Sketch`](/docs/kcl-std/types/std-types-Sketch) - A sketch is a collection of paths. + + +### Examples + +```kcl +exampleSketch = startSketchOn(-XZ) + |> rectangle(center = [0, 0], width = 10, height = 5) + +``` + +![Rendered example of rectangle 0](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAAAALQCAYAAADPfd1WAABebUlEQVR4Ae3AA6AkWZbG8f937o3IzKdyS2Oubdu2bdu2bdu2bWmMnpZKr54yMyLu+Xa3anqmhztr1a8+6EEP4qqrrrrqqquuuuqqq6666qqrrrrqqquu+j+JylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqmf5pm/6pqdz1VVXXXXVVVdd9X+YJNk2DyBJts0DSJJt8wCSZNs8gCTZNg8gSbbNA0iSbfMAkmTbPIAk2TYPIEm2zQNIkm3zAJJk2wAf8iEf8hCuuuqqq64CoHLVVVddddVln/u5n/tbr/u6r/tgrrrqqquuuuqqq676X++bvumbnv4hH/IhD+Gqq6666ioqV1111VVXPct6vWZ7e5urrrrqqquuuuqqq/73GoaBq6666qqrnoXKVVddddVVV1111VVXXXXVVVf9H7K/v88//MM//DZXXXXVVVcBEFx11VVXXXXZ3//93//2wcEBV1111VVXXXXVVVf97zYMA/fdd9+tXHXVVVddBUBw1VVXXXXVZf/wD//wO3fffTdXXXXVVVddddVVV/3vNgwDZ8+efQZXXXXVVVcBULnqqquuuuqqq6666qqrrrrqqv9D9vf3+Yd/+Iff5qqrrrrqKgAqV1111VVXXXb27Nlbueqqq6666qqrrrrqf71hGLjqqquuuupZCK666qqrrrrsvvvuu/W+++67dRgGrrrqqquuuuqqq6763+2+++67lauuuuqqqwAIrrrqqquuepazZ8/eul6vueqqq6666qqrrrrqf6fz58/zW7/1W9/NVVddddVV9yO46qqrrrrqWe67775bDw4OuOqqq6666qqrrrrqqquuuuqq/yMIrrrqqquuepb77rvv1rvvvpurrrrqqquuuuqqq/53Ojg44B/+4R9+h6uuuuqqq+5H5aqrrrrqqmf5h3/4h9/hqquuuuqqq6666qqrrrrqqqv+76By1VVXXXXVs5w9e/ZWrrrqqquuuuqqq676X2t/f59/+Id/+G2uuuqqq666H5Wrrrrqqque5b777ruVq6666qqrrrrqqqv+1xqGgfvuu+9Wrrrqqquuuh/BVVddddVVz+Ef/uEffnt/f5+rrrrqqquuuuqqq/53OTg44B/+4R9+m6uuuuqqqx6IylVXXXXVVVddddVVV1111VVX/R+wXq+57777buWqq6666qoHIrjqqquuuuo5/P3f//1vP/nJT+aqq6666qqrrrrqqv9dhmHgvvvuu5WrrrrqqqseiMpVV1111VXP4R/+4R9+h6uuuuqqq6666qqr/tcZhoGzZ88+g6uuuuqqqx6IylVXXXXVVc/h7Nmzt3LVVVddddVVV1111f86+/v7/MM//MNvc9VVV1111QNRueqqq6666qqrrrrqqquuuuqq/wOGYeC+++67lauuuuqqqx6I4Kqrrrrqqudw33333XrffffdOgwDV1111VVXXXXVVVf97zAMA1ddddVVVz1fBFddddVVVz2Ps2fP3rper7nqqquuuuqqq6666n+H/f19fuu3fut7uOqqq6666rkRXHXVVVdd9Tz+/u///rcPDg646qqrrrrqqquuuuqqq6666qr/5Qiuuuqqq656HmfPnn3G3XffzVVXXXXVVVddddVV/zscHBzwD//wD7/NVVddddVVz43KVVddddVVz+O+++67lauuuuqqq6666qqr/tdYr9ecPXv2Vq666qqrrnpuVK666qqrrnoeZ8+evZWrrrrqqquuuuqqq/7XGIaB++6771auuuqqq656bgRXXXXVVVc9j/vuu+9WgGEYuOqqq6666qqrrrrqf75hGLjvvvtu5aqrrrrqqudGcNVVV1111fP1D//wD7+9Xq+56qqrrrrqqquuuup/tv39ff7hH/7ht7nqqquuuur5oXLVVVddddXzdd999906DANXXXXVVVddddVVV/3PNgwD9913361cddVVV131/BBcddVVV131fN133323PuMZz+Cqq6666qqrrrrqqv/ZDg4OuO+++27lqquuuuqq54fKVVddddVVz9c//MM//A5XXXXVVVddddVVV/2vcPbs2Wdw1VVXXXXV80Plqquuuuqq5+vs2bO3ctVVV1111VVXXXXV/3j7+/v8wz/8w29z1VVXXXXV80Plqquuuuqqq6666qqrrrrqqqv+FxuGgfvuu+9Wrrrqqquuen4Irrrqqquuer7uu+++W//hH/7ht/f397nqqquuuuqqq6666n+mYRi47777buWqq6666qoXhMpVV1111VVXXXXVVVddddVVV/0vtb+/zz/8wz/8NlddddVVV70gBFddddVVV71Af//3f//bBwcHXHXVVVddddVVV131P9MwDNx33323ctVVV1111QtCcNVVV1111Qv0D//wD79z9913c9VVV1111VVXXXXV/0zDMHD27NlncNVVV1111QtC5aqrrrrqqquuuuqqq6666qqr/pfa39/nH/7hH36bq6666qqrXhAqV1111VVXvUBnz569lauuuuqqq6666qqr/scahoGrrrrqqqteKIKrrrrqqqteoPvuu+/W++6779ZhGLjqqquuuuqqq6666n+m++6771auuuqqq656QQiuuuqqq656oc6ePXvrer3mqquuuuqqq6666qr/Wc6fP89v/dZvfTdXXXXVVVe9MARXXXXVVVe9UPfdd9+tBwcHXHXVVVddddVVV1111VVXXXXV/0IEV1111VVXvVD33XffrXfffTdXXXXVVVddddVVV/3PcnBwwD/8wz/8DlddddVVV70wVK666qqrrnqh/uEf/uF3uOqqq6666qqrrrrqqquuuuqq/52oXHXVVVdd9UKdPXv2Vq666qqrrrrqqquu+h9nf3+ff/iHf/htrrrqqquuemGoXHXVVVdd9ULdd999t3LVVVddddVVV1111f84wzBw33333cpVV1111VUvDMFVV1111VX/on/4h3/47f39fa666qqrrrrqqquu+p/h4OCAf/iHf/htrrrqqquu+pdQueqqq6666qqrrrrqqquuuuqq/2XW6zX33XffrVx11VVXXfUvIbjqqquuuupf9Pd///e//eQnP5mrrrrqqquuuuqqq/5nGIaB++6771auuuqqq676l1C56qqrrrrqX/QP//APv8NVV1111VVXXXXVVf9jDMPA2bNnn8FVV1111VX/EipXXXXVVVf9i86ePXsrV1111VVXXXXVVVf9j7G/v88//MM//DZXXXXVVVf9S6hcddVVV1111VVXXXXVVVddddX/MsMwcN99993KVVddddVV/xKCq6666qqr/kX33Xffrffdd9+twzBw1VVXXXXVVVddddV/r2EYuOqqq6666kVGcNVVV1111Yvk7Nmzt67Xa6666qqrrrrqqquu+u+1v7/Pb/3Wb30PV1111VVXvSgIrrrqqquuepH8/d///W8fHBxw1VVXXXXVVVddddVVV1111VX/ixBcddVVV131Ijl79uwz7r77bq666qqrrrrqqquu+u91cHDAP/zDP/w2V1111VVXvSioXHXVVVdd9SK57777buWqq6666qqrrrrqqv926/Was2fP3spVV1111VUvCipXXXXVVVe9SM6ePXsrV1111VVXXXXVVVf9txuGgfvuu+9WrrrqqquuelEQXHXVVVdd9SK57777bgUYhoGrrrrqqquuuuqqq/77DMPAfffddytXXXXVVVe9KAiuuuqqq656kf3DP/zDb6/Xa6666qqrrrrqqquu+u+xv7/PP/zDP/w2V1111VVXvaioXHXVVVdd9SK77777bh2Ggauuuuqqq6666qqr/nsMw8B99913K1ddddVVV72oCK666qqrrnqR3Xfffbc+4xnP4Kqrrrrqqquuuuqq/x4HBwfcd999t3LVVVddddWLispVV1111VUvsn/4h3/4Ha666qqrrrrqqquu+m919uzZZ3DVVVddddWLispVV1111VUvsrNnz97KVVddddVVV1111VX/bfb39/mHf/iH3+aqq6666qoXFZWrrrrqqquuuuqqq6666qqrrvpfYhgG7rvvvlu56qqrrrrqRUVw1VVXXXXVi+y+++679R/+4R9+e39/n6uuuuqqq6666qqr/msNw8B99913K1ddddVVV/1rULnqqquuuuqqq6666qqrrrrqqv8F9vf3+Yd/+Iff5qqrrrrqqn8Ngquuuuqqq/5V/v7v//63Dw4OuOqqq6666qqrrrrqv9YwDNx33323ctVVV1111b8GwVVXXXXVVf8q//AP//A7d999N1ddddVVV1111VVX/dcahoGzZ88+g6uuuuqqq/41qFx11VVXXXXVVVddddVVV1111f8C+/v7/MM//MNvc9VVV1111b8Glauuuuqqq/5Vzp49eytXXXXVVVddddVVV/2XG4aBq6666qqr/tUIrrrqqquu+le57777br3vvvtuHYaBq6666qqrrrrqqqv+a9133323ctVVV1111b8GwVVXXXXVVf9qZ8+evXW9XnPVVVddddVVV1111X+N8+fP81u/9VvfzVVXXXXVVf9aBFddddVVV/2r3XfffbceHBxw1VVXXXXVVVddddVVV1111VX/wxFcddVVV131r3bffffdevfdd3PVVVddddVVV1111X+Ng4MD/uEf/uF3uOqqq6666l+LylVXXXXVVf9q//AP//A7XHXVVVddddVVV1111VVXXXXV/3xUrrrqqquu+lc7e/bsrVx11VVXXXXVVVdd9V9mf3+ff/iHf/htrrrqqquu+teictVVV1111b/afffddytXXXXVVVddddVVV/2XGYaB++6771auuuqqq6761yK46qqrrrrq3+Qf/uEffnt/f5+rrrrqqquuuuqqq/5zHRwc8A//8A+/zVVXXXXVVf8WVK666qqrrrrqqquuuuqqq6666n+w9XrNfffddytXXXXVVVf9WxBcddVVV131b/L3f//3v/3kJz+Zq6666qqrrrrqqqv+cw3DwH333XcrV1111VVX/VtQueqqq6666t/kH/7hH36Hq6666qqrrrrqqqv+0w3DwNmzZ5/BVVddddVV/xZUrrrqqquu+jc5e/bsrVx11VVXXXXVVVdd9Z9uf3+ff/iHf/htrrrqqquu+regctVVV1111VVXXXXVVVddddVV/4MNw8B99913K1ddddVVV/1bEFx11VVXXfVvct99991633333ToMA1ddddVVV1111VVX/ecYhoGrrrrqqqv+XQiuuuqqq676Nzt79uyt6/Waq6666qqrrrrqqqv+c+zv7/Nbv/Vb38NVV1111VX/VgRXXXXVVVf9m/393//9bx8cHHDVVVddddVVV1111VVXXXXVVf9DEVx11VVXXfVvdvbs2WfcfffdXHXVVVddddVVV131n+Pg4IB/+Id/+G2uuuqqq676t6Jy1VVXXXXVv9l99913K1ddddVVV1111VVX/adZr9ecPXv2Vq666qqrrvq3onLVVVddddW/2dmzZ2/lqquuuuqqq6666qr/NMMwcN99993KVVddddVV/1YEV1111VVX/Zvdd999twIMw8BVV1111VVXXXXVVf/xhmHgvvvuu5Wrrrrqqqv+rQiuuuqqq676d/mHf/iH316v11x11VVXXXXVVVdd9R9rf3+ff/iHf/htrrrqqquu+vegctVVV1111b/Lfffdd+swDFx11VVXXXXVVVdd9R9rGAbuu+++W7nqqquuuurfg+Cqq6666qp/l/vuu+/WZzzjGVx11VVXXXXVVVdd9R/r4OCA++6771auuuqqq67696By1VVXXXXVv8s//MM//A5XXXXVVVddddVVV/2nOHv27DO46qqrrrrq34PKVVddddVV/y5nz569lauuuuqqq6666qqr/sPt7+/zD//wD7/NVVddddVV/x5Urrrqqquuuuqqq6666qqrrrrqf6BhGLjvvvtu5aqrrrrqqn8Pgquuuuqqq/5d7rvvvlv/4R/+4bf39/e56qqrrrrqqquuuuo/xjAM3Hfffbdy1VVXXXXVvxeVq6666qqrrrrqqquuuuqqq676H2Z/f59/+Id/+G2uuuqqq6769yK46qqrrrrq3+3v//7vf/vg4ICrrrrqqquuuuqqq/5jDMPAfffddytXXXXVVVf9exFcddVVV1317/YP//APv3P33Xdz1VVXXXXVVVddddV/jGEYOHv27DO46qqrrrrq34vKVVddddVVV1111VVXXXXVVVf9D7O/v88//MM//DZXXXXVVVf9e1G56qqrrrrq3+3s2bO3ctVVV1111VVXXXXVf5hhGLjqqquuuuo/BMFVV1111VX/bvfdd9+t9913363DMHDVVVddddVVV1111X+M++6771auuuqqq6769yK46qqrrrrqP8TZs2dvXa/XXHXVVVddddVVV13173P+/Hl+67d+67u56qqrrrrqPwLBVVddddVV/yHuu+++Ww8ODrjqqquuuuqqq6666qqrrrrqqv9BCK666qqrrvoPcd9999169913c9VVV1111VVXXXXVv8/BwQH/8A//8DtcddVVV131H4HKVVddddVV/yH+4R/+4Xe46qqrrrrqqquuuuqqq6666qr/WahcddVVV131H+Ls2bO3ctVVV1111VVXXXXVv9v+/j7/8A//8NtcddVVV131H4HKVVddddVV/yHuu+++W7nqqquuuuqqq6666t9tGAbuu+++W7nqqquuuuo/AsFVV1111VX/Yf7hH/7ht/f397nqqquuuuqqq6666t/m4OCAf/iHf/htrrrqqquu+o9C5aqrrrrqqquuuuqqq6666qqr/odYr9fcd999t3LVVVddddV/FIKrrrrqqqv+w/z93//9bz/5yU/mqquuuuqqq6666qp/m2EYuO+++27lqquuuuqq/yhUrrrqqquu+g/zD//wD7/DVVddddVVV1111VX/ZsMwcPbs2Wdw1VVXXXXVfxQqV1111VVX/Yc5e/bsrVx11VVXXXXVVVdd9W+2v7/PP/zDP/w2V1111VVX/UehctVVV1111VVXXXXVVVddddVV/0MMw8B99913K1ddddVVV/1HIbjqqquuuuo/zH333Xfrfffdd+swDFx11VVXXXXVVVdd9a8zDANXXXXVVVf9hyO46qqrrrrqP9TZs2dvXa/XXHXVVVddddVVV131r7O/v89v/dZvfQ9XXXXVVVf9RyK46qqrrrrqP9Tf//3f//bBwQFXXXXVVVddddVVV1111VVXXfU/AMFVV1111VX/oc6ePfuMu+++m6uuuuqqq6666qqr/nUODg74h3/4h9/mqquuuuqq/0hUrrrqqquu+g9133333cpVV1111VVXXXXVVf9q6/Was2fP3spVV1111VX/kahcddVVV131H+rs2bO3ctVVV1111VVXXXXVv9owDNx33323ctVVV1111X8kgquuuuqqq/5D3XfffbcCDMPAVVddddVVV1111VUvumEYuO+++27lqquuuuqq/0gEV1111VVX/Yf7h3/4h99er9dcddVVV1111VVXXfWi2d/f5x/+4R9+m6uuuuqqq/6jUbnqqquuuuo/3H333XfrMAxcddVVV1111VVXXfWiGYaB++6771auuuqqq676j0Zw1VVXXXXVf7j77rvv1mc84xlcddVVV1111VVXXfWiOTg44L777ruVq6666qqr/qNRueqqq6666j/cP/zDP/wOV1111VVXXXXVVVf9q5w9e/YZXHXVVVdd9R+NylVXXXXVVf/hzp49eytXXXXVVVddddVVV73I9vf3+Yd/+Iff5qqrrrrqqv9oVK666qqrrrrqqquuuuqqq6666r/ZMAzcd999t3LVVVddddV/NIKrrrrqqqv+w9133323/sM//MNv7+/vc9VVV1111VVXXXXVCzcMA/fdd9+tXHXVVVdd9Z+BylVXXXXVVVddddVVV1111VVX/Tfa39/nH/7hH36bq6666qqr/jMQXHXVVVdd9Z/i7//+73/74OCAq6666qqrrrrqqqteuGEYuO+++27lqquuuuqq/wwEV1111VVX/af4h3/4h9+5++67ueqqq6666qqrrrrqhRuGgbNnzz6Dq6666qqr/jNQueqqq6666qqrrrrqqquuuuqq/0b7+/v8wz/8w29z1VVXXXXVfwYqV1111VVX/ac4e/bsrVx11VVXXXXVVVdd9S8ahoGrrrrqqqv+0xBcddVVV131n+K+++679b777rt1GAauuuqqq6666qqrrnrh7rvvvlu56qqrrrrqPwPBVVddddVV/2nOnj1763q95qqrrrrqqquuuuqq5+/8+fP81m/91ndz1VVXXXXVfxaCq6666qqr/tPcd999tx4cHHDVVVddddVVV1111VVXXXXVVf9NCK666qqrrvpPc99999169913c9VVV1111VVXXXXV83dwcMA//MM//A5XXXXVVVf9Z6Fy1VVXXXXVf5p/+Id/+B2uuuqqq6666qqrrrrqqquuuuq/D5Wrrrrqqqv+05w9e/ZWrrrqqquuuuqqq656gfb39/mHf/iH3+aqq6666qr/LFSuuuqqq676T3PffffdylVXXXXVVVddddVVL9AwDNx33323ctVVV1111X8Wgquuuuqqq/5T/cM//MNv7+/vc9VVV1111VVXXXXVczo4OOAf/uEffpurrrrqqqv+M1G56qqrrrrqqquuuuqqq6666qr/Buv1mvvuu+9Wrrrqqquu+s9EcNVVV1111X+qv//7v//tJz/5yVx11VVXXXXVVVdd9ZyGYeC+++67lauuuuqqq/4zUbnqqquuuuo/1T/8wz/8DlddddVVV1111VVXPY9hGDh79uwzuOqqq6666j8Tlauuuuqqq/5TnT179lauuuqqq6666qqrrnoe+/v7/MM//MNvc9VVV1111X8mKlddddVVV1111VVXXXXVVVdd9d9gGAbuu+++W7nqqquuuuo/E8FVV1111VX/qe67775b77vvvlv39/e56qqrrrrqqquuuuqKYRi46qqrrrrqvwTBVVddddVV/+nOnj17K1ddddVVV1111VVXPcv+/j6/9Vu/9T1cddVVV131n43gqquuuuqq/3R///d//9sHBwdcddVVV1111VVXXXXVVVddddV/MYKrrrrqqqv+0509e/YZd999N1ddddVVV1111VVXXXFwcMA//MM//DZXXXXVVVf9Z6Ny1VVXXXXVf7r77rvvVq666qqrrrrqqquuepb9/X3Onj17K1ddddVVV/1no3LVVVddddV/urNnz97KVVddddVVV1111VXP4b777ruVq6666qqr/rMRXHXVVVdd9Z/uvvvuuxVgGAauuuqqq6666qqrroJhGLjvvvtu5aqrrrrqqv9sBFddddVVV/2X+Id/+IffXq/XXHXVVVddddVVV/1/t7+/zz/8wz/8NlddddVVV/1XoHLVVVddddV/ifvuu+/WYRi46qqrrrrqqquu+v9uGAbuu+++W7nqqquuuuq/AsFVV1111VX/Je67775bn/GMZ3DVVVddddVVV131/93BwQH33XffrVx11VVXXfVfgcpVV1111VX/Jf7hH/7hd7jqqquuuuqqq6666rKzZ88+g6uuuuqqq/4rULnqqquuuuq/xNmzZ2/lqquuuuqqq6666ir29/f5h3/4h9/mqquuuuqq/wpUrrrqqquuuuqqq6666qqrrrrqv9AwDNx33323ctVVV1111X8Fgquuuuqqq/5L3Hfffbf+wz/8w2/v7+9z1VVXXXXVVVdd9f/VMAzcd999t3LVVVddddV/FSpXXXXVVVddddVVV1111VVXXfVfZH9/n3/4h3/4ba666qqrrvqvQnDVVVddddV/mb//+7//7YODA6666qqrrrrqqqv+vxqGgfvuu+9Wrrrqqquu+q9CcNVVV1111X+Zf/iHf/idu+++m6uuuuqqq6666qr/r4Zh4OzZs8/gqquuuuqq/ypUrrrqqquuuuqqq6666qqrrrrqv8j+/j7/8A//8NtcddVVV131X4XKVVddddVV/2XOnj17K1ddddVVV1111VX/jw3DwFVXXXXVVf+lCK666qqrrvovc999991633333ToMA1ddddVVV1111VX/X9133323ctVVV1111X8Vgquuuuqqq/5LnT179tb1es1VV1111VVXXXXV/zfnz5/nt37rt76bq6666qqr/isRXHXVVVdd9V/qvvvuu/Xg4ICrrrrqqquuuuqqq6666qqrrvovQHDVVVddddV/qfvuu+/Wu+++m6uuuuqqq6666qr/bw4ODviHf/iH3+Gqq6666qr/SlSuuuqqq676L/UP//APv8NVV1111VVXXXXVVVddddVVV/3XoHLVVVddddV/qbNnz97KVVddddVVV1111f9D+/v7/MM//MNvc9VVV1111X8lKlddddVVV/2Xuu+++27lqquuuuqqq6666v+hYRi47777buWqq6666qr/SgRXXXXVVVf9l/uHf/iH397f3+eqq6666qqrrrrq/4uDgwP+4R/+4be56qqrrrrqvxqVq6666qqrrrrqqquuuuqqq676T7Zer7nvvvtu5aqrrrrqqv9qBFddddVVV/2X+/u///vffvKTn8xVV1111VVXXXXV/xfDMHDffffdylVXXXXVVf/VqFx11VVXXfVf7h/+4R9+h6uuuuqqq6666qr/R4Zh4OzZs8/gqquuuuqq/2pUrrrqqquu+i939uzZW7nqqquuuuqqq676f2R/f59/+Id/+G2uuuqqq676r0blqquuuuqqq6666qqrrrrqqqv+kw3DwH333XcrV1111VVX/VcjuOqqq6666r/cfffdd+t999136/7+PlddddVVV1111VX/1w3DwFVXXXXVVf9tCK666qqrrvpvcfbs2Vu56qqrrrrqqquu+n9gf3+f3/qt3/oerrrqqquu+u9AcNVVV1111X+Lv//7v//tg4MDrrrqqquuuuqqq6666qqrrrrqPxHBVVddddVV/y3Onj37jLvvvpurrrrqqquuuuqq/+sODg74h3/4h9/mqquuuuqq/w5Urrrqqquu+m9x33333cpVV1111VVXXXXV/wP7+/ucPXv2Vq666qqrrvrvQOWqq6666qr/FmfPnr2Vq6666qqrrrrqqv8n7rvvvlu56qqrrrrqvwPBVVddddVV/y3uu+++WwGGYeCqq6666qqrrrrq/7JhGLjvvvtu5aqrrrrqqv8OBFddddVVV/23+Yd/+IffXq/XXHXVVVddddVVV/1ftb+/zz/8wz/8NlddddVVV/13oXLVVVddddV/m/vuu+/WYRi46qqrrrrqqquu+r9qGAbuu+++W7nqqquuuuq/C8FVV1111VX/be67775bn/GMZ3DVVVddddVVV131f9XBwQH33XffrVx11VVXXfXfhcpVV1111VX/bf7hH/7hd7jqqquuuuqqq676P+7s2bPP4Kqrrrrqqv8uVK666qqrrvpvc/bs2Vu56qqrrrrqqquu+j9sf3+ff/iHf/htrrrqqquu+u9C5aqrrrrqqquuuuqqq6666qqr/pMMw8B99913K1ddddVVV/13Ibjqqquuuuq/zX333XfrP/zDP/z2/v4+V1111VVXXXXVVf/XDMPAfffddytXXXXVVVf9d6Jy1VVXXXXVVVddddVVV1111VX/Cfb39/mHf/iH3+aqq6666qr/TgRXXXXVVVf9t/r7v//73z44OOCqq6666qqrrrrq/5phGLjvvvtu5aqrrrrqqv9OBFddddVVV/23+od/+Iffufvuu7nqqquuuuqqq676v2YYBs6ePfsMrrrqqquu+u9E5aqrrrrqqquuuuqqq6666qqr/hPs7+/zD//wD7/NVVddddVV/52oXHXVVVdd9d/q7Nmzt3LVVVddddVVV131f9AwDFx11VVXXfXfjuCqq6666qr/Vvfdd9+t9913363DMHDVVVddddVVV131f8199913K1ddddVVV/13Irjqqquuuuq/3dmzZ29dr9dcddVVV1111VVX/V9x/vx5fuu3fuu7ueqqq6666r8bwVVXXXXVVf/t/v7v//63Dw4OuOqqq6666qqrrrrqqquuuuqq/2AEV1111VVX/Y9w9913c9VVV1111VVXXfV/xcHBAf/wD//wO1x11VVXXfXfjcpVV1111VX/7f7hH/7hd7jqqquuuuqqq6666qqrrrrqqv94VK666qqrrvpvd/bs2Vu56qqrrrrqqquu+j9kf3+ff/iHf/htrrrqqquu+u9G5aqrrrrqqv929913361cddVVV1111VVX/R8yDAP33XffrVx11VVXXfXfjeCqq6666qr/Ef7hH/7ht/f397nqqquuuuqqq6763+7g4IB/+Id/+G2uuuqqq676n4DKVVddddVVV1111VVXXXXVVVf9B1qv19x33323ctVVV1111f8EBFddddVVV/2P8Pd///e//eQnP5mrrrrqqquuuuqq/+2GYeC+++67lauuuuqqq/4noHLVVVddddX/CP/wD//wO1x11VVXXXXVVVf9HzAMA2fPnn0GV1111VVX/U9A5aqrrrrqqv8Rzp49eytXXXXVVVddddVV/wfs7+/zD//wD7/NVVddddVV/xNQueqqq6666qqrrrrqqquuuuqq/0DDMHDffffdylVXXXXVVf8TEFx11VVXXfU/wn333Xfrfffdd+v+/j5XXXXVVVddddVV/1sNw8BVV1111VX/oxBcddVVV131P8bZs2dv5aqrrrrqqquuuup/sf39fX7rt37re7jqqquuuup/CoKrrrrqqqv+x/j7v//73z44OOCqq6666qqrrrrqqquuuuqqq/6DEFx11VVXXfU/xtmzZ59x9913c9VVV1111VVXXfW/1cHBAf/wD//w21x11VVXXfU/BZWrrrrqqqv+x7jvvvtu5aqrrrrqqquuuup/sf39fc6ePXsrV1111VVX/U9B5aqrrrrqqv8xzp49eytXXXXVVVddddVV/8vdd999t3LVVVddddX/FARXXXXVVVf9j3HffffdCjAMA1ddddVVV1111VX/Gw3DwH333XcrV1111VVX/U9BcNVVV1111f8o//AP//Db6/Waq6666qqrrrrqqv9t9vf3+Yd/+Iff5qqrrrrqqv9JqFx11VVXXfU/yn333XfrMAxcddVVV1111VVX/W8zDAP33XffrVx11VVXXfU/CcFVV1111VX/o9x33323PuMZz+Cqq6666qqrrrrqf5uDgwP+4R/+4Xe46qqrrrrqfxIqV1111VVX/Y/yD//wD7/DVVddddVVV1111VVXXXXVVVf9x6By1VVXXXXV/yhnz569lauuuuqqq6666qr/hfb39/mHf/iH3+aqq6666qr/SahcddVVV1111VVXXXXVVVddddV/gGEYuO+++27lqquuuuqq/0kIrrrqqquu+h/lvvvuu/Uf/uEffnt/f5+rrrrqqquuuuqq/y2GYeC+++67lauuuuqqq/6noXLVVVddddVVV1111VVXXXXVVf9O+/v7/MM//MNvc9VVV1111f80BFddddVVV/2P8/d///e/fXBwwFVXXXXVVVddddX/FsMwcN99993KVVddddVV/9MQXHXVVVdd9T/OP/zDP/zO3XffzVVXXXXVVVddddX/FsMwcPbs2Wdw1VVXXXXV/zRUrrrqqquuuuqqq6666qqrrrrq32l/f59/+Id/+G2uuuqqq676n4bKVVddddVV/+OcPXv2Vq666qqrrrrqqqv+FxmGgauuuuqqq/5HIrjqqquuuup/nPvuu+/W++6779ZhGLjqqquuuuqqq6763+K+++67lauuuuqqq/6nIbjqqquuuup/pLNnz966Xq+56qqrrrrqqquu+p/u/Pnz/NZv/dZ3c9VVV1111f9EBFddddVVV/2P9Pd///e/fXBwwFVXXXXVVVddddVVV1111VVX/TsQXHXVVVdd9T/W3XffzVVXXXXVVVddddX/dAcHB/zDP/zD73DVVVddddX/RFSuuuqqq676H+kf/uEffoerrrrqqquuuuqqq6666qqrrvr3oXLVVVddddX/SGfPnr2Vq6666qqrrrrqqv8F9vf3+Yd/+Iff5qqrrrrqqv+JqFx11VVXXfU/0n333XcrV1111VVXXXXVVf8LDMPAfffddytXXXXVVVf9T0Rw1VVXXXXV/1j/8A//8Nv7+/tcddVVV1111VVX/U91cHDAP/zDP/w2V1111VVX/U9F5aqrrrrqqquuuuqqq6666qqr/o3W6zX33XffrVx11VVXXfU/FcFVV1111VX/Y/393//9bz/5yU/mqquuuuqqq6666n+qYRi47777buWqq6666qr/qahcddVVV131P9Y//MM//A5XXXXVVVddddVV/4MNw8DZs2efwVVXXXXVVf9TUbnqqquuuup/rLNnz97KVVddddVVV1111f9g+/v7/MM//MNvc9VVV1111f9UVK666qqrrrrqqquuuuqqq6666t9oGAbuu+++W7nqqquuuup/KoKrrrrqqqv+x7rvvvtuve+++27d39/nqquuuuqqq6666n+aYRi46qqrrrrqfzyCq6666qqr/kc7e/bsrVx11VVXXXXVVVf9D7S/v89v/dZvfQ9XXXXVVVf9T0Zw1VVXXXXV/2h///d//9sHBwdcddVVV1111VVXXXXVVVddddW/AcFVV1111VX/o509e/YZd999N1ddddVVV1111VX/0xwcHPAP//APv81VV1111VX/k1G56qqrrrrqf7T77rvvVq666qqrrrrqqqv+B9rf3+fs2bO3ctVVV1111f9kVK666qqrrvof7ezZs7dy1VVXXXXVVVdd9T/UfffddytXXXXVVVf9T0Zw1VVXXXXV/2j33XffrQDDMHDVVVddddVVV131P8kwDNx33323ctVVV1111f9kBFddddVVV/2P9w//8A+/vV6vueqqq6666qqrrvqfYn9/n3/4h3/4ba666qqrrvqfjspVV1111VX/49133323DsPAVVddddVVV1111f8UwzBw33333cpVV1111VX/0xFcddVVV131P95999136zOe8Qyuuuqqq6666qqr/qc4ODjgH/7hH36Hq6666qqr/qejctVVV1111f94//AP//A7XHXVVVddddVVV1111VVXXXXVvx6Vq6666qqr/sc7e/bsrVx11VVXXXXVVVf9D7K/v88//MM//DZXXXXVVVf9T0flqquuuuqqq6666qqrrrrqqqv+lYZh4L777ruVq6666qqr/qcjuOqqq6666n+8++6779Z/+Id/+O39/X2uuuqqq6666qqr/rsNw8B99913K1ddddVVV/1vQOWqq6666qqrrrrqqquuuuqqq/4V9vf3+Yd/+Iff5qqrrrrqqv8NCK666qqrrvpf4e///u9/++DggKuuuuqqq6666qr/bsMwcN99993KVVddddVV/xsQXHXVVVdd9b/CP/zDP/zO3XffzVVXXXXVVVddddV/t2EYOHv27DO46qqrrrrqfwMqV1111VVXXXXVVVddddVVV131r7C/v88//MM//DZXXXXVVVf9b0Dlqquuuuqq/xXOnj17K1ddddVVV1111VX/AwzDwFVXXXXVVf9rEFx11VVXXfW/wn333Xfrfffdd+swDFx11VVXXXXVVVf9d7vvvvtu5aqrrrrqqv8NCK666qqrrvpf4+zZs7eu12uuuuqqq6666qqr/rucP3+e3/qt3/purrrqqquu+t+C4Kqrrrrqqv81/v7v//63Dw4OuOqqq6666qqrrrrqqquuuuqqFxHBVVddddVV/6vcfffdXHXVVVddddVVV/13ecYznsE//MM//A5XXXXVVVf9b0Hlqquuuuqq/zV++7d/+3vOnj37jA//8A//Lq666qqrrrrqqqv+G/zIj/zIZ//Wb/3Wd3PVVVddddX/FuhBD3oQV1111VVXXXXVVVddddVVV1111VVXXXXV/0lUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V/GPl+emO0MXBNcAAAAASUVORK5CYII=) + +```kcl +exampleSketch = startSketchOn(-XZ) + |> rectangle(corner = [0, 0], width = 10, height = 5) + +``` + +![Rendered example of rectangle 1](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAAAALQCAYAAADPfd1WAABebUlEQVR4Ae3AA6AkWZbG8f937o3IzKdyS2Oubdu2bdu2bdu2bWmMnpZKr54yMyLu+Xa3anqmhztr1a8+6EEP4qqrrrrqqquuuuqqq6666qqrrrrqqquu+j+JylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqmf5pm/6pqdz1VVXXXXVVVdd9X+YJNk2DyBJts0DSJJt8wCSZNs8gCTZNg8gSbbNA0iSbfMAkmTbPIAk2TYPIEm2zQNIkm3zAJJk2wAf8iEf8hCuuuqqq64CoHLVVVddddVln/u5n/tbr/u6r/tgrrrqqquuuuqqq676X++bvumbnv4hH/IhD+Gqq6666ioqV1111VVXPct6vWZ7e5urrrrqqquuuuqqq/73GoaBq6666qqrnoXKVVddddVVV1111VVXXXXVVVf9H7K/v88//MM//DZXXXXVVVcBEFx11VVXXXXZ3//93//2wcEBV1111VVXXXXVVVf97zYMA/fdd9+tXHXVVVddBUBw1VVXXXXVZf/wD//wO3fffTdXXXXVVVddddVVV/3vNgwDZ8+efQZXXXXVVVcBULnqqquuuuqqq6666qqrrrrqqv9D9vf3+Yd/+Iff5qqrrrrqKgAqV1111VVXXXb27Nlbueqqq6666qqrrrrqf71hGLjqqquuuupZCK666qqrrrrsvvvuu/W+++67dRgGrrrqqquuuuqqq6763+2+++67lauuuuqqqwAIrrrqqquuepazZ8/eul6vueqqq6666qqrrrrqf6fz58/zW7/1W9/NVVddddVV9yO46qqrrrrqWe67775bDw4OuOqqq6666qqrrrrqqquuuuqq/yMIrrrqqquuepb77rvv1rvvvpurrrrqqquuuuqqq/53Ojg44B/+4R9+h6uuuuqqq+5H5aqrrrrqqmf5h3/4h9/hqquuuuqqq6666qqrrrrqqqv+76By1VVXXXXVs5w9e/ZWrrrqqquuuuqqq676X2t/f59/+Id/+G2uuuqqq666H5Wrrrrqqque5b777ruVq6666qqrrrrqqqv+1xqGgfvuu+9Wrrrqqquuuh/BVVddddVVz+Ef/uEffnt/f5+rrrrqqquuuuqqq/53OTg44B/+4R9+m6uuuuqqqx6IylVXXXXVVVddddVVV1111VVX/R+wXq+57777buWqq6666qoHIrjqqquuuuo5/P3f//1vP/nJT+aqq6666qqrrrrqqv9dhmHgvvvuu5WrrrrqqqseiMpVV1111VXP4R/+4R9+h6uuuuqqq6666qqr/tcZhoGzZ88+g6uuuuqqqx6IylVXXXXVVc/h7Nmzt3LVVVddddVVV1111f86+/v7/MM//MNvc9VVV1111QNRueqqq6666qqrrrrqqquuuuqq/wOGYeC+++67lauuuuqqqx6I4Kqrrrrqqudw33333XrffffdOgwDV1111VVXXXXVVVf97zAMA1ddddVVVz1fBFddddVVVz2Ps2fP3rper7nqqquuuuqqq6666n+H/f19fuu3fut7uOqqq6666rkRXHXVVVdd9Tz+/u///rcPDg646qqrrrrqqquuuuqqq6666qr/5Qiuuuqqq656HmfPnn3G3XffzVVXXXXVVVddddVV/zscHBzwD//wD7/NVVddddVVz43KVVddddVVz+O+++67lauuuuqqq6666qqr/tdYr9ecPXv2Vq666qqrrnpuVK666qqrrnoeZ8+evZWrrrrqqquuuuqqq/7XGIaB++6771auuuqqq656bgRXXXXVVVc9j/vuu+9WgGEYuOqqq6666qqrrrrqf75hGLjvvvtu5aqrrrrqqudGcNVVV1111fP1D//wD7+9Xq+56qqrrrrqqquuuup/tv39ff7hH/7ht7nqqquuuur5oXLVVVddddXzdd999906DANXXXXVVVddddVVV/3PNgwD9913361cddVVV131/BBcddVVV131fN133323PuMZz+Cqq6666qqrrrrqqv/ZDg4OuO+++27lqquuuuqq54fKVVddddVVz9c//MM//A5XXXXVVVddddVVV/2vcPbs2Wdw1VVXXXXV80Plqquuuuqq5+vs2bO3ctVVV1111VVXXXXV/3j7+/v8wz/8w29z1VVXXXXV80Plqquuuuqqq6666qqrrrrqqqv+FxuGgfvuu+9Wrrrqqquuen4Irrrqqquuer7uu+++W//hH/7ht/f397nqqquuuuqqq6666n+mYRi47777buWqq6666qoXhMpVV1111VVXXXXVVVddddVVV/0vtb+/zz/8wz/8NlddddVVV70gBFddddVVV71Af//3f//bBwcHXHXVVVddddVVV131P9MwDNx33323ctVVV1111QtCcNVVV1111Qv0D//wD79z9913c9VVV1111VVXXXXV/0zDMHD27NlncNVVV1111QtC5aqrrrrqqquuuuqqq6666qqr/pfa39/nH/7hH36bq6666qqrXhAqV1111VVXvUBnz569lauuuuqqq6666qqr/scahoGrrrrqqqteKIKrrrrqqqteoPvuu+/W++6779ZhGLjqqquuuuqqq6666n+m++6771auuuqqq656QQiuuuqqq656oc6ePXvrer3mqquuuuqqq6666qr/Wc6fP89v/dZvfTdXXXXVVVe9MARXXXXVVVe9UPfdd9+tBwcHXHXVVVddddVVV1111VVXXXXV/0IEV1111VVXvVD33XffrXfffTdXXXXVVVddddVVV/3PcnBwwD/8wz/8DlddddVVV70wVK666qqrrnqh/uEf/uF3uOqqq6666qqrrrrqqquuuuqq/52oXHXVVVdd9UKdPXv2Vq666qqrrrrqqquu+h9nf3+ff/iHf/htrrrqqquuemGoXHXVVVdd9ULdd999t3LVVVddddVVV1111f84wzBw33333cpVV1111VUvDMFVV1111VX/on/4h3/47f39fa666qqrrrrqqquu+p/h4OCAf/iHf/htrrrqqquu+pdQueqqq6666qqrrrrqqquuuuqq/2XW6zX33XffrVx11VVXXfUvIbjqqquuuupf9Pd///e//eQnP5mrrrrqqquuuuqqq/5nGIaB++6771auuuqqq676l1C56qqrrrrqX/QP//APv8NVV1111VVXXXXVVf9jDMPA2bNnn8FVV1111VX/EipXXXXVVVf9i86ePXsrV1111VVXXXXVVVf9j7G/v88//MM//DZXXXXVVVf9S6hcddVVV1111VVXXXXVVVddddX/MsMwcN99993KVVddddVV/xKCq6666qqr/kX33Xffrffdd9+twzBw1VVXXXXVVVddddV/r2EYuOqqq6666kVGcNVVV1111Yvk7Nmzt67Xa6666qqrrrrqqquu+u+1v7/Pb/3Wb30PV1111VVXvSgIrrrqqquuepH8/d///W8fHBxw1VVXXXXVVVddddVVV1111VX/ixBcddVVV131Ijl79uwz7r77bq666qqrrrrqqquu+u91cHDAP/zDP/w2V1111VVXvSioXHXVVVdd9SK57777buWqq6666qqrrrrqqv926/Was2fP3spVV1111VUvCipXXXXVVVe9SM6ePXsrV1111VVXXXXVVVf9txuGgfvuu+9WrrrqqquuelEQXHXVVVdd9SK57777bgUYhoGrrrrqqquuuuqqq/77DMPAfffddytXXXXVVVe9KAiuuuqqq656kf3DP/zDb6/Xa6666qqrrrrqqquu+u+xv7/PP/zDP/w2V1111VVXvaioXHXVVVdd9SK77777bh2Ggauuuuqqq6666qqr/nsMw8B99913K1ddddVVV72oCK666qqrrnqR3Xfffbc+4xnP4Kqrrrrqqquuuuqq/x4HBwfcd999t3LVVVddddWLispVV1111VUvsn/4h3/4Ha666qqrrrrqqquu+m919uzZZ3DVVVddddWLispVV1111VUvsrNnz97KVVddddVVV1111VX/bfb39/mHf/iH3+aqq6666qoXFZWrrrrqqquuuuqqq6666qqrrvpfYhgG7rvvvlu56qqrrrrqRUVw1VVXXXXVi+y+++679R/+4R9+e39/n6uuuuqqq6666qqr/msNw8B99913K1ddddVVV/1rULnqqquuuuqqq6666qqrrrrqqv8F9vf3+Yd/+Iff5qqrrrrqqn8Ngquuuuqqq/5V/v7v//63Dw4OuOqqq6666qqrrrrqv9YwDNx33323ctVVV1111b8GwVVXXXXVVf8q//AP//A7d999N1ddddVVV1111VVX/dcahoGzZ88+g6uuuuqqq/41qFx11VVXXXXVVVddddVVV1111f8C+/v7/MM//MNvc9VVV1111b8Glauuuuqqq/5Vzp49eytXXXXVVVddddVVV/2XG4aBq6666qqr/tUIrrrqqquu+le57777br3vvvtuHYaBq6666qqrrrrqqqv+a9133323ctVVV1111b8GwVVXXXXVVf9qZ8+evXW9XnPVVVddddVVV1111X+N8+fP81u/9VvfzVVXXXXVVf9aBFddddVVV/2r3XfffbceHBxw1VVXXXXVVVddddVVV1111VX/wxFcddVVV131r3bffffdevfdd3PVVVddddVVV1111X+Ng4MD/uEf/uF3uOqqq6666l+LylVXXXXVVf9q//AP//A7XHXVVVddddVVV1111VVXXXXV/3xUrrrqqquu+lc7e/bsrVx11VVXXXXVVVdd9V9mf3+ff/iHf/htrrrqqquu+teictVVV1111b/afffddytXXXXVVVddddVVV/2XGYaB++6771auuuqqq6761yK46qqrrrrq3+Qf/uEffnt/f5+rrrrqqquuuuqqq/5zHRwc8A//8A+/zVVXXXXVVf8WVK666qqrrrrqqquuuuqqq6666n+w9XrNfffddytXXXXVVVf9WxBcddVVV131b/L3f//3v/3kJz+Zq6666qqrrrrqqqv+cw3DwH333XcrV1111VVX/VtQueqqq6666t/kH/7hH36Hq6666qqrrrrqqqv+0w3DwNmzZ5/BVVddddVV/xZUrrrqqquu+jc5e/bsrVx11VVXXXXVVVdd9Z9uf3+ff/iHf/htrrrqqquu+regctVVV1111VVXXXXVVVddddVV/4MNw8B99913K1ddddVVV/1bEFx11VVXXfVvct99991633333ToMA1ddddVVV1111VVX/ecYhoGrrrrqqqv+XQiuuuqqq676Nzt79uyt6/Waq6666qqrrrrqqqv+c+zv7/Nbv/Vb38NVV1111VX/VgRXXXXVVVf9m/393//9bx8cHHDVVVddddVVV1111VVXXXXVVf9DEVx11VVXXfVvdvbs2WfcfffdXHXVVVddddVVV131n+Pg4IB/+Id/+G2uuuqqq676t6Jy1VVXXXXVv9l99913K1ddddVVV1111VVX/adZr9ecPXv2Vq666qqrrvq3onLVVVddddW/2dmzZ2/lqquuuuqqq6666qr/NMMwcN99993KVVddddVV/1YEV1111VVX/Zvdd999twIMw8BVV1111VVXXXXVVf/xhmHgvvvuu5Wrrrrqqqv+rQiuuuqqq676d/mHf/iH316v11x11VVXXXXVVVdd9R9rf3+ff/iHf/htrrrqqquu+vegctVVV1111b/Lfffdd+swDFx11VVXXXXVVVdd9R9rGAbuu+++W7nqqquuuurfg+Cqq6666qp/l/vuu+/WZzzjGVx11VVXXXXVVVdd9R/r4OCA++6771auuuqqq67696By1VVXXXXVv8s//MM//A5XXXXVVVddddVVV/2nOHv27DO46qqrrrrq34PKVVddddVV/y5nz569lauuuuqqq6666qqr/sPt7+/zD//wD7/NVVddddVV/x5Urrrqqquuuuqqq6666qqrrrrqf6BhGLjvvvtu5aqrrrrqqn8Pgquuuuqqq/5d7rvvvlv/4R/+4bf39/e56qqrrrrqqquuuuo/xjAM3Hfffbdy1VVXXXXVvxeVq6666qqrrrrqqquuuuqqq676H2Z/f59/+Id/+G2uuuqqq6769yK46qqrrrrq3+3v//7vf/vg4ICrrrrqqquuuuqqq/5jDMPAfffddytXXXXVVVf9exFcddVVV1317/YP//APv3P33Xdz1VVXXXXVVVddddV/jGEYOHv27DO46qqrrrrq34vKVVddddVVV1111VVXXXXVVVf9D7O/v88//MM//DZXXXXVVVf9e1G56qqrrrrq3+3s2bO3ctVVV1111VVXXXXVf5hhGLjqqquuuuo/BMFVV1111VX/bvfdd9+t9913363DMHDVVVddddVVV1111X+M++6771auuuqqq6769yK46qqrrrrqP8TZs2dvXa/XXHXVVVddddVVV13173P+/Hl+67d+67u56qqrrrrqPwLBVVddddVV/yHuu+++Ww8ODrjqqquuuuqqq6666qqrrrrqqv9BCK666qqrrvoPcd9999169913c9VVV1111VVXXXXVv8/BwQH/8A//8DtcddVVV131H4HKVVddddVV/yH+4R/+4Xe46qqrrrrqqquuuuqqq6666qr/WahcddVVV131H+Ls2bO3ctVVV1111VVXXXXVv9v+/j7/8A//8NtcddVVV131H4HKVVddddVV/yHuu+++W7nqqquuuuqqq6666t9tGAbuu+++W7nqqquuuuo/AsFVV1111VX/Yf7hH/7ht/f397nqqquuuuqqq6666t/m4OCAf/iHf/htrrrqqquu+o9C5aqrrrrqqquuuuqqq6666qqr/odYr9fcd999t3LVVVddddV/FIKrrrrqqqv+w/z93//9bz/5yU/mqquuuuqqq6666qp/m2EYuO+++27lqquuuuqq/yhUrrrqqquu+g/zD//wD7/DVVddddVVV1111VX/ZsMwcPbs2Wdw1VVXXXXVfxQqV1111VVX/Yc5e/bsrVx11VVXXXXVVVdd9W+2v7/PP/zDP/w2V1111VVX/UehctVVV1111VVXXXXVVVddddVV/0MMw8B99913K1ddddVVV/1HIbjqqquuuuo/zH333Xfrfffdd+swDFx11VVXXXXVVVdd9a8zDANXXXXVVVf9hyO46qqrrrrqP9TZs2dvXa/XXHXVVVddddVVV131r7O/v89v/dZvfQ9XXXXVVVf9RyK46qqrrrrqP9Tf//3f//bBwQFXXXXVVVddddVVV1111VVXXfU/AMFVV1111VX/oc6ePfuMu+++m6uuuuqqq6666qqr/nUODg74h3/4h9/mqquuuuqq/0hUrrrqqquu+g9133333cpVV1111VVXXXXVVf9q6/Was2fP3spVV1111VX/kahcddVVV131H+rs2bO3ctVVV1111VVXXXXVv9owDNx33323ctVVV1111X8kgquuuuqqq/5D3XfffbcCDMPAVVddddVVV1111VUvumEYuO+++27lqquuuuqq/0gEV1111VVX/Yf7h3/4h99er9dcddVVV1111VVXXfWi2d/f5x/+4R9+m6uuuuqqq/6jUbnqqquuuuo/3H333XfrMAxcddVVV1111VVXXfWiGYaB++6771auuuqqq676j0Zw1VVXXXXVf7j77rvv1mc84xlcddVVV1111VVXXfWiOTg44L777ruVq6666qqr/qNRueqqq6666j/cP/zDP/wOV1111VVXXXXVVVf9q5w9e/YZXHXVVVdd9R+NylVXXXXVVf/hzp49eytXXXXVVVddddVVV73I9vf3+Yd/+Iff5qqrrrrqqv9oVK666qqrrrrqqquuuuqqq6666r/ZMAzcd999t3LVVVddddV/NIKrrrrqqqv+w9133323/sM//MNv7+/vc9VVV1111VVXXXXVCzcMA/fdd9+tXHXVVVdd9Z+BylVXXXXVVVddddVVV1111VVX/Tfa39/nH/7hH36bq6666qqr/jMQXHXVVVdd9Z/i7//+73/74OCAq6666qqrrrrqqqteuGEYuO+++27lqquuuuqq/wwEV1111VVX/af4h3/4h9+5++67ueqqq6666qqrrrrqhRuGgbNnzz6Dq6666qqr/jNQueqqq6666qqrrrrqqquuuuqq/0b7+/v8wz/8w29z1VVXXXXVfwYqV1111VVX/ac4e/bsrVx11VVXXXXVVVdd9S8ahoGrrrrqqqv+0xBcddVVV131n+K+++679b777rt1GAauuuqqq6666qqrrnrh7rvvvlu56qqrrrrqPwPBVVddddVV/2nOnj1763q95qqrrrrqqquuuuqq5+/8+fP81m/91ndz1VVXXXXVfxaCq6666qqr/tPcd999tx4cHHDVVVddddVVV1111VVXXXXVVf9NCK666qqrrvpPc99999169913c9VVV1111VVXXXXV83dwcMA//MM//A5XXXXVVVf9Z6Fy1VVXXXXVf5p/+Id/+B2uuuqqq6666qqrrrrqqquuuuq/D5Wrrrrqqqv+05w9e/ZWrrrqqquuuuqqq656gfb39/mHf/iH3+aqq6666qr/LFSuuuqqq676T3PffffdylVXXXXVVVddddVVL9AwDNx33323ctVVV1111X8Wgquuuuqqq/5T/cM//MNv7+/vc9VVV1111VVXXXXVczo4OOAf/uEffpurrrrqqqv+M1G56qqrrrrqqquuuuqqq6666qr/Buv1mvvuu+9Wrrrqqquu+s9EcNVVV1111X+qv//7v//tJz/5yVx11VVXXXXVVVdd9ZyGYeC+++67lauuuuqqq/4zUbnqqquuuuo/1T/8wz/8DlddddVVV1111VVXPY9hGDh79uwzuOqqq6666j8Tlauuuuqqq/5TnT179lauuuqqq6666qqrrnoe+/v7/MM//MNvc9VVV1111X8mKlddddVVV1111VVXXXXVVVdd9d9gGAbuu+++W7nqqquuuuo/E8FVV1111VX/qe67775b77vvvlv39/e56qqrrrrqqquuuuqKYRi46qqrrrrqvwTBVVddddVV/+nOnj17K1ddddVVV1111VVXPcv+/j6/9Vu/9T1cddVVV131n43gqquuuuqq/3R///d//9sHBwdcddVVV1111VVXXXXVVVddddV/MYKrrrrqqqv+0509e/YZd999N1ddddVVV1111VVXXXFwcMA//MM//DZXXXXVVVf9Z6Ny1VVXXXXVf7r77rvvVq666qqrrrrqqquuepb9/X3Onj17K1ddddVVV/1no3LVVVddddV/urNnz97KVVddddVVV1111VXP4b777ruVq6666qqr/rMRXHXVVVdd9Z/uvvvuuxVgGAauuuqqq6666qqrroJhGLjvvvtu5aqrrrrqqv9sBFddddVVV/2X+Id/+IffXq/XXHXVVVddddVVV/1/t7+/zz/8wz/8NlddddVVV/1XoHLVVVddddV/ifvuu+/WYRi46qqrrrrqqquu+v9uGAbuu+++W7nqqquuuuq/AsFVV1111VX/Je67775bn/GMZ3DVVVddddVVV131/93BwQH33XffrVx11VVXXfVfgcpVV1111VX/Jf7hH/7hd7jqqquuuuqqq6666rKzZ88+g6uuuuqqq/4rULnqqquuuuq/xNmzZ2/lqquuuuqqq6666ir29/f5h3/4h9/mqquuuuqq/wpUrrrqqquuuuqqq6666qqrrrrqv9AwDNx33323ctVVV1111X8Fgquuuuqqq/5L3Hfffbf+wz/8w2/v7+9z1VVXXXXVVVdd9f/VMAzcd999t3LVVVddddV/FSpXXXXVVVddddVVV1111VVXXfVfZH9/n3/4h3/4ba666qqrrvqvQnDVVVddddV/mb//+7//7YODA6666qqrrrrqqqv+vxqGgfvuu+9Wrrrqqquu+q9CcNVVV1111X+Zf/iHf/idu+++m6uuuuqqq6666qr/r4Zh4OzZs8/gqquuuuqq/ypUrrrqqquuuuqqq6666qqrrrrqv8j+/j7/8A//8NtcddVVV131X4XKVVddddVV/2XOnj17K1ddddVVV1111VX/jw3DwFVXXXXVVf+lCK666qqrrvovc999991633333ToMA1ddddVVV1111VX/X9133323ctVVV1111X8Vgquuuuqqq/5LnT179tb1es1VV1111VVXXXXV/zfnz5/nt37rt76bq6666qqr/isRXHXVVVdd9V/qvvvuu/Xg4ICrrrrqqquuuuqqq6666qqrrvovQHDVVVddddV/qfvuu+/Wu+++m6uuuuqqq6666qr/bw4ODviHf/iH3+Gqq6666qr/SlSuuuqqq676L/UP//APv8NVV1111VVXXXXVVVddddVVV/3XoHLVVVddddV/qbNnz97KVVddddVVV1111f9D+/v7/MM//MNvc9VVV1111X8lKlddddVVV/2Xuu+++27lqquuuuqqq6666v+hYRi47777buWqq6666qr/SgRXXXXVVVf9l/uHf/iH397f3+eqq6666qqrrrrq/4uDgwP+4R/+4be56qqrrrrqvxqVq6666qqrrrrqqquuuuqqq676T7Zer7nvvvtu5aqrrrrqqv9qBFddddVVV/2X+/u///vffvKTn8xVV1111VVXXXXV/xfDMHDffffdylVXXXXVVf/VqFx11VVXXfVf7h/+4R9+h6uuuuqqq6666qr/R4Zh4OzZs8/gqquuuuqq/2pUrrrqqquu+i939uzZW7nqqquuuuqqq676f2R/f59/+Id/+G2uuuqqq676r0blqquuuuqqq6666qqrrrrqqqv+kw3DwH333XcrV1111VVX/VcjuOqqq6666r/cfffdd+t999136/7+PlddddVVV1111VX/1w3DwFVXXXXVVf9tCK666qqrrvpvcfbs2Vu56qqrrrrqqquu+n9gf3+f3/qt3/oerrrqqquu+u9AcNVVV1111X+Lv//7v//tg4MDrrrqqquuuuqqq6666qqrrrrqPxHBVVddddVV/y3Onj37jLvvvpurrrrqqquuuuqq/+sODg74h3/4h9/mqquuuuqq/w5Urrrqqquu+m9x33333cpVV1111VVXXXXV/wP7+/ucPXv2Vq666qqrrvrvQOWqq6666qr/FmfPnr2Vq6666qqrrrrqqv8n7rvvvlu56qqrrrrqvwPBVVddddVV/y3uu+++WwGGYeCqq6666qqrrrrq/7JhGLjvvvtu5aqrrrrqqv8OBFddddVVV/23+Yd/+IffXq/XXHXVVVddddVVV/1ftb+/zz/8wz/8NlddddVVV/13oXLVVVddddV/m/vuu+/WYRi46qqrrrrqqquu+r9qGAbuu+++W7nqqquuuuq/C8FVV1111VX/be67775bn/GMZ3DVVVddddVVV131f9XBwQH33XffrVx11VVXXfXfhcpVV1111VX/bf7hH/7hd7jqqquuuuqqq676P+7s2bPP4Kqrrrrqqv8uVK666qqrrvpvc/bs2Vu56qqrrrrqqquu+j9sf3+ff/iHf/htrrrqqquu+u9C5aqrrrrqqquuuuqqq6666qqr/pMMw8B99913K1ddddVVV/13Ibjqqquuuuq/zX333XfrP/zDP/z2/v4+V1111VVXXXXVVf/XDMPAfffddytXXXXVVVf9d6Jy1VVXXXXVVVddddVVV1111VX/Cfb39/mHf/iH3+aqq6666qr/TgRXXXXVVVf9t/r7v//73z44OOCqq6666qqrrrrq/5phGLjvvvtu5aqrrrrqqv9OBFddddVVV/23+od/+Iffufvuu7nqqquuuuqqq676v2YYBs6ePfsMrrrqqquu+u9E5aqrrrrqqquuuuqqq6666qqr/hPs7+/zD//wD7/NVVddddVV/52oXHXVVVdd9d/q7Nmzt3LVVVddddVVV131f9AwDFx11VVXXfXfjuCqq6666qr/Vvfdd9+t9913363DMHDVVVddddVVV131f8199913K1ddddVVV/13Irjqqquuuuq/3dmzZ29dr9dcddVVV1111VVX/V9x/vx5fuu3fuu7ueqqq6666r8bwVVXXXXVVf/t/v7v//63Dw4OuOqqq6666qqrrrrqqquuuuqq/2AEV1111VVX/Y9w9913c9VVV1111VVXXfV/xcHBAf/wD//wO1x11VVXXfXfjcpVV1111VX/7f7hH/7hd7jqqquuuuqqq6666qqrrrrqqv94VK666qqrrvpvd/bs2Vu56qqrrrrqqquu+j9kf3+ff/iHf/htrrrqqquu+u9G5aqrrrrqqv929913361cddVVV1111VVX/R8yDAP33XffrVx11VVXXfXfjeCqq6666qr/Ef7hH/7ht/f397nqqquuuuqqq6763+7g4IB/+Id/+G2uuuqqq676n4DKVVddddVVV1111VVXXXXVVVf9B1qv19x33323ctVVV1111f8EBFddddVVV/2P8Pd///e//eQnP5mrrrrqqquuuuqq/+2GYeC+++67lauuuuqqq/4noHLVVVddddX/CP/wD//wO1x11VVXXXXVVVf9HzAMA2fPnn0GV1111VVX/U9A5aqrrrrqqv8Rzp49eytXXXXVVVddddVV/wfs7+/zD//wD7/NVVddddVV/xNQueqqq6666qqrrrrqqquuuuqq/0DDMHDffffdylVXXXXVVf8TEFx11VVXXfU/wn333Xfrfffdd+v+/j5XXXXVVVddddVV/1sNw8BVV1111VX/oxBcddVVV131P8bZs2dv5aqrrrrqqquuuup/sf39fX7rt37re7jqqquuuup/CoKrrrrqqqv+x/j7v//73z44OOCqq6666qqrrrrqqquuuuqqq/6DEFx11VVXXfU/xtmzZ59x9913c9VVV1111VVXXfW/1cHBAf/wD//w21x11VVXXfU/BZWrrrrqqqv+x7jvvvtu5aqrrrrqqquuuup/sf39fc6ePXsrV1111VVX/U9B5aqrrrrqqv8xzp49eytXXXXVVVddddVV/8vdd999t3LVVVddddX/FARXXXXVVVf9j3HffffdCjAMA1ddddVVV1111VX/Gw3DwH333XcrV1111VVX/U9BcNVVV1111f8o//AP//Db6/Waq6666qqrrrrqqv9t9vf3+Yd/+Iff5qqrrrrqqv9JqFx11VVXXfU/yn333XfrMAxcddVVV1111VVX/W8zDAP33XffrVx11VVXXfU/CcFVV1111VX/o9x33323PuMZz+Cqq6666qqrrrrqf5uDgwP+4R/+4Xe46qqrrrrqfxIqV1111VVX/Y/yD//wD7/DVVddddVVV1111VVXXXXVVVf9x6By1VVXXXXV/yhnz569lauuuuqqq6666qr/hfb39/mHf/iH3+aqq6666qr/SahcddVVV1111VVXXXXVVVddddV/gGEYuO+++27lqquuuuqq/0kIrrrqqquu+h/lvvvuu/Uf/uEffnt/f5+rrrrqqquuuuqq/y2GYeC+++67lauuuuqqq/6noXLVVVddddVVV1111VVXXXXVVf9O+/v7/MM//MNvc9VVV1111f80BFddddVVV/2P8/d///e/fXBwwFVXXXXVVVddddX/FsMwcN99993KVVddddVV/9MQXHXVVVdd9T/OP/zDP/zO3XffzVVXXXXVVVddddX/FsMwcPbs2Wdw1VVXXXXV/zRUrrrqqquuuuqqq6666qqrrrrq32l/f59/+Id/+G2uuuqqq676n4bKVVddddVV/+OcPXv2Vq666qqrrrrqqqv+FxmGgauuuuqqq/5HIrjqqquuuup/nPvuu+/W++6779ZhGLjqqquuuuqqq6763+K+++67lauuuuqqq/6nIbjqqquuuup/pLNnz966Xq+56qqrrrrqqquu+p/u/Pnz/NZv/dZ3c9VVV1111f9EBFddddVVV/2P9Pd///e/fXBwwFVXXXXVVVddddVVV1111VVX/TsQXHXVVVdd9T/W3XffzVVXXXXVVVddddX/dAcHB/zDP/zD73DVVVddddX/RFSuuuqqq676H+kf/uEffoerrrrqqquuuuqqq6666qqrrvr3oXLVVVddddX/SGfPnr2Vq6666qqrrrrqqv8F9vf3+Yd/+Iff5qqrrrrqqv+JqFx11VVXXfU/0n333XcrV1111VVXXXXVVf8LDMPAfffddytXXXXVVVf9T0Rw1VVXXXXV/1j/8A//8Nv7+/tcddVVV1111VVX/U91cHDAP/zDP/w2V1111VVX/U9F5aqrrrrqqquuuuqqq6666qqr/o3W6zX33XffrVx11VVXXfU/FcFVV1111VX/Y/393//9bz/5yU/mqquuuuqqq6666n+qYRi47777buWqq6666qr/qahcddVVV131P9Y//MM//A5XXXXVVVddddVV/4MNw8DZs2efwVVXXXXVVf9TUbnqqquuuup/rLNnz97KVVddddVVV1111f9g+/v7/MM//MNvc9VVV1111f9UVK666qqrrrrqqquuuuqqq6666t9oGAbuu+++W7nqqquuuup/KoKrrrrqqqv+x7rvvvtuve+++27d39/nqquuuuqqq6666n+aYRi46qqrrrrqfzyCq6666qqr/kc7e/bsrVx11VVXXXXVVVf9D7S/v89v/dZvfQ9XXXXVVVf9T0Zw1VVXXXXV/2h///d//9sHBwdcddVVV1111VVXXXXVVVddddW/AcFVV1111VX/o509e/YZd999N1ddddVVV1111VX/0xwcHPAP//APv81VV1111VX/k1G56qqrrrrqf7T77rvvVq666qqrrrrqqqv+B9rf3+fs2bO3ctVVV1111f9kVK666qqrrvof7ezZs7dy1VVXXXXVVVdd9T/UfffddytXXXXVVVf9T0Zw1VVXXXXV/2j33XffrQDDMHDVVVddddVVV131P8kwDNx33323ctVVV1111f9kBFddddVVV/2P9w//8A+/vV6vueqqq6666qqrrvqfYn9/n3/4h3/4ba666qqrrvqfjspVV1111VX/49133323DsPAVVddddVVV1111f8UwzBw33333cpVV1111VX/0xFcddVVV131P95999136zOe8Qyuuuqqq6666qqr/qc4ODjgH/7hH36Hq6666qqr/qejctVVV1111f94//AP//A7XHXVVVddddVVV1111VVXXXXVvx6Vq6666qqr/sc7e/bsrVx11VVXXXXVVVf9D7K/v88//MM//DZXXXXVVVf9T0flqquuuuqqq6666qqrrrrqqqv+lYZh4L777ruVq6666qqr/qcjuOqqq6666n+8++6779Z/+Id/+O39/X2uuuqqq6666qqr/rsNw8B99913K1ddddVVV/1vQOWqq6666qqrrrrqqquuuuqqq/4V9vf3+Yd/+Iff5qqrrrrqqv8NCK666qqrrvpf4e///u9/++DggKuuuuqqq6666qr/bsMwcN99993KVVddddVV/xsQXHXVVVdd9b/CP/zDP/zO3XffzVVXXXXVVVddddV/t2EYOHv27DO46qqrrrrqfwMqV1111VVXXXXVVVddddVVV131r7C/v88//MM//DZXXXXVVVf9b0Dlqquuuuqq/xXOnj17K1ddddVVV1111VX/AwzDwFVXXXXVVf9rEFx11VVXXfW/wn333Xfrfffdd+swDFx11VVXXXXVVVf9d7vvvvtu5aqrrrrqqv8NCK666qqrrvpf4+zZs7eu12uuuuqqq6666qqr/rucP3+e3/qt3/purrrqqquu+t+C4Kqrrrrqqv81/v7v//63Dw4OuOqqq6666qqrrrrqqquuuuqqFxHBVVddddVV/6vcfffdXHXVVVddddVVV/13ecYznsE//MM//A5XXXXVVVf9b0Hlqquuuuqq/zV++7d/+3vOnj37jA//8A//Lq666qqrrrrqqqv+G/zIj/zIZ//Wb/3Wd3PVVVddddX/FuhBD3oQV1111VVXXXXVVVddddVVV1111VVXXXXV/0lUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V/GPl+emO0MXBNcAAAAASUVORK5CYII=) + + diff --git a/docs/kcl-std/index.md b/docs/kcl-std/index.md index 4a31d1d64..7a0c8f7e5 100644 --- a/docs/kcl-std/index.md +++ b/docs/kcl-std/index.md @@ -72,6 +72,7 @@ layout: manual * [`profileStart`](/docs/kcl-std/functions/std-sketch-profileStart) * [`profileStartX`](/docs/kcl-std/functions/std-sketch-profileStartX) * [`profileStartY`](/docs/kcl-std/functions/std-sketch-profileStartY) + * [`rectangle`](/docs/kcl-std/functions/std-sketch-rectangle) * [`revolve`](/docs/kcl-std/functions/std-sketch-revolve) * [`segAng`](/docs/kcl-std/functions/std-sketch-segAng) * [`segEnd`](/docs/kcl-std/functions/std-sketch-segEnd) diff --git a/docs/kcl-std/modules/std-sketch.md b/docs/kcl-std/modules/std-sketch.md index a96536547..d9cf7079e 100644 --- a/docs/kcl-std/modules/std-sketch.md +++ b/docs/kcl-std/modules/std-sketch.md @@ -37,6 +37,7 @@ This module contains functions for creating and manipulating sketches, and makin * [`profileStart`](/docs/kcl-std/functions/std-sketch-profileStart) * [`profileStartX`](/docs/kcl-std/functions/std-sketch-profileStartX) * [`profileStartY`](/docs/kcl-std/functions/std-sketch-profileStartY) +* [`rectangle`](/docs/kcl-std/functions/std-sketch-rectangle) * [`revolve`](/docs/kcl-std/functions/std-sketch-revolve) * [`segAng`](/docs/kcl-std/functions/std-sketch-segAng) * [`segEnd`](/docs/kcl-std/functions/std-sketch-segEnd) diff --git a/rust/kcl-derive-docs/src/example_tests.rs b/rust/kcl-derive-docs/src/example_tests.rs index 27ba9fcf9..94a64f9f6 100644 --- a/rust/kcl-derive-docs/src/example_tests.rs +++ b/rust/kcl-derive-docs/src/example_tests.rs @@ -100,6 +100,8 @@ pub const TEST_NAMES: &[&str] = &[ "std-sketch-planeOf-0", "std-sketch-circle-0", "std-sketch-circle-1", + "std-sketch-rectangle-0", + "std-sketch-rectangle-1", "std-sketch-patternTransform2d-0", "std-sketch-revolve-0", "std-sketch-revolve-1", diff --git a/rust/kcl-lib/src/execution/geometry.rs b/rust/kcl-lib/src/execution/geometry.rs index 4745c6e94..658da8bf2 100644 --- a/rust/kcl-lib/src/execution/geometry.rs +++ b/rust/kcl-lib/src/execution/geometry.rs @@ -1031,7 +1031,7 @@ pub struct GeoMeta { #[ts(export)] #[serde(tag = "type")] pub enum Path { - /// A path that goes to a point. + /// A straight line which ends at the given point. ToPoint { #[serde(flatten)] base: BasePath, diff --git a/rust/kcl-lib/src/simulation_tests.rs b/rust/kcl-lib/src/simulation_tests.rs index 40a507ba0..d49079e1b 100644 --- a/rust/kcl-lib/src/simulation_tests.rs +++ b/rust/kcl-lib/src/simulation_tests.rs @@ -3632,6 +3632,48 @@ mod non_english_identifiers { super::execute(TEST_NAME, true).await } } +mod rect { + const TEST_NAME: &str = "rect"; + + /// Test parsing KCL. + #[test] + fn parse() { + super::parse(TEST_NAME) + } + + /// Test that parsing and unparsing KCL produces the original KCL input. + #[tokio::test(flavor = "multi_thread")] + async fn unparse() { + super::unparse(TEST_NAME).await + } + + /// Test that KCL is executed correctly. + #[tokio::test(flavor = "multi_thread")] + async fn kcl_test_execute() { + super::execute(TEST_NAME, true).await + } +} +mod rect_helper { + const TEST_NAME: &str = "rect_helper"; + + /// Test parsing KCL. + #[test] + fn parse() { + super::parse(TEST_NAME) + } + + /// Test that parsing and unparsing KCL produces the original KCL input. + #[tokio::test(flavor = "multi_thread")] + async fn unparse() { + super::unparse(TEST_NAME).await + } + + /// Test that KCL is executed correctly. + #[tokio::test(flavor = "multi_thread")] + async fn kcl_test_execute() { + super::execute(TEST_NAME, true).await + } +} mod plane_of { const TEST_NAME: &str = "plane_of"; diff --git a/rust/kcl-lib/src/std/mod.rs b/rust/kcl-lib/src/std/mod.rs index 152cd4be1..ab34ce0f9 100644 --- a/rust/kcl-lib/src/std/mod.rs +++ b/rust/kcl-lib/src/std/mod.rs @@ -256,6 +256,10 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp |e, a| Box::pin(crate::std::shapes::circle(e, a)), StdFnProps::default("std::sketch::circle"), ), + ("sketch", "rectangle") => ( + |e, a| Box::pin(crate::std::shapes::rectangle(e, a)), + StdFnProps::default("std::sketch::rectangle"), + ), ("sketch", "planeOf") => ( |e, a| Box::pin(crate::std::planes::plane_of(e, a)), StdFnProps::default("std::sketch::planeOf"), diff --git a/rust/kcl-lib/src/std/shapes.rs b/rust/kcl-lib/src/std/shapes.rs index 5518f228b..7c3379c4d 100644 --- a/rust/kcl-lib/src/std/shapes.rs +++ b/rust/kcl-lib/src/std/shapes.rs @@ -38,6 +38,119 @@ pub enum SketchOrSurface { Sketch(Box), } +/// Sketch a rectangle. +pub async fn rectangle(exec_state: &mut ExecState, args: Args) -> Result { + let sketch_or_surface = + args.get_unlabeled_kw_arg("sketchOrSurface", &RuntimeType::sketch_or_surface(), exec_state)?; + let center = args.get_kw_arg_opt("center", &RuntimeType::point2d(), exec_state)?; + let corner = args.get_kw_arg_opt("corner", &RuntimeType::point2d(), exec_state)?; + let width: TyF64 = args.get_kw_arg("width", &RuntimeType::length(), exec_state)?; + let height: TyF64 = args.get_kw_arg("height", &RuntimeType::length(), exec_state)?; + + inner_rectangle(sketch_or_surface, center, corner, width, height, exec_state, args) + .await + .map(Box::new) + .map(|value| KclValue::Sketch { value }) +} + +async fn inner_rectangle( + sketch_or_surface: SketchOrSurface, + center: Option<[TyF64; 2]>, + corner: Option<[TyF64; 2]>, + width: TyF64, + height: TyF64, + exec_state: &mut ExecState, + args: Args, +) -> Result { + let sketch_surface = match sketch_or_surface { + SketchOrSurface::SketchSurface(surface) => surface, + SketchOrSurface::Sketch(s) => s.on, + }; + + // Find the corner in the negative quadrant + let (ty, corner) = match (center, corner) { + (Some(center), None) => ( + center[0].ty, + [center[0].n - width.n / 2.0, center[1].n - height.n / 2.0], + ), + (None, Some(corner)) => (corner[0].ty, [corner[0].n, corner[1].n]), + (None, None) => { + return Err(KclError::new_semantic(KclErrorDetails::new( + "You must supply either `corner` or `center` arguments, but not both".to_string(), + vec![args.source_range], + ))); + } + (Some(_), Some(_)) => { + return Err(KclError::new_semantic(KclErrorDetails::new( + "You must supply either `corner` or `center` arguments, but not both".to_string(), + vec![args.source_range], + ))); + } + }; + let units = ty.expect_length(); + let corner_t = [TyF64::new(corner[0], ty), TyF64::new(corner[1], ty)]; + + // Start the sketch then draw the 4 lines. + let sketch = + crate::std::sketch::inner_start_profile(sketch_surface, corner_t, None, exec_state, args.clone()).await?; + let sketch_id = sketch.id; + let deltas = [[width.n, 0.0], [0.0, height.n], [-width.n, 0.0], [0.0, -height.n]]; + let ids = [ + exec_state.next_uuid(), + exec_state.next_uuid(), + exec_state.next_uuid(), + exec_state.next_uuid(), + ]; + for (id, delta) in ids.iter().copied().zip(deltas) { + exec_state + .batch_modeling_cmd( + ModelingCmdMeta::from_args_id(&args, id), + ModelingCmd::from(mcmd::ExtendPath { + path: sketch.id.into(), + segment: PathSegment::Line { + end: KPoint2d::from(untyped_point_to_mm(delta, units)) + .with_z(0.0) + .map(LengthUnit), + relative: true, + }, + }), + ) + .await?; + } + exec_state + .batch_modeling_cmd( + ModelingCmdMeta::from_args_id(&args, sketch_id), + ModelingCmd::from(mcmd::ClosePath { path_id: sketch.id }), + ) + .await?; + + // Update the sketch in KCL memory. + let mut new_sketch = sketch.clone(); + fn add(a: [f64; 2], b: [f64; 2]) -> [f64; 2] { + [a[0] + b[0], a[1] + b[1]] + } + let a = (corner, add(corner, deltas[0])); + let b = (a.1, add(a.1, deltas[1])); + let c = (b.1, add(b.1, deltas[2])); + let d = (c.1, add(c.1, deltas[3])); + for (id, (from, to)) in ids.into_iter().zip([a, b, c, d]) { + let current_path = Path::ToPoint { + base: BasePath { + from, + to, + tag: None, + units, + geo_meta: GeoMeta { + id, + metadata: args.source_range.into(), + }, + }, + }; + new_sketch.paths.push(current_path); + } + Ok(new_sketch) +} + /// Sketch a circle. pub async fn circle(exec_state: &mut ExecState, args: Args) -> Result { let sketch_or_surface = diff --git a/rust/kcl-lib/std/sketch.kcl b/rust/kcl-lib/std/sketch.kcl index 864b0246e..396581dd1 100644 --- a/rust/kcl-lib/std/sketch.kcl +++ b/rust/kcl-lib/std/sketch.kcl @@ -234,6 +234,39 @@ export fn startProfile( tag?: TagDecl, ): Sketch {} +/// Sketch a rectangle. +/// +/// ``` +/// exampleSketch = startSketchOn(-XZ) +/// |> rectangle(center = [0, 0], width = 10, height = 5) +// |> extrude(length = 2) +/// ``` +/// +/// ``` +/// exampleSketch = startSketchOn(-XZ) +/// |> rectangle(corner = [0, 0], width = 10, height = 5) +// |> extrude(length = 2) +/// ``` +@(impl = std_rust) +export fn rectangle( + /// Sketch to extend, or plane or surface to sketch on. + @sketchOrSurface: Sketch | Plane | Face, + /// Rectangle's width along X axis. + width: number(Length), + /// Rectangle's height along Y axis. + height: number(Length), + /// The center of the rectangle. + /// Incompatible with `corner`. + @(snippetArray = ["0", "0"]) + center?: Point2d, + /// The corner of the rectangle. + /// Incompatible with `center`. + /// This will be the corner which is most negative on + /// both X and Y axes. + @(snippetArray = ["0", "0"]) + corner?: Point2d, +): Sketch {} + /// Construct a 2-dimensional circle, of the specified radius, centered at /// the provided (x, y) origin point. /// diff --git a/rust/kcl-lib/tests/outputs/serial_test_example_fn_std-sketch-rectangle0.png b/rust/kcl-lib/tests/outputs/serial_test_example_fn_std-sketch-rectangle0.png new file mode 100644 index 0000000000000000000000000000000000000000..be2d109a13abb97a3c9e0e49ad5d279ff0340031 GIT binary patch literal 24230 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[27, 54, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 3["Segment
    [60, 103, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 2 }] + 4["Segment
    [109, 155, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 3 }] + 5["Segment
    [161, 211, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 4 }] + 6["Segment
    [217, 273, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 5 }] + 7["Segment
    [279, 286, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 6 }] + 8[Solid2d] + end + 1["Plane
    [4, 21, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 0 }] + 1 --- 2 + 2 --- 3 + 2 --- 4 + 2 --- 5 + 2 --- 6 + 2 --- 7 + 2 --- 8 +``` diff --git a/rust/kcl-lib/tests/rect/ast.snap b/rust/kcl-lib/tests/rect/ast.snap new file mode 100644 index 000000000..42dc11681 --- /dev/null +++ b/rust/kcl-lib/tests/rect/ast.snap @@ -0,0 +1,701 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of parsing rect.kcl +--- +{ + "Ok": { + "body": [ + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "x", + "start": 0, + "type": "Identifier" + }, + "init": { + "body": [ + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "startSketchOn", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "XY", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "at", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "argument": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "operator": "-", + "start": 0, + "type": "UnaryExpression", + "type": "UnaryExpression" + }, + { + "argument": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "1", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 1.0, + "suffix": "None" + } + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "operator": "-", + "start": 0, + "type": "UnaryExpression", + "type": "UnaryExpression" + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "startProfile", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "angle", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "length", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "3", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 3.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "tag", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "TagDeclarator", + "type": "TagDeclarator", + "value": "a" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "angledLine", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "angle", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "left": { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "segAng", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "a", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + "moduleId": 0, + "operator": "+", + "right": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "90", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 90.0, + "suffix": "None" + } + }, + "start": 0, + "type": "BinaryExpression", + "type": "BinaryExpression" + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "length", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "angledLine", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "angle", + "start": 0, + "type": "Identifier" + }, + "arg": { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "segAng", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "a", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "length", + "start": 0, + "type": "Identifier" + }, + "arg": { + "argument": { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "segLen", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "a", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "operator": "-", + "start": 0, + "type": "UnaryExpression", + "type": "UnaryExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "angledLine", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "endAbsolute", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "profileStartX", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "PipeSubstitution", + "type": "PipeSubstitution" + } + }, + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "profileStartY", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "PipeSubstitution", + "type": "PipeSubstitution" + } + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "line", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "close", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "PipeExpression", + "type": "PipeExpression" + }, + "moduleId": 0, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "const", + "moduleId": 0, + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0 + } +} diff --git a/rust/kcl-lib/tests/rect/input.kcl b/rust/kcl-lib/tests/rect/input.kcl new file mode 100644 index 000000000..2ed70845f --- /dev/null +++ b/rust/kcl-lib/tests/rect/input.kcl @@ -0,0 +1,7 @@ +x = startSketchOn(XY) + |> startProfile(at = [-2, -1]) + |> angledLine(angle = 0, length = 3, tag = $a) + |> angledLine(angle = segAng(a) + 90, length = 2) + |> angledLine(angle = segAng(a), length = -segLen(a)) + |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) + |> close() diff --git a/rust/kcl-lib/tests/rect/ops.snap b/rust/kcl-lib/tests/rect/ops.snap new file mode 100644 index 000000000..cf120d1ec --- /dev/null +++ b/rust/kcl-lib/tests/rect/ops.snap @@ -0,0 +1,128 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Operations executed rect.kcl +--- +{ + "rust/kcl-lib/tests/rect/input.kcl": [ + { + "type": "StdLibCall", + "name": "startSketchOn", + "unlabeledArg": { + "value": { + "type": "Plane", + "artifact_id": "[uuid]" + }, + "sourceRange": [] + }, + "labeledArgs": {}, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 0 + }, + { + "type": "VariableDeclarationDeclaration" + }, + { + "type": "VariableDeclarationInit" + }, + { + "type": "PipeBodyItem", + "index": 0 + } + ] + }, + "sourceRange": [] + } + ], + "std::appearance": [], + "std::array": [], + "std::math": [ + { + "type": "VariableDeclaration", + "name": "PI", + "value": { + "type": "Number", + "value": 3.141592653589793, + "ty": { + "type": "Unknown" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "E", + "value": { + "type": "Number", + "value": 2.718281828459045, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "TAU", + "value": { + "type": "Number", + "value": 6.283185307179586, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::prelude": [ + { + "type": "VariableDeclaration", + "name": "START", + "value": { + "type": "String", + "value": "start" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "END", + "value": { + "type": "String", + "value": "end" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/rect/program_memory.snap b/rust/kcl-lib/tests/rect/program_memory.snap new file mode 100644 index 000000000..a93bc3091 --- /dev/null +++ b/rust/kcl-lib/tests/rect/program_memory.snap @@ -0,0 +1,181 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Variables in memory after executing rect.kcl +--- +{ + "a": { + "type": "TagIdentifier", + "type": "TagIdentifier", + "value": "a" + }, + "x": { + "type": "Sketch", + "value": { + "type": "Sketch", + "id": "[uuid]", + "paths": [ + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + -2.0, + -1.0 + ], + "tag": { + "commentStart": 100, + "end": 102, + "moduleId": 0, + "start": 100, + "type": "TagDeclarator", + "value": "a" + }, + "to": [ + 1.0, + -1.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + 1.0, + -1.0 + ], + "tag": null, + "to": [ + 1.0000000000000002, + 1.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + 1.0000000000000002, + 1.0 + ], + "tag": null, + "to": [ + -1.9999999999999998, + 1.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + -1.9999999999999998, + 1.0 + ], + "tag": null, + "to": [ + -2.0, + -1.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + -2.0, + -1.0 + ], + "tag": null, + "to": [ + -2.0, + -1.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + } + ], + "on": { + "artifactId": "[uuid]", + "id": "[uuid]", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Mm" + } + }, + "type": "plane", + "value": "XY", + "xAxis": { + "x": 1.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Unknown" + } + }, + "yAxis": { + "x": 0.0, + "y": 1.0, + "z": 0.0, + "units": { + "type": "Unknown" + } + } + }, + "start": { + "from": [ + -2.0, + -1.0 + ], + "to": [ + -2.0, + -1.0 + ], + "units": { + "type": "Mm" + }, + "tag": null, + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + } + }, + "tags": { + "a": { + "type": "TagIdentifier", + "value": "a" + } + }, + "artifactId": "[uuid]", + "originalId": "[uuid]", + "units": { + "type": "Mm" + } + } + } +} diff --git a/rust/kcl-lib/tests/rect/rendered_model.png b/rust/kcl-lib/tests/rect/rendered_model.png new file mode 100644 index 0000000000000000000000000000000000000000..d67607ac6eaef8868f0be390c30cf63f2600fbaf GIT binary patch literal 26188 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 literal 0 HcmV?d00001 diff --git a/rust/kcl-lib/tests/rect/unparsed.snap b/rust/kcl-lib/tests/rect/unparsed.snap new file mode 100644 index 000000000..99637e205 --- /dev/null +++ b/rust/kcl-lib/tests/rect/unparsed.snap @@ -0,0 +1,11 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of unparsing rect.kcl +--- +x = startSketchOn(XY) + |> startProfile(at = [-2, -1]) + |> angledLine(angle = 0, length = 3, tag = $a) + |> angledLine(angle = segAng(a) + 90, length = 2) + |> angledLine(angle = segAng(a), length = -segLen(a)) + |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) + |> close() diff --git a/rust/kcl-lib/tests/rect_helper/artifact_commands.snap b/rust/kcl-lib/tests/rect_helper/artifact_commands.snap new file mode 100644 index 000000000..3071652d6 --- /dev/null +++ b/rust/kcl-lib/tests/rect_helper/artifact_commands.snap @@ -0,0 +1,163 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact commands rect_helper.kcl +--- +{ + "rust/kcl-lib/tests/rect_helper/input.kcl": [ + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "make_plane", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "x_axis": { + "x": 1.0, + "y": 0.0, + "z": 0.0 + }, + "y_axis": { + "x": 0.0, + "y": 1.0, + "z": 0.0 + }, + "size": 60.0, + "clobber": false, + "hide": true + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "start_path" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "move_path_pen", + "path": "[uuid]", + "to": { + "x": -2.0, + "y": -1.0, + "z": 0.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 3.0, + "y": 0.0, + "z": 0.0 + }, + "relative": true + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 0.0, + "y": 2.0, + "z": 0.0 + }, + "relative": true + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": -3.0, + "y": 0.0, + "z": 0.0 + }, + "relative": true + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 0.0, + "y": -2.0, + "z": 0.0 + }, + "relative": true + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "close_path", + "path_id": "[uuid]" + } + } + ], + "std::appearance": [], + "std::array": [], + "std::math": [], + "std::prelude": [], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/rect_helper/artifact_graph_flowchart.snap b/rust/kcl-lib/tests/rect_helper/artifact_graph_flowchart.snap new file mode 100644 index 000000000..fa21abca9 --- /dev/null +++ b/rust/kcl-lib/tests/rect_helper/artifact_graph_flowchart.snap @@ -0,0 +1,6 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact graph flowchart rect_helper.kcl +extension: md +snapshot_kind: binary +--- diff --git a/rust/kcl-lib/tests/rect_helper/artifact_graph_flowchart.snap.md b/rust/kcl-lib/tests/rect_helper/artifact_graph_flowchart.snap.md new file mode 100644 index 000000000..a082bd808 --- /dev/null +++ b/rust/kcl-lib/tests/rect_helper/artifact_graph_flowchart.snap.md @@ -0,0 +1,24 @@ +```mermaid +flowchart LR + subgraph path2 [Path] + 2["Path
    [25, 76, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 3["Segment
    [25, 76, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 4["Segment
    [25, 76, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 5["Segment
    [25, 76, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 6["Segment
    [25, 76, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 7[Solid2d] + end + 1["Plane
    [4, 21, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 0 }] + 1 --- 2 + 2 --- 3 + 2 --- 4 + 2 --- 5 + 2 --- 6 + 2 --- 7 +``` diff --git a/rust/kcl-lib/tests/rect_helper/ast.snap b/rust/kcl-lib/tests/rect_helper/ast.snap new file mode 100644 index 000000000..9c157979f --- /dev/null +++ b/rust/kcl-lib/tests/rect_helper/ast.snap @@ -0,0 +1,233 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of parsing rect_helper.kcl +--- +{ + "Ok": { + "body": [ + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "x", + "start": 0, + "type": "Identifier" + }, + "init": { + "body": [ + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "startSketchOn", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "XY", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "width", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "3", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 3.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "height", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "corner", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "argument": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "operator": "-", + "start": 0, + "type": "UnaryExpression", + "type": "UnaryExpression" + }, + { + "argument": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "1", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 1.0, + "suffix": "None" + } + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "operator": "-", + "start": 0, + "type": "UnaryExpression", + "type": "UnaryExpression" + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "rectangle", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "PipeExpression", + "type": "PipeExpression" + }, + "moduleId": 0, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "const", + "moduleId": 0, + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0 + } +} diff --git a/rust/kcl-lib/tests/rect_helper/input.kcl b/rust/kcl-lib/tests/rect_helper/input.kcl new file mode 100644 index 000000000..3e041e728 --- /dev/null +++ b/rust/kcl-lib/tests/rect_helper/input.kcl @@ -0,0 +1,2 @@ +x = startSketchOn(XY) +|> rectangle(width = 3, height = 2, corner = [-2, -1]) diff --git a/rust/kcl-lib/tests/rect_helper/ops.snap b/rust/kcl-lib/tests/rect_helper/ops.snap new file mode 100644 index 000000000..a34c67bb0 --- /dev/null +++ b/rust/kcl-lib/tests/rect_helper/ops.snap @@ -0,0 +1,128 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Operations executed rect_helper.kcl +--- +{ + "rust/kcl-lib/tests/rect_helper/input.kcl": [ + { + "type": "StdLibCall", + "name": "startSketchOn", + "unlabeledArg": { + "value": { + "type": "Plane", + "artifact_id": "[uuid]" + }, + "sourceRange": [] + }, + "labeledArgs": {}, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 0 + }, + { + "type": "VariableDeclarationDeclaration" + }, + { + "type": "VariableDeclarationInit" + }, + { + "type": "PipeBodyItem", + "index": 0 + } + ] + }, + "sourceRange": [] + } + ], + "std::appearance": [], + "std::array": [], + "std::math": [ + { + "type": "VariableDeclaration", + "name": "PI", + "value": { + "type": "Number", + "value": 3.141592653589793, + "ty": { + "type": "Unknown" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "E", + "value": { + "type": "Number", + "value": 2.718281828459045, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "TAU", + "value": { + "type": "Number", + "value": 6.283185307179586, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::prelude": [ + { + "type": "VariableDeclaration", + "name": "START", + "value": { + "type": "String", + "value": "start" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "END", + "value": { + "type": "String", + "value": "end" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/rect_helper/program_memory.snap b/rust/kcl-lib/tests/rect_helper/program_memory.snap new file mode 100644 index 000000000..d2fd3a45a --- /dev/null +++ b/rust/kcl-lib/tests/rect_helper/program_memory.snap @@ -0,0 +1,144 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Variables in memory after executing rect_helper.kcl +--- +{ + "x": { + "type": "Sketch", + "value": { + "type": "Sketch", + "id": "[uuid]", + "paths": [ + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + -2.0, + -1.0 + ], + "tag": null, + "to": [ + 1.0, + -1.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + 1.0, + -1.0 + ], + "tag": null, + "to": [ + 1.0, + 1.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + 1.0, + 1.0 + ], + "tag": null, + "to": [ + -2.0, + 1.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + -2.0, + 1.0 + ], + "tag": null, + "to": [ + -2.0, + -1.0 + ], + "type": "ToPoint", + "units": { + "type": "Mm" + } + } + ], + "on": { + "artifactId": "[uuid]", + "id": "[uuid]", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Mm" + } + }, + "type": "plane", + "value": "XY", + "xAxis": { + "x": 1.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Unknown" + } + }, + "yAxis": { + "x": 0.0, + "y": 1.0, + "z": 0.0, + "units": { + "type": "Unknown" + } + } + }, + "start": { + "from": [ + -2.0, + -1.0 + ], + "to": [ + -2.0, + -1.0 + ], + "units": { + "type": "Mm" + }, + "tag": null, + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + } + }, + "artifactId": "[uuid]", + "originalId": "[uuid]", + "units": { + "type": "Mm" + } + } + } +} diff --git a/rust/kcl-lib/tests/rect_helper/rendered_model.png b/rust/kcl-lib/tests/rect_helper/rendered_model.png new file mode 100644 index 0000000000000000000000000000000000000000..d67607ac6eaef8868f0be390c30cf63f2600fbaf GIT binary patch literal 26188 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 literal 0 HcmV?d00001 diff --git a/rust/kcl-lib/tests/rect_helper/unparsed.snap b/rust/kcl-lib/tests/rect_helper/unparsed.snap new file mode 100644 index 000000000..f8376774d --- /dev/null +++ b/rust/kcl-lib/tests/rect_helper/unparsed.snap @@ -0,0 +1,6 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of unparsing rect_helper.kcl +--- +x = startSketchOn(XY) + |> rectangle(width = 3, height = 2, corner = [-2, -1]) From 6ddbb7a31df05f2624e53db67014eac8f43dfc74 Mon Sep 17 00:00:00 2001 From: Jonathan Tran Date: Tue, 1 Jul 2025 14:37:01 -0400 Subject: [PATCH 16/19] Fix unknown property error message on sketches and solids (#7632) * Fix unknown property error message on sketches and solids * Add suggestion for common case * Move test code in file to avoid conflict --- rust/kcl-lib/src/execution/exec_ast.rs | 16 + rust/kcl-lib/src/simulation_tests.rs | 21 + .../artifact_commands.snap | 206 +++++ .../artifact_graph_flowchart.snap | 6 + .../artifact_graph_flowchart.snap.md | 78 ++ .../ast.snap | 780 ++++++++++++++++++ .../execution_error.snap | 15 + .../input.kcl | 14 + .../ops.snap | 233 ++++++ .../unparsed.snap | 17 + 10 files changed, 1386 insertions(+) create mode 100644 rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_commands.snap create mode 100644 rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_graph_flowchart.snap create mode 100644 rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_graph_flowchart.snap.md create mode 100644 rust/kcl-lib/tests/property_access_not_found_on_solid/ast.snap create mode 100644 rust/kcl-lib/tests/property_access_not_found_on_solid/execution_error.snap create mode 100644 rust/kcl-lib/tests/property_access_not_found_on_solid/input.kcl create mode 100644 rust/kcl-lib/tests/property_access_not_found_on_solid/ops.snap create mode 100644 rust/kcl-lib/tests/property_access_not_found_on_solid/unparsed.snap diff --git a/rust/kcl-lib/src/execution/exec_ast.rs b/rust/kcl-lib/src/execution/exec_ast.rs index 9d2240e30..d8752495e 100644 --- a/rust/kcl-lib/src/execution/exec_ast.rs +++ b/rust/kcl-lib/src/execution/exec_ast.rs @@ -1046,6 +1046,16 @@ impl Node { (KclValue::Solid { value }, Property::String(prop), false) if prop == "sketch" => Ok(KclValue::Sketch { value: Box::new(value.sketch), }), + (geometry @ KclValue::Solid { .. }, Property::String(prop), false) if prop == "tags" => { + // This is a common mistake. + Err(KclError::new_semantic(KclErrorDetails::new( + format!( + "Property `{prop}` not found on {}. You can get a solid's tags through its sketch, as in, `exampleSolid.sketch.tags`.", + geometry.human_friendly_type() + ), + vec![self.clone().into()], + ))) + } (KclValue::Sketch { value: sk }, Property::String(prop), false) if prop == "tags" => Ok(KclValue::Object { meta: vec![Metadata { source_range: SourceRange::from(self.clone()), @@ -1056,6 +1066,12 @@ impl Node { .map(|(k, tag)| (k.to_owned(), KclValue::TagIdentifier(Box::new(tag.to_owned())))) .collect(), }), + (geometry @ (KclValue::Sketch { .. } | KclValue::Solid { .. }), Property::String(property), false) => { + Err(KclError::new_semantic(KclErrorDetails::new( + format!("Property `{property}` not found on {}", geometry.human_friendly_type()), + vec![self.clone().into()], + ))) + } (being_indexed, _, _) => Err(KclError::new_semantic(KclErrorDetails::new( format!( "Only arrays can be indexed, but you're trying to index {}", diff --git a/rust/kcl-lib/src/simulation_tests.rs b/rust/kcl-lib/src/simulation_tests.rs index d49079e1b..86440c84f 100644 --- a/rust/kcl-lib/src/simulation_tests.rs +++ b/rust/kcl-lib/src/simulation_tests.rs @@ -887,6 +887,27 @@ mod invalid_index_fractional { super::execute(TEST_NAME, false).await } } +mod property_access_not_found_on_solid { + const TEST_NAME: &str = "property_access_not_found_on_solid"; + + /// Test parsing KCL. + #[test] + fn parse() { + super::parse(TEST_NAME) + } + + /// Test that parsing and unparsing KCL produces the original KCL input. + #[tokio::test(flavor = "multi_thread")] + async fn unparse() { + super::unparse(TEST_NAME).await + } + + /// Test that KCL is executed correctly. + #[tokio::test(flavor = "multi_thread")] + async fn kcl_test_execute() { + super::execute(TEST_NAME, true).await + } +} mod invalid_member_object { const TEST_NAME: &str = "invalid_member_object"; diff --git a/rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_commands.snap b/rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_commands.snap new file mode 100644 index 000000000..4c6e3b052 --- /dev/null +++ b/rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_commands.snap @@ -0,0 +1,206 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact commands property_access_not_found_on_solid.kcl +--- +{ + "rust/kcl-lib/tests/property_access_not_found_on_solid/input.kcl": [ + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "make_plane", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "x_axis": { + "x": 1.0, + "y": 0.0, + "z": 0.0 + }, + "y_axis": { + "x": 0.0, + "y": 1.0, + "z": 0.0 + }, + "size": 60.0, + "clobber": false, + "hide": true + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "start_path" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "move_path_pen", + "path": "[uuid]", + "to": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 10.0, + "y": 10.0, + "z": 0.0 + }, + "relative": true + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": -20.0, + "y": 0.0, + "z": 0.0 + }, + "relative": true + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 10.0, + "y": -10.0, + "z": 0.0 + }, + "relative": true + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "close_path", + "path_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extrude", + "target": "[uuid]", + "distance": 5.0, + "faces": null, + "opposite": "None" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_bring_to_front", + "object_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_extrusion_face_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_adjacency_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + } + ], + "std::appearance": [], + "std::array": [], + "std::math": [], + "std::prelude": [], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_graph_flowchart.snap b/rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_graph_flowchart.snap new file mode 100644 index 000000000..5a6d20b91 --- /dev/null +++ b/rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_graph_flowchart.snap @@ -0,0 +1,6 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact graph flowchart property_access_not_found_on_solid.kcl +extension: md +snapshot_kind: binary +--- diff --git a/rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_graph_flowchart.snap.md b/rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_graph_flowchart.snap.md new file mode 100644 index 000000000..4a45dfcec --- /dev/null +++ b/rust/kcl-lib/tests/property_access_not_found_on_solid/artifact_graph_flowchart.snap.md @@ -0,0 +1,78 @@ +```mermaid +flowchart LR + subgraph path2 [Path] + 2["Path
    [52, 77, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, FunctionExpressionBody, FunctionExpressionBodyItem { index: 0 }, ReturnStatementArg, PipeBodyItem { index: 1 }] + 3["Segment
    [85, 119, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, FunctionExpressionBody, FunctionExpressionBodyItem { index: 0 }, ReturnStatementArg, PipeBodyItem { index: 2 }] + 4["Segment
    [127, 147, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, FunctionExpressionBody, FunctionExpressionBodyItem { index: 0 }, ReturnStatementArg, PipeBodyItem { index: 3 }] + 5["Segment
    [155, 176, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, FunctionExpressionBody, FunctionExpressionBodyItem { index: 0 }, ReturnStatementArg, PipeBodyItem { index: 4 }] + 6["Segment
    [184, 191, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, FunctionExpressionBody, FunctionExpressionBodyItem { index: 0 }, ReturnStatementArg, PipeBodyItem { index: 5 }] + 7[Solid2d] + end + 1["Plane
    [27, 44, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, FunctionExpressionBody, FunctionExpressionBodyItem { index: 0 }, ReturnStatementArg, PipeBodyItem { index: 0 }] + 8["Sweep Extrusion
    [199, 235, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, FunctionExpressionBody, FunctionExpressionBodyItem { index: 0 }, ReturnStatementArg, PipeBodyItem { index: 6 }] + 9[Wall] + %% face_code_ref=Missing NodePath + 10[Wall] + %% face_code_ref=Missing NodePath + 11[Wall] + %% face_code_ref=Missing NodePath + 12["Cap Start"] + %% face_code_ref=Missing NodePath + 13["Cap End"] + %% face_code_ref=Missing NodePath + 14["SweepEdge Opposite"] + 15["SweepEdge Adjacent"] + 16["SweepEdge Opposite"] + 17["SweepEdge Adjacent"] + 18["SweepEdge Opposite"] + 19["SweepEdge Adjacent"] + 1 --- 2 + 2 --- 3 + 2 --- 4 + 2 --- 5 + 2 --- 6 + 2 --- 7 + 2 ---- 8 + 3 --- 9 + 3 x--> 12 + 3 --- 14 + 3 --- 15 + 4 --- 10 + 4 x--> 12 + 4 --- 16 + 4 --- 17 + 5 --- 11 + 5 x--> 12 + 5 --- 18 + 5 --- 19 + 8 --- 9 + 8 --- 10 + 8 --- 11 + 8 --- 12 + 8 --- 13 + 8 --- 14 + 8 --- 15 + 8 --- 16 + 8 --- 17 + 8 --- 18 + 8 --- 19 + 9 --- 14 + 9 --- 15 + 19 <--x 9 + 15 <--x 10 + 10 --- 16 + 10 --- 17 + 17 <--x 11 + 11 --- 18 + 11 --- 19 + 14 <--x 13 + 16 <--x 13 + 18 <--x 13 +``` diff --git a/rust/kcl-lib/tests/property_access_not_found_on_solid/ast.snap b/rust/kcl-lib/tests/property_access_not_found_on_solid/ast.snap new file mode 100644 index 000000000..26dbee524 --- /dev/null +++ b/rust/kcl-lib/tests/property_access_not_found_on_solid/ast.snap @@ -0,0 +1,780 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of parsing property_access_not_found_on_solid.kcl +--- +{ + "Ok": { + "body": [ + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "myFunction", + "start": 0, + "type": "Identifier" + }, + "init": { + "body": { + "body": [ + { + "argument": { + "body": [ + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "startSketchOn", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "XY", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "at", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + }, + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "startProfile", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "end", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "10", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 10.0, + "suffix": "None" + } + }, + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "10", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 10.0, + "suffix": "None" + } + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "tag", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "TagDeclarator", + "type": "TagDeclarator", + "value": "seg01" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "line", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "end", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "argument": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "20", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 20.0, + "suffix": "None" + } + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "operator": "-", + "start": 0, + "type": "UnaryExpression", + "type": "UnaryExpression" + }, + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "line", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "end", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "10", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 10.0, + "suffix": "None" + } + }, + { + "argument": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "10", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 10.0, + "suffix": "None" + } + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "operator": "-", + "start": 0, + "type": "UnaryExpression", + "type": "UnaryExpression" + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "line", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "close", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "length", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "5", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 5.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "tagEnd", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "TagDeclarator", + "type": "TagDeclarator", + "value": "end01" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "extrude", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "PipeExpression", + "type": "PipeExpression" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ReturnStatement", + "type": "ReturnStatement" + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0 + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "params": [], + "start": 0, + "type": "FunctionExpression", + "type": "FunctionExpression" + }, + "moduleId": 0, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "fn", + "moduleId": 0, + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + }, + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "myShape", + "start": 0, + "type": "Identifier" + }, + "init": { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "myFunction", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + "moduleId": 0, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "const", + "moduleId": 0, + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + }, + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "sketch001", + "start": 0, + "type": "Identifier" + }, + "init": { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "face", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "computed": false, + "end": 0, + "moduleId": 0, + "object": { + "commentStart": 0, + "computed": false, + "end": 0, + "moduleId": 0, + "object": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "myShape", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + }, + "property": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "tags", + "start": 0, + "type": "Identifier", + "type": "Identifier" + }, + "start": 0, + "type": "MemberExpression", + "type": "MemberExpression" + }, + "property": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "seg01", + "start": 0, + "type": "Identifier", + "type": "Identifier" + }, + "start": 0, + "type": "MemberExpression", + "type": "MemberExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "startSketchOn", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "myShape", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + "moduleId": 0, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "const", + "moduleId": 0, + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "nonCodeMeta": { + "nonCodeNodes": { + "0": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "NonCodeNode", + "value": { + "type": "newLine" + } + } + ], + "1": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "NonCodeNode", + "value": { + "type": "newLine" + } + } + ], + "2": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "NonCodeNode", + "value": { + "type": "newLine" + } + } + ] + }, + "startNodes": [] + }, + "start": 0 + } +} diff --git a/rust/kcl-lib/tests/property_access_not_found_on_solid/execution_error.snap b/rust/kcl-lib/tests/property_access_not_found_on_solid/execution_error.snap new file mode 100644 index 000000000..2dd58ad6d --- /dev/null +++ b/rust/kcl-lib/tests/property_access_not_found_on_solid/execution_error.snap @@ -0,0 +1,15 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Error from executing property_access_not_found_on_solid.kcl +--- +KCL Semantic error + + × semantic: Property `tags` not found on a solid. You can get a solid's tags + │ through its sketch, as in, `exampleSolid.sketch.tags`. + ╭─[13:43] + 12 │ + 13 │ sketch001 = startSketchOn(myShape, face = myShape.tags.seg01) + · ──────┬───── + · ╰── tests/property_access_not_found_on_solid/input.kcl + 14 │ + ╰──── diff --git a/rust/kcl-lib/tests/property_access_not_found_on_solid/input.kcl b/rust/kcl-lib/tests/property_access_not_found_on_solid/input.kcl new file mode 100644 index 000000000..35b1d360c --- /dev/null +++ b/rust/kcl-lib/tests/property_access_not_found_on_solid/input.kcl @@ -0,0 +1,14 @@ +fn myFunction() { + return startSketchOn(XY) + |> startProfile(at = [0, 0]) + |> line(end = [10, 10], tag = $seg01) + |> line(end = [-20, 0]) + |> line(end = [10, -10]) + |> close() + |> extrude(length = 5, tagEnd = $end01) +} + +myShape = myFunction() + +sketch001 = startSketchOn(myShape, face = myShape.tags.seg01) + diff --git a/rust/kcl-lib/tests/property_access_not_found_on_solid/ops.snap b/rust/kcl-lib/tests/property_access_not_found_on_solid/ops.snap new file mode 100644 index 000000000..693b13f70 --- /dev/null +++ b/rust/kcl-lib/tests/property_access_not_found_on_solid/ops.snap @@ -0,0 +1,233 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Operations executed property_access_not_found_on_solid.kcl +--- +{ + "rust/kcl-lib/tests/property_access_not_found_on_solid/input.kcl": [ + { + "type": "GroupBegin", + "group": { + "type": "FunctionCall", + "name": "myFunction", + "functionSourceRange": [], + "unlabeledArg": null, + "labeledArgs": {} + }, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 1 + }, + { + "type": "VariableDeclarationDeclaration" + }, + { + "type": "VariableDeclarationInit" + } + ] + }, + "sourceRange": [] + }, + { + "type": "StdLibCall", + "name": "startSketchOn", + "unlabeledArg": { + "value": { + "type": "Plane", + "artifact_id": "[uuid]" + }, + "sourceRange": [] + }, + "labeledArgs": {}, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 0 + }, + { + "type": "VariableDeclarationDeclaration" + }, + { + "type": "VariableDeclarationInit" + }, + { + "type": "FunctionExpressionBody" + }, + { + "type": "FunctionExpressionBodyItem", + "index": 0 + }, + { + "type": "ReturnStatementArg" + }, + { + "type": "PipeBodyItem", + "index": 0 + } + ] + }, + "sourceRange": [] + }, + { + "type": "StdLibCall", + "name": "extrude", + "unlabeledArg": { + "value": { + "type": "Sketch", + "value": { + "artifactId": "[uuid]" + } + }, + "sourceRange": [] + }, + "labeledArgs": { + "length": { + "value": { + "type": "Number", + "value": 5.0, + "ty": { + "type": "Default", + "len": { + "type": "Mm" + }, + "angle": { + "type": "Degrees" + } + } + }, + "sourceRange": [] + }, + "tagEnd": { + "value": { + "type": "TagDeclarator", + "name": "end01" + }, + "sourceRange": [] + } + }, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 0 + }, + { + "type": "VariableDeclarationDeclaration" + }, + { + "type": "VariableDeclarationInit" + }, + { + "type": "FunctionExpressionBody" + }, + { + "type": "FunctionExpressionBodyItem", + "index": 0 + }, + { + "type": "ReturnStatementArg" + }, + { + "type": "PipeBodyItem", + "index": 6 + } + ] + }, + "sourceRange": [] + }, + { + "type": "GroupEnd" + } + ], + "std::appearance": [], + "std::array": [], + "std::math": [ + { + "type": "VariableDeclaration", + "name": "PI", + "value": { + "type": "Number", + "value": 3.141592653589793, + "ty": { + "type": "Unknown" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "E", + "value": { + "type": "Number", + "value": 2.718281828459045, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "TAU", + "value": { + "type": "Number", + "value": 6.283185307179586, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::prelude": [ + { + "type": "VariableDeclaration", + "name": "START", + "value": { + "type": "String", + "value": "start" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "END", + "value": { + "type": "String", + "value": "end" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/property_access_not_found_on_solid/unparsed.snap b/rust/kcl-lib/tests/property_access_not_found_on_solid/unparsed.snap new file mode 100644 index 000000000..106565aac --- /dev/null +++ b/rust/kcl-lib/tests/property_access_not_found_on_solid/unparsed.snap @@ -0,0 +1,17 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of unparsing property_access_not_found_on_solid.kcl +--- +fn myFunction() { + return startSketchOn(XY) + |> startProfile(at = [0, 0]) + |> line(end = [10, 10], tag = $seg01) + |> line(end = [-20, 0]) + |> line(end = [10, -10]) + |> close() + |> extrude(length = 5, tagEnd = $end01) +} + +myShape = myFunction() + +sketch001 = startSketchOn(myShape, face = myShape.tags.seg01) From a85a534d6b464eb838f61e4db12303bbffac3850 Mon Sep 17 00:00:00 2001 From: Jonathan Tran Date: Tue, 1 Jul 2025 15:15:35 -0400 Subject: [PATCH 17/19] Release KCL 84 (#7653) --- rust/Cargo.lock | 20 ++++++++++---------- rust/kcl-bumper/Cargo.toml | 2 +- rust/kcl-derive-docs/Cargo.toml | 2 +- rust/kcl-directory-test-macro/Cargo.toml | 2 +- rust/kcl-language-server-release/Cargo.toml | 2 +- rust/kcl-language-server/Cargo.toml | 2 +- rust/kcl-lib/Cargo.toml | 2 +- rust/kcl-python-bindings/Cargo.toml | 2 +- rust/kcl-test-server/Cargo.toml | 2 +- rust/kcl-to-core/Cargo.toml | 2 +- rust/kcl-wasm-lib/Cargo.toml | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 57dd1c8c9..c5c58240f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1814,7 +1814,7 @@ dependencies = [ [[package]] name = "kcl-bumper" -version = "0.1.83" +version = "0.1.84" dependencies = [ "anyhow", "clap", @@ -1825,7 +1825,7 @@ dependencies = [ [[package]] name = "kcl-derive-docs" -version = "0.1.83" +version = "0.1.84" dependencies = [ "proc-macro2", "quote", @@ -1834,7 +1834,7 @@ dependencies = [ [[package]] name = "kcl-directory-test-macro" -version = "0.1.83" +version = "0.1.84" dependencies = [ "convert_case", "proc-macro2", @@ -1844,7 +1844,7 @@ dependencies = [ [[package]] name = "kcl-language-server" -version = "0.2.83" +version = "0.2.84" dependencies = [ "anyhow", "clap", @@ -1865,7 +1865,7 @@ dependencies = [ [[package]] name = "kcl-language-server-release" -version = "0.1.83" +version = "0.1.84" dependencies = [ "anyhow", "clap", @@ -1885,7 +1885,7 @@ dependencies = [ [[package]] name = "kcl-lib" -version = "0.2.83" +version = "0.2.84" dependencies = [ "anyhow", "approx 0.5.1", @@ -1962,7 +1962,7 @@ dependencies = [ [[package]] name = "kcl-python-bindings" -version = "0.3.83" +version = "0.3.84" dependencies = [ "anyhow", "kcl-lib", @@ -1977,7 +1977,7 @@ dependencies = [ [[package]] name = "kcl-test-server" -version = "0.1.83" +version = "0.1.84" dependencies = [ "anyhow", "hyper 0.14.32", @@ -1990,7 +1990,7 @@ dependencies = [ [[package]] name = "kcl-to-core" -version = "0.1.83" +version = "0.1.84" dependencies = [ "anyhow", "async-trait", @@ -2004,7 +2004,7 @@ dependencies = [ [[package]] name = "kcl-wasm-lib" -version = "0.1.83" +version = "0.1.84" dependencies = [ "anyhow", "bson", diff --git a/rust/kcl-bumper/Cargo.toml b/rust/kcl-bumper/Cargo.toml index 397c74faa..db2c82531 100644 --- a/rust/kcl-bumper/Cargo.toml +++ b/rust/kcl-bumper/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kcl-bumper" -version = "0.1.83" +version = "0.1.84" edition = "2021" repository = "https://github.com/KittyCAD/modeling-api" rust-version = "1.76" diff --git a/rust/kcl-derive-docs/Cargo.toml b/rust/kcl-derive-docs/Cargo.toml index 239862f2a..4e5b29f16 100644 --- a/rust/kcl-derive-docs/Cargo.toml +++ b/rust/kcl-derive-docs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kcl-derive-docs" description = "A tool for generating documentation from Rust derive macros" -version = "0.1.83" +version = "0.1.84" edition = "2021" license = "MIT" repository = "https://github.com/KittyCAD/modeling-app" diff --git a/rust/kcl-directory-test-macro/Cargo.toml b/rust/kcl-directory-test-macro/Cargo.toml index a3216c8ca..860fcb1b1 100644 --- a/rust/kcl-directory-test-macro/Cargo.toml +++ b/rust/kcl-directory-test-macro/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kcl-directory-test-macro" description = "A tool for generating tests from a directory of kcl files" -version = "0.1.83" +version = "0.1.84" edition = "2021" license = "MIT" repository = "https://github.com/KittyCAD/modeling-app" diff --git a/rust/kcl-language-server-release/Cargo.toml b/rust/kcl-language-server-release/Cargo.toml index f7d51e4e1..801060edc 100644 --- a/rust/kcl-language-server-release/Cargo.toml +++ b/rust/kcl-language-server-release/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kcl-language-server-release" -version = "0.1.83" +version = "0.1.84" edition = "2021" authors = ["KittyCAD Inc "] publish = false diff --git a/rust/kcl-language-server/Cargo.toml b/rust/kcl-language-server/Cargo.toml index 5b529de7a..88ee106ea 100644 --- a/rust/kcl-language-server/Cargo.toml +++ b/rust/kcl-language-server/Cargo.toml @@ -2,7 +2,7 @@ name = "kcl-language-server" description = "A language server for KCL." authors = ["KittyCAD Inc "] -version = "0.2.83" +version = "0.2.84" edition = "2021" license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rust/kcl-lib/Cargo.toml b/rust/kcl-lib/Cargo.toml index 501afae99..ee0b2cacc 100644 --- a/rust/kcl-lib/Cargo.toml +++ b/rust/kcl-lib/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kcl-lib" description = "KittyCAD Language implementation and tools" -version = "0.2.83" +version = "0.2.84" edition = "2024" license = "MIT" repository = "https://github.com/KittyCAD/modeling-app" diff --git a/rust/kcl-python-bindings/Cargo.toml b/rust/kcl-python-bindings/Cargo.toml index 8d6cde759..a7184becf 100644 --- a/rust/kcl-python-bindings/Cargo.toml +++ b/rust/kcl-python-bindings/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kcl-python-bindings" -version = "0.3.83" +version = "0.3.84" edition = "2021" repository = "https://github.com/kittycad/modeling-app" exclude = ["tests/*", "files/*", "venv/*"] diff --git a/rust/kcl-test-server/Cargo.toml b/rust/kcl-test-server/Cargo.toml index 5a16659f0..bb8505841 100644 --- a/rust/kcl-test-server/Cargo.toml +++ b/rust/kcl-test-server/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kcl-test-server" description = "A test server for KCL" -version = "0.1.83" +version = "0.1.84" edition = "2021" license = "MIT" diff --git a/rust/kcl-to-core/Cargo.toml b/rust/kcl-to-core/Cargo.toml index 8f73372a7..c5a89ff86 100644 --- a/rust/kcl-to-core/Cargo.toml +++ b/rust/kcl-to-core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kcl-to-core" description = "Utility methods to convert kcl to engine core executable tests" -version = "0.1.83" +version = "0.1.84" edition = "2021" license = "MIT" repository = "https://github.com/KittyCAD/modeling-app" diff --git a/rust/kcl-wasm-lib/Cargo.toml b/rust/kcl-wasm-lib/Cargo.toml index 209abefd3..a4c80d98d 100644 --- a/rust/kcl-wasm-lib/Cargo.toml +++ b/rust/kcl-wasm-lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kcl-wasm-lib" -version = "0.1.83" +version = "0.1.84" edition = "2021" repository = "https://github.com/KittyCAD/modeling-app" rust-version = "1.83" From fba62dab985fc55072b5a9d5c5b4494ea6cdb162 Mon Sep 17 00:00:00 2001 From: Jonathan Tran Date: Tue, 1 Jul 2025 19:33:36 -0400 Subject: [PATCH 18/19] Add parsing arrays and objects as binary operands (#7661) * Add parsing arrays and objects as binary operands * Add sim test showing the error message --- rust/kcl-lib/src/execution/exec_ast.rs | 3 + rust/kcl-lib/src/lsp/kcl/hover.rs | 3 + rust/kcl-lib/src/parsing/ast/digest.rs | 3 + rust/kcl-lib/src/parsing/ast/mod.rs | 3 + rust/kcl-lib/src/parsing/ast/types/mod.rs | 21 ++++ rust/kcl-lib/src/parsing/parser.rs | 29 ++++- rust/kcl-lib/src/simulation_tests.rs | 21 ++++ rust/kcl-lib/src/unparser.rs | 6 + rust/kcl-lib/src/walk/ast_node.rs | 3 + .../tests/add_arrays/artifact_commands.snap | 18 +++ .../add_arrays/artifact_graph_flowchart.snap | 6 + .../artifact_graph_flowchart.snap.md | 3 + rust/kcl-lib/tests/add_arrays/ast.snap | 106 ++++++++++++++++++ .../tests/add_arrays/execution_error.snap | 12 ++ rust/kcl-lib/tests/add_arrays/input.kcl | 1 + rust/kcl-lib/tests/add_arrays/ops.snap | 96 ++++++++++++++++ rust/kcl-lib/tests/add_arrays/unparsed.snap | 5 + 17 files changed, 336 insertions(+), 3 deletions(-) create mode 100644 rust/kcl-lib/tests/add_arrays/artifact_commands.snap create mode 100644 rust/kcl-lib/tests/add_arrays/artifact_graph_flowchart.snap create mode 100644 rust/kcl-lib/tests/add_arrays/artifact_graph_flowchart.snap.md create mode 100644 rust/kcl-lib/tests/add_arrays/ast.snap create mode 100644 rust/kcl-lib/tests/add_arrays/execution_error.snap create mode 100644 rust/kcl-lib/tests/add_arrays/input.kcl create mode 100644 rust/kcl-lib/tests/add_arrays/ops.snap create mode 100644 rust/kcl-lib/tests/add_arrays/unparsed.snap diff --git a/rust/kcl-lib/src/execution/exec_ast.rs b/rust/kcl-lib/src/execution/exec_ast.rs index d8752495e..f1ee7cc47 100644 --- a/rust/kcl-lib/src/execution/exec_ast.rs +++ b/rust/kcl-lib/src/execution/exec_ast.rs @@ -864,6 +864,9 @@ impl BinaryPart { BinaryPart::CallExpressionKw(call_expression) => call_expression.execute(exec_state, ctx).await, BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_result(exec_state, ctx).await, BinaryPart::MemberExpression(member_expression) => member_expression.get_result(exec_state, ctx).await, + BinaryPart::ArrayExpression(e) => e.execute(exec_state, ctx).await, + BinaryPart::ArrayRangeExpression(e) => e.execute(exec_state, ctx).await, + BinaryPart::ObjectExpression(e) => e.execute(exec_state, ctx).await, BinaryPart::IfExpression(e) => e.get_result(exec_state, ctx).await, BinaryPart::AscribedExpression(e) => e.get_result(exec_state, ctx).await, } diff --git a/rust/kcl-lib/src/lsp/kcl/hover.rs b/rust/kcl-lib/src/lsp/kcl/hover.rs index 0db697c83..1b3e1b2c8 100644 --- a/rust/kcl-lib/src/lsp/kcl/hover.rs +++ b/rust/kcl-lib/src/lsp/kcl/hover.rs @@ -149,6 +149,9 @@ impl BinaryPart { BinaryPart::UnaryExpression(unary_expression) => { unary_expression.get_hover_value_for_position(pos, code, opts) } + BinaryPart::ArrayExpression(e) => e.get_hover_value_for_position(pos, code, opts), + BinaryPart::ArrayRangeExpression(e) => e.get_hover_value_for_position(pos, code, opts), + BinaryPart::ObjectExpression(e) => e.get_hover_value_for_position(pos, code, opts), BinaryPart::IfExpression(e) => e.get_hover_value_for_position(pos, code, opts), BinaryPart::AscribedExpression(e) => e.expr.get_hover_value_for_position(pos, code, opts), BinaryPart::MemberExpression(member_expression) => { diff --git a/rust/kcl-lib/src/parsing/ast/digest.rs b/rust/kcl-lib/src/parsing/ast/digest.rs index 1526a13f8..76850717d 100644 --- a/rust/kcl-lib/src/parsing/ast/digest.rs +++ b/rust/kcl-lib/src/parsing/ast/digest.rs @@ -161,6 +161,9 @@ impl BinaryPart { BinaryPart::CallExpressionKw(ce) => ce.compute_digest(), BinaryPart::UnaryExpression(ue) => ue.compute_digest(), BinaryPart::MemberExpression(me) => me.compute_digest(), + BinaryPart::ArrayExpression(e) => e.compute_digest(), + BinaryPart::ArrayRangeExpression(e) => e.compute_digest(), + BinaryPart::ObjectExpression(e) => e.compute_digest(), BinaryPart::IfExpression(e) => e.compute_digest(), BinaryPart::AscribedExpression(e) => e.compute_digest(), } diff --git a/rust/kcl-lib/src/parsing/ast/mod.rs b/rust/kcl-lib/src/parsing/ast/mod.rs index 147004e81..697b9b39a 100644 --- a/rust/kcl-lib/src/parsing/ast/mod.rs +++ b/rust/kcl-lib/src/parsing/ast/mod.rs @@ -51,6 +51,9 @@ impl BinaryPart { BinaryPart::CallExpressionKw(call_expression) => call_expression.module_id, BinaryPart::UnaryExpression(unary_expression) => unary_expression.module_id, BinaryPart::MemberExpression(member_expression) => member_expression.module_id, + BinaryPart::ArrayExpression(e) => e.module_id, + BinaryPart::ArrayRangeExpression(e) => e.module_id, + BinaryPart::ObjectExpression(e) => e.module_id, BinaryPart::IfExpression(e) => e.module_id, BinaryPart::AscribedExpression(e) => e.module_id, } diff --git a/rust/kcl-lib/src/parsing/ast/types/mod.rs b/rust/kcl-lib/src/parsing/ast/types/mod.rs index bd44f7181..ee2849d96 100644 --- a/rust/kcl-lib/src/parsing/ast/types/mod.rs +++ b/rust/kcl-lib/src/parsing/ast/types/mod.rs @@ -1214,6 +1214,9 @@ impl From<&BinaryPart> for Expr { BinaryPart::CallExpressionKw(call_expression) => Expr::CallExpressionKw(call_expression.clone()), BinaryPart::UnaryExpression(unary_expression) => Expr::UnaryExpression(unary_expression.clone()), BinaryPart::MemberExpression(member_expression) => Expr::MemberExpression(member_expression.clone()), + BinaryPart::ArrayExpression(e) => Expr::ArrayExpression(e.clone()), + BinaryPart::ArrayRangeExpression(e) => Expr::ArrayRangeExpression(e.clone()), + BinaryPart::ObjectExpression(e) => Expr::ObjectExpression(e.clone()), BinaryPart::IfExpression(e) => Expr::IfExpression(e.clone()), BinaryPart::AscribedExpression(e) => Expr::AscribedExpression(e.clone()), } @@ -1281,6 +1284,9 @@ pub enum BinaryPart { CallExpressionKw(BoxNode), UnaryExpression(BoxNode), MemberExpression(BoxNode), + ArrayExpression(BoxNode), + ArrayRangeExpression(BoxNode), + ObjectExpression(BoxNode), IfExpression(BoxNode), AscribedExpression(BoxNode), } @@ -1307,6 +1313,9 @@ impl BinaryPart { BinaryPart::CallExpressionKw(call_expression) => call_expression.get_constraint_level(), BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_constraint_level(), BinaryPart::MemberExpression(member_expression) => member_expression.get_constraint_level(), + BinaryPart::ArrayExpression(e) => e.get_constraint_level(), + BinaryPart::ArrayRangeExpression(e) => e.get_constraint_level(), + BinaryPart::ObjectExpression(e) => e.get_constraint_level(), BinaryPart::IfExpression(e) => e.get_constraint_level(), BinaryPart::AscribedExpression(e) => e.expr.get_constraint_level(), } @@ -1320,6 +1329,9 @@ impl BinaryPart { BinaryPart::CallExpressionKw(call_expression) => call_expression.replace_value(source_range, new_value), BinaryPart::UnaryExpression(unary_expression) => unary_expression.replace_value(source_range, new_value), BinaryPart::MemberExpression(_) => {} + BinaryPart::ArrayExpression(e) => e.replace_value(source_range, new_value), + BinaryPart::ArrayRangeExpression(e) => e.replace_value(source_range, new_value), + BinaryPart::ObjectExpression(e) => e.replace_value(source_range, new_value), BinaryPart::IfExpression(e) => e.replace_value(source_range, new_value), BinaryPart::AscribedExpression(e) => e.expr.replace_value(source_range, new_value), } @@ -1333,6 +1345,9 @@ impl BinaryPart { BinaryPart::CallExpressionKw(call_expression) => call_expression.start, BinaryPart::UnaryExpression(unary_expression) => unary_expression.start, BinaryPart::MemberExpression(member_expression) => member_expression.start, + BinaryPart::ArrayExpression(e) => e.start, + BinaryPart::ArrayRangeExpression(e) => e.start, + BinaryPart::ObjectExpression(e) => e.start, BinaryPart::IfExpression(e) => e.start, BinaryPart::AscribedExpression(e) => e.start, } @@ -1346,6 +1361,9 @@ impl BinaryPart { BinaryPart::CallExpressionKw(call_expression) => call_expression.end, BinaryPart::UnaryExpression(unary_expression) => unary_expression.end, BinaryPart::MemberExpression(member_expression) => member_expression.end, + BinaryPart::ArrayExpression(e) => e.end, + BinaryPart::ArrayRangeExpression(e) => e.end, + BinaryPart::ObjectExpression(e) => e.end, BinaryPart::IfExpression(e) => e.end, BinaryPart::AscribedExpression(e) => e.end, } @@ -1360,6 +1378,9 @@ impl BinaryPart { BinaryPart::CallExpressionKw(call_expression) => call_expression.rename_identifiers(old_name, new_name), BinaryPart::UnaryExpression(unary_expression) => unary_expression.rename_identifiers(old_name, new_name), BinaryPart::MemberExpression(member_expression) => member_expression.rename_identifiers(old_name, new_name), + BinaryPart::ArrayExpression(e) => e.rename_identifiers(old_name, new_name), + BinaryPart::ArrayRangeExpression(e) => e.rename_identifiers(old_name, new_name), + BinaryPart::ObjectExpression(e) => e.rename_identifiers(old_name, new_name), BinaryPart::IfExpression(if_expression) => if_expression.rename_identifiers(old_name, new_name), BinaryPart::AscribedExpression(e) => e.expr.rename_identifiers(old_name, new_name), } diff --git a/rust/kcl-lib/src/parsing/parser.rs b/rust/kcl-lib/src/parsing/parser.rs index c8b277a6b..6e3ec4c96 100644 --- a/rust/kcl-lib/src/parsing/parser.rs +++ b/rust/kcl-lib/src/parsing/parser.rs @@ -624,9 +624,6 @@ fn operand(i: &mut TokenSlice) -> ModalResult { Expr::FunctionExpression(_) | Expr::PipeExpression(_) | Expr::PipeSubstitution(_) - | Expr::ArrayExpression(_) - | Expr::ArrayRangeExpression(_) - | Expr::ObjectExpression(_) | Expr::LabelledExpression(..) => return Err(CompilationError::fatal(source_range, TODO_783)), Expr::None(_) => { return Err(CompilationError::fatal( @@ -652,6 +649,9 @@ fn operand(i: &mut TokenSlice) -> ModalResult { Expr::BinaryExpression(x) => BinaryPart::BinaryExpression(x), Expr::CallExpressionKw(x) => BinaryPart::CallExpressionKw(x), Expr::MemberExpression(x) => BinaryPart::MemberExpression(x), + Expr::ArrayExpression(x) => BinaryPart::ArrayExpression(x), + Expr::ArrayRangeExpression(x) => BinaryPart::ArrayRangeExpression(x), + Expr::ObjectExpression(x) => BinaryPart::ObjectExpression(x), Expr::IfExpression(x) => BinaryPart::IfExpression(x), Expr::AscribedExpression(x) => BinaryPart::AscribedExpression(x), }; @@ -2115,6 +2115,8 @@ fn possible_operands(i: &mut TokenSlice) -> ModalResult { literal.map(Expr::Literal), fn_call_kw.map(Box::new).map(Expr::CallExpressionKw), name.map(Box::new).map(Expr::Name), + array, + object.map(Box::new).map(Expr::ObjectExpression), binary_expr_in_parens.map(Box::new).map(Expr::BinaryExpression), unnecessarily_bracketed, )) @@ -3398,6 +3400,27 @@ mod tests { operand.parse(tokens).unwrap(); } + #[test] + fn parse_binary_operator_on_array() { + let tokens = crate::parsing::token::lex("[0] + 1", ModuleId::default()).unwrap(); + let tokens = tokens.as_slice(); + binary_expression.parse(tokens).unwrap(); + } + + #[test] + fn parse_binary_operator_on_object() { + let tokens = crate::parsing::token::lex("{ a = 1 } + 2", ModuleId::default()).unwrap(); + let tokens = tokens.as_slice(); + binary_expression.parse(tokens).unwrap(); + } + + #[test] + fn parse_call_array_operator() { + let tokens = crate::parsing::token::lex("f([0] + 1)", ModuleId::default()).unwrap(); + let tokens = tokens.as_slice(); + fn_call_kw.parse(tokens).unwrap(); + } + #[test] fn weird_program_just_a_pipe() { let tokens = crate::parsing::token::lex("|", ModuleId::default()).unwrap(); diff --git a/rust/kcl-lib/src/simulation_tests.rs b/rust/kcl-lib/src/simulation_tests.rs index 86440c84f..fb223f65c 100644 --- a/rust/kcl-lib/src/simulation_tests.rs +++ b/rust/kcl-lib/src/simulation_tests.rs @@ -779,6 +779,27 @@ mod add_lots { super::execute(TEST_NAME, false).await } } +mod add_arrays { + const TEST_NAME: &str = "add_arrays"; + + /// Test parsing KCL. + #[test] + fn parse() { + super::parse(TEST_NAME) + } + + /// Test that parsing and unparsing KCL produces the original KCL input. + #[tokio::test(flavor = "multi_thread")] + async fn unparse() { + super::unparse(TEST_NAME).await + } + + /// Test that KCL is executed correctly. + #[tokio::test(flavor = "multi_thread")] + async fn kcl_test_execute() { + super::execute(TEST_NAME, false).await + } +} mod argument_error { //! The argument error points to the problematic argument in the call site, //! not the function definition that the variable points to. diff --git a/rust/kcl-lib/src/unparser.rs b/rust/kcl-lib/src/unparser.rs index 352a9ec1f..42c4b9a24 100644 --- a/rust/kcl-lib/src/unparser.rs +++ b/rust/kcl-lib/src/unparser.rs @@ -363,6 +363,9 @@ impl BinaryPart { BinaryPart::MemberExpression(member_expression) => { member_expression.recast(options, indentation_level, ctxt) } + BinaryPart::ArrayExpression(e) => e.recast(options, indentation_level, ctxt), + BinaryPart::ArrayRangeExpression(e) => e.recast(options, indentation_level, ctxt), + BinaryPart::ObjectExpression(e) => e.recast(options, indentation_level, ctxt), BinaryPart::IfExpression(e) => e.recast(options, indentation_level, ExprContext::Other), BinaryPart::AscribedExpression(e) => e.recast(options, indentation_level, ExprContext::Other), } @@ -745,6 +748,9 @@ impl UnaryExpression { BinaryPart::Literal(_) | BinaryPart::Name(_) | BinaryPart::MemberExpression(_) + | BinaryPart::ArrayExpression(_) + | BinaryPart::ArrayRangeExpression(_) + | BinaryPart::ObjectExpression(_) | BinaryPart::IfExpression(_) | BinaryPart::AscribedExpression(_) | BinaryPart::CallExpressionKw(_) => { diff --git a/rust/kcl-lib/src/walk/ast_node.rs b/rust/kcl-lib/src/walk/ast_node.rs index 01d8950ce..c62bc0fc3 100644 --- a/rust/kcl-lib/src/walk/ast_node.rs +++ b/rust/kcl-lib/src/walk/ast_node.rs @@ -220,6 +220,9 @@ impl<'tree> From<&'tree types::BinaryPart> for Node<'tree> { types::BinaryPart::CallExpressionKw(ce) => ce.as_ref().into(), types::BinaryPart::UnaryExpression(ue) => ue.as_ref().into(), types::BinaryPart::MemberExpression(me) => me.as_ref().into(), + types::BinaryPart::ArrayExpression(e) => e.as_ref().into(), + types::BinaryPart::ArrayRangeExpression(e) => e.as_ref().into(), + types::BinaryPart::ObjectExpression(e) => e.as_ref().into(), types::BinaryPart::IfExpression(e) => e.as_ref().into(), types::BinaryPart::AscribedExpression(e) => e.as_ref().into(), } diff --git a/rust/kcl-lib/tests/add_arrays/artifact_commands.snap b/rust/kcl-lib/tests/add_arrays/artifact_commands.snap new file mode 100644 index 000000000..a0448a9cd --- /dev/null +++ b/rust/kcl-lib/tests/add_arrays/artifact_commands.snap @@ -0,0 +1,18 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact commands add_arrays.kcl +--- +{ + "rust/kcl-lib/tests/add_arrays/input.kcl": [], + "std::appearance": [], + "std::array": [], + "std::math": [], + "std::prelude": [], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/add_arrays/artifact_graph_flowchart.snap b/rust/kcl-lib/tests/add_arrays/artifact_graph_flowchart.snap new file mode 100644 index 000000000..c9f05dab0 --- /dev/null +++ b/rust/kcl-lib/tests/add_arrays/artifact_graph_flowchart.snap @@ -0,0 +1,6 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact graph flowchart add_arrays.kcl +extension: md +snapshot_kind: binary +--- diff --git a/rust/kcl-lib/tests/add_arrays/artifact_graph_flowchart.snap.md b/rust/kcl-lib/tests/add_arrays/artifact_graph_flowchart.snap.md new file mode 100644 index 000000000..13e533509 --- /dev/null +++ b/rust/kcl-lib/tests/add_arrays/artifact_graph_flowchart.snap.md @@ -0,0 +1,3 @@ +```mermaid +flowchart LR +``` diff --git a/rust/kcl-lib/tests/add_arrays/ast.snap b/rust/kcl-lib/tests/add_arrays/ast.snap new file mode 100644 index 000000000..87d65a56e --- /dev/null +++ b/rust/kcl-lib/tests/add_arrays/ast.snap @@ -0,0 +1,106 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of parsing add_arrays.kcl +--- +{ + "Ok": { + "body": [ + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "answer", + "start": 0, + "type": "Identifier" + }, + "init": { + "commentStart": 0, + "end": 0, + "left": { + "commentStart": 0, + "elements": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + }, + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "1", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 1.0, + "suffix": "None" + } + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + }, + "moduleId": 0, + "operator": "+", + "right": { + "commentStart": 0, + "elements": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + }, + "start": 0, + "type": "BinaryExpression", + "type": "BinaryExpression" + }, + "moduleId": 0, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "const", + "moduleId": 0, + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0 + } +} diff --git a/rust/kcl-lib/tests/add_arrays/execution_error.snap b/rust/kcl-lib/tests/add_arrays/execution_error.snap new file mode 100644 index 000000000..0724d8eef --- /dev/null +++ b/rust/kcl-lib/tests/add_arrays/execution_error.snap @@ -0,0 +1,12 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Error from executing add_arrays.kcl +--- +KCL Semantic error + + × semantic: Expected a number, but found an array of `number`, `number` + ╭──── + 1 │ answer = [0, 1] + [2] + · ───┬── + · ╰── tests/add_arrays/input.kcl + ╰──── diff --git a/rust/kcl-lib/tests/add_arrays/input.kcl b/rust/kcl-lib/tests/add_arrays/input.kcl new file mode 100644 index 000000000..6699ec5f9 --- /dev/null +++ b/rust/kcl-lib/tests/add_arrays/input.kcl @@ -0,0 +1 @@ +answer = [0, 1] + [2] diff --git a/rust/kcl-lib/tests/add_arrays/ops.snap b/rust/kcl-lib/tests/add_arrays/ops.snap new file mode 100644 index 000000000..32038be77 --- /dev/null +++ b/rust/kcl-lib/tests/add_arrays/ops.snap @@ -0,0 +1,96 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Operations executed add_arrays.kcl +--- +{ + "rust/kcl-lib/tests/add_arrays/input.kcl": [], + "std::appearance": [], + "std::array": [], + "std::math": [ + { + "type": "VariableDeclaration", + "name": "PI", + "value": { + "type": "Number", + "value": 3.141592653589793, + "ty": { + "type": "Unknown" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "E", + "value": { + "type": "Number", + "value": 2.718281828459045, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "TAU", + "value": { + "type": "Number", + "value": 6.283185307179586, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::prelude": [ + { + "type": "VariableDeclaration", + "name": "START", + "value": { + "type": "String", + "value": "start" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "END", + "value": { + "type": "String", + "value": "end" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/add_arrays/unparsed.snap b/rust/kcl-lib/tests/add_arrays/unparsed.snap new file mode 100644 index 000000000..18ba47ca7 --- /dev/null +++ b/rust/kcl-lib/tests/add_arrays/unparsed.snap @@ -0,0 +1,5 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of unparsing add_arrays.kcl +--- +answer = [0, 1] + [2] From 1b7502068672f5e11d0e16bd5ca578c57a7c9b36 Mon Sep 17 00:00:00 2001 From: Jace Browning Date: Wed, 2 Jul 2025 10:49:34 -0400 Subject: [PATCH 19/19] Remove unused code to skip auth (#7280) --- .env.development | 1 - .env.production | 1 - interface.d.ts | 1 - src/env.ts | 1 - src/machines/authMachine.ts | 40 +------------------------------------ src/main.ts | 1 - src/preload.ts | 1 - 7 files changed, 1 insertion(+), 45 deletions(-) diff --git a/.env.development b/.env.development index 47ce20bfc..7b474799a 100644 --- a/.env.development +++ b/.env.development @@ -7,7 +7,6 @@ VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands VITE_KC_API_BASE_URL=https://api.dev.zoo.dev VITE_KC_SITE_BASE_URL=https://dev.zoo.dev VITE_KC_SITE_APP_URL=https://app.dev.zoo.dev -VITE_KC_SKIP_AUTH=false VITE_KC_CONNECTION_TIMEOUT_MS=5000 #VITE_WASM_URL="optional way of overriding the wasm url, particular for unit tests which need this if you running not on the default 3000 port" #VITE_KC_DEV_TOKEN="optional token to skip auth in the app" diff --git a/.env.production b/.env.production index 6adcecc5d..49aee03e9 100644 --- a/.env.production +++ b/.env.production @@ -3,5 +3,4 @@ VITE_KC_API_WS_MODELING_URL=wss://api.zoo.dev/ws/modeling/commands VITE_KC_API_BASE_URL=https://api.zoo.dev VITE_KC_SITE_BASE_URL=https://zoo.dev VITE_KC_SITE_APP_URL=https://app.zoo.dev -VITE_KC_SKIP_AUTH=false VITE_KC_CONNECTION_TIMEOUT_MS=15000 diff --git a/interface.d.ts b/interface.d.ts index 8b6af29bd..1a2904e2b 100644 --- a/interface.d.ts +++ b/interface.d.ts @@ -79,7 +79,6 @@ export interface IElectronAPI { VITE_KC_API_BASE_URL: string VITE_KC_SITE_BASE_URL: string VITE_KC_SITE_APP_URL: string - VITE_KC_SKIP_AUTH: string VITE_KC_CONNECTION_TIMEOUT_MS: string VITE_KC_DEV_TOKEN: string NODE_ENV: string diff --git a/src/env.ts b/src/env.ts index bde829f58..f3f0af864 100644 --- a/src/env.ts +++ b/src/env.ts @@ -11,7 +11,6 @@ export const VITE_KC_API_WS_MODELING_URL = env.VITE_KC_API_WS_MODELING_URL as export const VITE_KC_API_BASE_URL = env.VITE_KC_API_BASE_URL export const VITE_KC_SITE_BASE_URL = env.VITE_KC_SITE_BASE_URL export const VITE_KC_SITE_APP_URL = env.VITE_KC_SITE_APP_URL -export const VITE_KC_SKIP_AUTH = env.VITE_KC_SKIP_AUTH as string | undefined export const VITE_KC_CONNECTION_TIMEOUT_MS = env.VITE_KC_CONNECTION_TIMEOUT_MS as string | undefined export const VITE_KC_DEV_TOKEN = env.VITE_KC_DEV_TOKEN as string | undefined diff --git a/src/machines/authMachine.ts b/src/machines/authMachine.ts index 45b2d328b..97acd35a4 100644 --- a/src/machines/authMachine.ts +++ b/src/machines/authMachine.ts @@ -1,10 +1,5 @@ import type { Models } from '@kittycad/lib' -import { - DEV, - VITE_KC_API_BASE_URL, - VITE_KC_DEV_TOKEN, - VITE_KC_SKIP_AUTH, -} from '@src/env' +import { VITE_KC_API_BASE_URL, VITE_KC_DEV_TOKEN } from '@src/env' import { assign, fromPromise, setup } from 'xstate' import { COOKIE_NAME, OAUTH2_DEVICE_CLIENT_ID } from '@src/lib/constants' @@ -21,26 +16,6 @@ import { } from '@src/lib/withBaseURL' import { ACTOR_IDS } from '@src/machines/machineConstants' -const SKIP_AUTH = VITE_KC_SKIP_AUTH === 'true' && DEV - -const LOCAL_USER: Models['User_type'] = { - id: '8675309', - name: 'Test User', - email: 'kittycad.sidebar.test@example.com', - image: 'https://placekitten.com/200/200', - created_at: 'yesteryear', - updated_at: 'today', - company: 'Test Company', - discord: 'Test User#1234', - github: 'testuser', - phone: '555-555-5555', - first_name: 'Test', - last_name: 'User', - can_train_on_data: false, - is_service_account: false, - deletion_scheduled: false, -} - export interface UserContext { user?: Models['User_type'] token: string @@ -165,19 +140,6 @@ async function getUser(input: { token?: string }) { if (!token && isDesktop()) return Promise.reject(new Error('No token found')) if (token) headers['Authorization'] = `Bearer ${token}` - if (SKIP_AUTH) { - // For local tests - if (localStorage.getItem('FORCE_NO_IMAGE')) { - LOCAL_USER.image = '' - } - - markOnce('code/didAuth') - return { - user: LOCAL_USER, - token, - } - } - const userPromise = isDesktop() ? getUserDesktop(token, VITE_KC_API_BASE_URL) : fetch(url, { diff --git a/src/main.ts b/src/main.ts index 27bf5b8f9..c130963b9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -75,7 +75,6 @@ process.env.VITE_KC_API_WS_MODELING_URL ??= viteEnv.VITE_KC_API_WS_MODELING_URL process.env.VITE_KC_API_BASE_URL ??= viteEnv.VITE_KC_API_BASE_URL process.env.VITE_KC_SITE_BASE_URL ??= viteEnv.VITE_KC_SITE_BASE_URL process.env.VITE_KC_SITE_APP_URL ??= viteEnv.VITE_KC_SITE_APP_URL -process.env.VITE_KC_SKIP_AUTH ??= viteEnv.VITE_KC_SKIP_AUTH process.env.VITE_KC_CONNECTION_TIMEOUT_MS ??= viteEnv.VITE_KC_CONNECTION_TIMEOUT_MS diff --git a/src/preload.ts b/src/preload.ts index 5e7ebe4c5..4eb8036f7 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -292,7 +292,6 @@ contextBridge.exposeInMainWorld('electron', { 'VITE_KC_API_BASE_URL', 'VITE_KC_SITE_BASE_URL', 'VITE_KC_SITE_APP_URL', - 'VITE_KC_SKIP_AUTH', 'VITE_KC_CONNECTION_TIMEOUT_MS', 'VITE_KC_DEV_TOKEN',